歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> OpenCV 輪廓檢測心得筆記

OpenCV 輪廓檢測心得筆記

日期:2017/3/1 9:36:26   编辑:Linux編程

程序采用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;
}

給出我自己搜索的一些函數介紹

CvSeq

可動態增長元素序列(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)

CvMemStorage

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 重置。

CreateMemStorage

創建內存塊

CvMemStorage* cvCreateMemStorage( int block_size=0 );
block_size
存儲塊的大小以字節表示。如果大小是 0 byte, 則將該塊設置成默認值 -- 當前默認大小為64k.

函數 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 查找所有邊緣(包含內部空洞),按照如下方式組織

DrawContours

在圖像中繪制外部和內部的輪廓。

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) );
img
用以繪制輪廓的圖像。和其他繪圖函數一樣,邊界圖像被感興趣區域(ROI)所剪切。
contour
指針指向第一個輪廓。
external_color
外層輪廓的顏色。
hole_color
內層輪廓的顏色。
max_level

繪制輪廓的最大等級。如果等級為0,繪制單獨的輪廓。如果為1,繪制輪廓及在其後的相同的級別下輪廓。如果值為2,所有的輪廓。

如果等級為2,繪制所有同級輪廓及所有低一級輪廓,諸此種種。如果值為負數,函數不繪制同級輪廓,但會升序繪制直到級別為

abs(max_level)-1的子輪廓。

thickness
繪制輪廓時所使用的線條的粗細度。如果值為負(e.g. =CV_FILLED),繪制內層輪廓。
line_type
線條的類型。參考cvLine.
offset
按照給出的偏移量移動每一個輪廓點坐標.當輪廓是從某些感興趣區域(ROI)中提取的然後需要在運算中考慮ROI偏移量時,
將會用到這個參數。

當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的下載地址:請點這裡

Copyright © Linux教程網 All Rights Reserved