程序采用OpenCV中國的例程,下面列舉了各個詳細函數的功能及簡單說明。
/**************************************************
* 輪廓檢測
* 主要函數:
* cvFindContours
* cvDrawContours
**************************************************/
/***********************************************************************
* OpenCV example
* By Shiqi Yu 2006
***********************************************************************/
#include "cv.h"
#include "cxcore.h"
#include "highgui.h"
int main( int argc, char** argv )
{
//聲明IplImage指針
IplImage* pImg = NULL;
IplImage* pContourImg = NULL;
CvMemStorage * storage = cvCreateMemStorage(0); //創建一個堆棧,存儲輪廓用
CvSeq * contour = 0; //設置存取提取的指針
int mode = CV_RETR_EXTERNAL; //提取物體最外層輪廓
if( argc == 3)
if(strcmp(argv[2], "all") == 0)
mode = CV_RETR_CCOMP; //內外輪廓都檢測
//創建窗口
cvNamedWindow("src", 1);
cvNamedWindow("contour",1);
//載入圖像,強制轉化為Gray
if( argc >= 2 &&
(pImg = cvLoadImage( argv[1], 0)) != 0 )
{
cvShowImage( "src", pImg );
//為輪廓顯示圖像申請空間
//3通道圖像,以便用彩色顯示
pContourImg = cvCreateImage(cvGetSize(pImg),
IPL_DEPTH_8U,
3);
//copy source image and convert it to BGR image
cvCvtColor(pImg, pContourImg, CV_GRAY2BGR);
//查找contour
cvFindContours( pImg, storage, &contour, sizeof(CvContour),
mode, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0));
}
else
{
//銷毀窗口
cvDestroyWindow( "src" );
cvDestroyWindow( "contour" );
cvReleaseMemStorage(&storage);
return -1;
}
//將輪廓畫出
cvDrawContours(pContourImg, contour,
CV_RGB(0,0,255), CV_RGB(255, 0, 0),
2, 2, 8, cvPoint(0,0));
//顯示圖像
cvShowImage( "contour", pContourImg );
cvWaitKey(0);
//銷毀窗口
cvDestroyWindow( "src" );
cvDestroyWindow( "contour" );
//釋放圖像
cvReleaseImage( &pImg );
cvReleaseImage( &pContourImg );
cvReleaseMemStorage(&storage);
return 0;
}
給出我自己搜索的一些函數介紹
可動態增長元素序列(OpenCV_1.0已發生改變,詳見cxtypes.h) Growable sequence of elements
#define CV_SEQUENCE_FIELDS() / int flags; /* micsellaneous flags */ / int header_size; /* size of sequence header */ / struct CvSeq* h_prev; /* previous sequence */ / struct CvSeq* h_next; /* next sequence */ / struct CvSeq* v_prev; /* 2nd previous sequence */ / struct CvSeq* v_next; /* 2nd next sequence */ / int total; /* total number of elements */ / int elem_size;/* size of sequence element in bytes */ / char* block_max;/* maximal bound of the last block */ / char* ptr; /* current write pointer */ / int delta_elems; /* how many elements allocated when the sequence grows (sequence granularity) */ / CvMemStorage* storage; /* where the seq is stored */ / CvSeqBlock* free_blocks; /* free blocks list */ / CvSeqBlock* first; /* pointer to the first sequence block */ typedef struct CvSeq { CV_SEQUENCE_FIELDS() } CvSeq;
結構CvSeq是所有OpenCV動態數據結構的基礎。在1.0版本中,將前六個成員剝離出來定義成一個宏. 通過不同尋常的宏定義簡化了帶有附加
參數的結構 CvSeq 的擴展。為了擴展 CvSeq, 用戶可以定義一新的數據結構或在通過宏CV_SEQUENCE_FIELDS()所包括的 CvSeq 的域後在放入用戶自定義的域。
有兩種類型的序列 -- 稠密序列和稀疏序列。稠密序列都派生自 CvSeq, 它們用來代表可擴展的一維數組 -- 向量,棧,隊列,雙端隊列。數據間不存在空隙(即:連續存放)-- 如果元素從序列中間被刪除或插入新的元素到序列中(不是兩端),那麼此元素後邊的相關元素會被移動。稀疏序列都派生自 CvSet,後面會有詳細的討論。它們都是由節點所組成的序列,每一個節點要麼被占用空間要麼是空,由 flag 標志指定。這些序列作為無序的數據結構而被使用,如點集,圖,哈希表等。
域 header_size(結構的大小) 含有序列頭部節點的實際大小,此大小大於或等於 sizeof(CvSeq).當這個宏用在序列中時,應該等於 sizeof(CvSeq),若這個宏用在其他結構中,如CvContour,結構的大小應該大於sizeof(CvSeq); 域 h_prev, h_next, v_prev, v_next 可用來創建不同序列的層次結構。域 h_prev, h_next 指向同一層次結構前一個和後一個序列,而域 v_prev, v_next指向在垂直方向上的前一個和後一個序列,即:父親和子孫。
域 first 指向第一個序列快,塊結構在後面描述。
域 total 包含稠密序列的總元素數和稀疏序列被分配的節點數。
域 flags 的高16位描述(包含)特定的動態結構類型(CV_SEQ_MAGIC_VAL 表示稠密序列,CV_SET_MAGIC_VAL 表示稀疏序列),同時包含形形色色的信息。
低 CV_SEQ_ELTYPE_BITS 位包含元素類型的 ID(標示符)。大多數處理函數並不會用到元素類型,而會用到存放在 elem_size 中的元素大小 。如果序列中包含 CvMat 中的數據,那麼元素的類型就與 CvMat 中的類型相匹配, 如:CV_32SC2 可以被使用為由二維空間中的點序列, CV_32FC1用為由浮點數組成的序列等。通過宏 CV_SEQ_ELTYPE(seq_header_ptr) 來獲取序列中元素的類型。處理數字序列的函數判斷: elem.size 等同於序列元素的大小。除了與 CvMat 相兼容的類型外,還有幾個在頭 cvtypes.h 中定義的額外的類型。
Standard Types of Sequence Elements #define CV_SEQ_ELTYPE_POINT CV_32SC2 /* (x,y) */ #define CV_SEQ_ELTYPE_CODE CV_8UC1 /* freeman code: 0..7 */ #define CV_SEQ_ELTYPE_GENERIC 0 /* unspecified type of sequence elements */ #define CV_SEQ_ELTYPE_PTR CV_USRTYPE1 /* =6 */ #define CV_SEQ_ELTYPE_PPOINT CV_SEQ_ELTYPE_PTR /* &elem: pointer to element of other sequence */ #define CV_SEQ_ELTYPE_INDEX CV_32SC1 /* #elem: index of element of some other sequence */ #define CV_SEQ_ELTYPE_GRAPH_EDGE CV_SEQ_ELTYPE_GENERIC /* &next_o, &next_d, &vtx_o, &vtx_d */ #define CV_SEQ_ELTYPE_GRAPH_VERTEX CV_SEQ_ELTYPE_GENERIC /* first_edge, &(x,y) */ #define CV_SEQ_ELTYPE_TRIAN_ATR CV_SEQ_ELTYPE_GENERIC /* vertex of the binary tree */ #define CV_SEQ_ELTYPE_CONNECTED_COMP CV_SEQ_ELTYPE_GENERIC /* connected component */ #define CV_SEQ_ELTYPE_POINT3D CV_32FC3 /* (x,y,z) */
後面的 CV_SEQ_KIND_BITS 字節表示序列的類型:
Standard Kinds of Sequences /* generic (unspecified) kind of sequence */ #define CV_SEQ_KIND_GENERIC (0 << CV_SEQ_ELTYPE_BITS) /* dense sequence suntypes */ #define CV_SEQ_KIND_CURVE (1 << CV_SEQ_ELTYPE_BITS) #define CV_SEQ_KIND_BIN_TREE (2 << CV_SEQ_ELTYPE_BITS) /* sparse sequence (or set) subtypes */ #define CV_SEQ_KIND_GRAPH (3 << CV_SEQ_ELTYPE_BITS) #define CV_SEQ_KIND_SUBDIV2D (4 << CV_SEQ_ELTYPE_BITS)
Growing memory storage
typedef struct CvMemStorage { struct CvMemBlock* bottom;/* first allocated block */ struct CvMemBlock* top; /* the current memory block - top of the stack */ struct CvMemStorage* parent; /* borrows new blocks from */ int block_size; /* block size */ int free_space; /* free space in the top block (in bytes) */ } CvMemStorage;
內存存儲器是一個可用來存儲諸如序列,輪廓,圖形,子劃分等動態增長數據結構的底層結構。它是由一系列以同等大小的內存塊構成,呈列表型
---bottom 域指的是列首,top 域指的是當前指向的塊但未必是列尾.在bottom和top之間所有的塊(包括bottom, 不包括top)被完全占據了
空間;在 top和列尾之間所有的塊(包括塊尾,不包括top)則是空的;而top塊本身則被占據了部分空間 -- free_space 指的是top塊剩馀的
空字節數。
新分配的內存緩沖區(或顯式的通過 cvMemStorageAlloc 函數分配,或隱式的通過 cvSeqPush, cvGraphAddEdge等高級函數分配)
總是起始於當前塊(即top塊)的剩馀那部分,如果剩馀那部分能滿足要求(夠分配的大小)。分配後,free_space 就減少了新分配的那部
分內存大小,外加一些用來保存適當列型的附加大小。當top塊的剩馀空間無法滿足被分配的塊(緩沖區)大小時,top塊的下一個存儲塊被
置為當前塊(新的top塊) -- free_space 被置為先前分配的整個塊的大小。
如果已經不存在空的存儲塊(即:top塊已是列尾),則必須再分配一個新的塊(或從parent那繼承,見 cvCreateChildMemStorage)並
將該塊加到列尾上去。於是,存儲器(memory storage)就如同棧(Stack)那樣, bottom指向棧底,(top, free_space)對指向棧頂。
棧頂可通過 cvSaveMemStoragePos保存,通過 cvRestoreMemStoragePos 恢復指向, 通過 cvClearStorage 重置。
創建內存塊
CvMemStorage* cvCreateMemStorage( int block_size=0 );
函數 cvCreateMemStorage 創建一內存塊並返回指向塊首的指針。起初,存儲塊是空的。頭部(即:header)的所有域值都為 0,除了
block_size 外.
cvFindContours
cvFindContours可以得到一個圖象所有的輪廓,返回的是輪廓的數量.它可以對cvCanny,cvThreshold(),cvAdaptiveThreshold()函數
處理得到的函數進行輪廓的提取.firstContour參數可以不用創建空間,在函數內部從函數cvFindNextContour返回輪廓的指針.最主要的是
method參數,這個參數涉及輪廓的存儲方式,以及什麼輪廓能被發現
cvFindContours的第5個參數
CV_RETR_EXTERNAL 查找外邊緣,各邊緣以指針h_next相連
CV_RETR_LIST 查找所有邊緣(包含內部空洞),各邊緣以指針h_next相連
CV_RETR_CCOMP 查找所有邊緣(包含內部空洞),按照如下方式組織
在圖像中繪制外部和內部的輪廓。
void cvDrawContours( CvArr *img, CvSeq* contour, CvScalar external_color, CvScalar hole_color, int max_level, int thickness=1, int line_type=8, CvPoint offset=cvPoint(0,0) );
繪制輪廓的最大等級。如果等級為0,繪制單獨的輪廓。如果為1,繪制輪廓及在其後的相同的級別下輪廓。如果值為2,所有的輪廓。
如果等級為2,繪制所有同級輪廓及所有低一級輪廓,諸此種種。如果值為負數,函數不繪制同級輪廓,但會升序繪制直到級別為
abs(max_level)-1的子輪廓。
當thickness>=0,函數cvDrawContours在圖像中繪制輪廓,或者當thickness<0時,填充輪廓所限制的區域。
#include "cv.h" #include "highgui.h" int main( int argc, char** argv ) { IplImage* src; // 第一條命令行參數確定了圖像的文件名。 if( argc == 2 && (src=cvLoadImage(argv[1], 0))!= 0) { IplImage* dst = cvCreateImage( cvGetSize(src), 8, 3 ); CvMemStorage* storage = cvCreateMemStorage(0); CvSeq* contour = 0; cvThreshold( src, src, 1, 255, CV_THRESH_BINARY ); cvNamedWindow( "Source", 1 ); cvShowImage( "Source", src ); cvFindContours( src, storage, &contour, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE ); cvZero( dst ); for( ; contour != 0; contour = contour->h_next ) { CvScalar color = CV_RGB( rand()&255, rand()&255, rand()&255 ); /* 用1替代 CV_FILLED 所指示的輪廓外形 */ cvDrawContours( dst, contour, color, color, -1, CV_FILLED, 8 ); } cvNamedWindow( "Components", 1 ); cvShowImage( "Components", dst ); cvWaitKey(0); } }
在樣本中用1替代 CV_FILLED 以指示的得到外形。
(注意:在cvFindContours中參數為CV_CHAIN_CODE時,cvDrawContours用CV_FILLED時不會畫出任何圖形)
其他參數嘗試的結果,下面的使用內外都檢測 CV_RETR_CCOMP
--------------------------------------分割線 --------------------------------------
Ubuntu Linux下安裝OpenCV2.4.1所需包 http://www.linuxidc.com/Linux/2012-08/68184.htm
Ubuntu 12.04 安裝 OpenCV2.4.2 http://www.linuxidc.com/Linux/2012-09/70158.htm
CentOS下OpenCV無法讀取視頻文件 http://www.linuxidc.com/Linux/2011-07/39295.htm
Ubuntu 12.04下安裝OpenCV 2.4.5總結 http://www.linuxidc.com/Linux/2013-06/86704.htm
Ubuntu 10.04中安裝OpenCv2.1九步曲 http://www.linuxidc.com/Linux/2010-09/28678.htm
基於QT和OpenCV的人臉識別系統 http://www.linuxidc.com/Linux/2011-11/47806.htm
[翻譯]Ubuntu 14.04, 13.10 下安裝 OpenCV 2.4.9 http://www.linuxidc.com/Linux/2014-12/110045.htm
--------------------------------------分割線 --------------------------------------
OpenCV的詳細介紹:請點這裡
OpenCV的下載地址:請點這裡