在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

opencv用序列存儲輪廓

C語言專家集中營 ? 來源:工程師曾玲 ? 2019-02-02 17:25 ? 次閱讀

查找輪廓

輪廓到底是什么?一個輪廓一般對應(yīng)一系列的點,也就是圖像中的一條曲線.表示的方法可能根據(jù)不同情況而有所不同.有多重方法可以表示曲線.在openCV中一般用序列來存儲輪廓信息.序列中的每一個元素是曲線中一個點的位置.關(guān)于序列表示的輪廓細(xì)節(jié)將在后面討論,現(xiàn)在只要簡單把輪廓想象為使用CvSeq表示的一系列的點就可以了.

函數(shù)cvFindContours()從二值圖像中尋找輪廓.cvFindContours()處理的圖像可以是從cvCanny()函數(shù)得到的有邊緣像素的圖像,或者是從cvThreshold()及cvAdaptiveThreshold()得到的圖像,這時的邊緣是正和負(fù)區(qū)域之間的邊界.

opencv用序列存儲輪廓

圖8-2描述了cvFindContours的函數(shù)功能,圖像的上半部分是神色背景和白色區(qū)域(被從A到E標(biāo)記)的測試圖像.下半部分是使用cvFindCountours()函數(shù)后會得到的輪廓的說明.這些輪廓被標(biāo)記為cX或hx,"c"表示"輪廓(contour)","h"表示"孔(hole)","X表述數(shù)字".其中一些輪廓用虛劃線表示;表明他們是白色區(qū)域的外部邊界(例如,非0區(qū)域).孔(hole)的外部邊界(例如,非0區(qū)域)即白色區(qū)域的內(nèi)部邊界.在圖中是用電線表示外部邊界的.OpenCV的cvFindContours()函數(shù)可區(qū)分內(nèi)部和外部邊界.

包含的概念在很多應(yīng)用中都非常重要.因此.OpenCV允許得到的輪廓被聚合成一個輪廓樹,從而把包含關(guān)系編碼到樹結(jié)構(gòu)中.這個測試圖的輪廓樹在根節(jié)點的輪廓叫c0,孔h00和h01是它的字子節(jié)點.這些輪廓中直接包含輪廓稱為他們的子節(jié)點,以此類推.

現(xiàn)在來看cvFindContours()函數(shù)

intcvFindContours(CvArr*image,CvMemStorage*storage,CvSeq**first_contour,

intheader_sizeCV_DEFAULT(sizeof(CvContour)),

intmodeCV_DEFAULT(CV_RETR_LIST),

intmethodCV_DEFAULT(CV_CHAIN_APPROX_SIMPLE),

CvPointoffsetCV_DEFAULT(cvPoint(0,0)));

第一個參數(shù) image是輸入圖像,圖像必須是8位單通道圖像,并且應(yīng)該被轉(zhuǎn)化成二值的(例如,所有非0像素的值都是一個定值).cvFindContours()運(yùn)行的時候,這個圖像會被直接涂改,因此如果是將來還有用的圖像,應(yīng)該復(fù)制之后再傳給cvFindContours().

storage 是內(nèi)存存儲器,cvFindContours()找到的輪廓記錄在此內(nèi)存里.正如之前所說,這個存儲器的空間應(yīng)該由cvCreateMemStorage()分配.

first_contour 是指向CvSeq*的一個指針firstContour.無需動手,cvFindContours()會自動分配該指針.實際上,只要在這里傳一個指針就可以了函數(shù)會自動設(shè)置.不需要分配和釋放(new/delete或者malloc/free).就是這個指針(例如,*firstContour)指向輪廓樹的首地址(head).cvFindContours()返回值是,找到的所有輪廓的個數(shù)

cvSeq* firstContout = NULL;

cvFindContours(..., &firstContour, ...);

headerSize告訴cvFindContours()更多有關(guān)對象分配的信息,它可以被設(shè)定為sizeof(CvContour)或者sizeof(CvChain)(當(dāng)近似方法參數(shù)method被設(shè)定為CV_ChAIN_CODE時使用后者).最后是mode和method參數(shù),他們分別指定計算方法和如何計算.

mode變量可以被設(shè)置為以下四個選項之一: CV_RETR_ExTERNAL, CV_RETR_LIST, CV_RETR_CCOMP或CV_RETR_TREE.mode的值向cvFindeContours()說明需要的輪廓類型,和希望的放回值形式.具體說來,mode的值決定把找到的輪廓如何掛到輪廓樹節(jié)點變量(h_prev,h_next,v_prev和v_next)上,圖8-3展示了四種可能的mode值所得到的結(jié)果的拓?fù)浣Y(jié)構(gòu).

opencv用序列存儲輪廓

每中情況下,結(jié)構(gòu)都可以看成是被"橫向"連接(h_next和h_prev)聯(lián)系和被"縱向"連接(v_next和v_prev)不同的"層次".

CV_RETR_EXTERNAL 只檢測出最外的輪廓.圖8-2中,只有一個最外輪廓,因此圖8-3中第一個輪廓指向最外的序列,除此之外沒有別的連接

CV_RETR_LIST 檢測所有的輪廓并將他們保存到表(list)中.圖8-3描繪了從圖8-2樣圖中得到的表.在這個例子中,有8條輪廓被找到,他們相互之間有h_prev和h_next連接(這里并沒有使用v_prev和v_next)

CV_RETR_CCOMP 檢出所有的輪廓并將他們組織成雙層結(jié)構(gòu)(two-level hierarchy),頂層邊界是所有成份的外界邊界,第二層邊界是空的邊界.圖8-3中,我們能看到5個外部邊界,其中3個包含孔.孔被v_next和v_prev可以只包括一個值,此節(jié)點可以只有一個子節(jié)點.c0中有兩個孔,因為v_next可以值包括一個值,次節(jié)點可以只有一個子節(jié)點.c0之內(nèi)的所有孔相互間有h_prev和h_next指針連接.

CV_RETR_TREE 檢出所有輪廓并且重新建立網(wǎng)狀的輪廓結(jié)構(gòu).在我們給出的例子中(圖8-2和8-3中),這意味著根節(jié)點是最外的輪廓c0.c0之下是空h00,在同一層次中與另一個孔h01相連接.同理,每個孔都有子節(jié)點(相對應(yīng)的是c000和c010),這些子節(jié)點與父節(jié)點被垂直連接起來.這個步驟一直持續(xù)到圖像最內(nèi)層的輪廓,這些輪廓會成為樹葉節(jié)點.

以下的五個值與方法相關(guān)(例如輪廓會如何被近似).

CV_CHAIN_CODE 用freeman鏈碼輸出輪廓,其他方法輸出多邊形(頂點的序列)

CV_CHAIN_APPROX_NONE 將鏈碼編碼中的所有點轉(zhuǎn)換為點

CV_CHAIN_APPROX_SIMPLE 壓縮水平,垂直或斜的部分,只保存最后一個點

CV_CHAIN_APPROX_TC89_L1或CV_CHAIN_APPROX_TC89_KCOS使用Ten-Chin鏈逼近算法中的一個

CV_LINK_RUNS 與上述算法完全不同的算法,連接所有水平層次的輪廓.此方法只可與Cv_RETR_LIST搭配使用.

使用序列表示輪廓

當(dāng)調(diào)用cvFindContours函數(shù)的時候,返回多個序列.序列的類型依賴與調(diào)用cvFindContours時 所傳遞的參數(shù).默認(rèn)情況下使用CV_RETR_LIST和CV_CHAIN_APPROX_SIMPLE參數(shù).

序列中保存一系列的點,這些點構(gòu)成輪廓,輪廓是本章的重點.輪廓只是序列所能表示物體的一種.輪廓的點的序列,可以用來表示圖像空間中的曲線.這種點的序列很常用,所有需要有專門的函數(shù)來幫助我們對他進(jìn)行處理.下面是一組這樣的處理函數(shù).

intcvFindContours(CvArr*image,CvMemStorage*storage,

CvSeq**first_contour,

intheader_sizeCV_DEFAULT(sizeof(CvContour)),

intmodeCV_DEFAULT(CV_RETR_LIST),

intmethodCV_DEFAULT(CV_CHAIN_APPROX_SIMPLE),

CvPointoffsetCV_DEFAULT(cvPoint(0,0)));

CvContourScannercvStartFindContours(CvArr*image,

CvMemStorage*storage,

intheader_sizeCV_DEFAULT(sizeof(CvContour)),

intmodeCV_DEFAULT(CV_RETR_LIST),

intmethodCV_DEFAULT(CV_CHAIN_APPROX_SIMPLE),

CvPointoffsetCV_DEFAULT(cvPoint(0,0)));

CvSeq*cvFindNextContour(CvContourScannerscanner);

voidcvSubstituteContour(CvContourScannerscanner,CvSeq*new_contour);

/*Releasescontourscannerandreturnspointertothefirstoutercontour*/

CvSeq*cvEndFindContours(CvContourScanner*scanner);

/*ApproximatesasingleFreemanchainoratreeofchainstopolygonalcurves*/

CvSeq*cvApproxChains(CvSeq*src_seq,

CvMemStorage*storage,

intmethodCV_DEFAULT(CV_CHAIN_APPROX_SIMPLE),

doubleparameterCV_DEFAULT(0),

intminimal_perimeterCV_DEFAULT(0),

intrecursiveCV_DEFAULT(0));

第一函數(shù)是cvFindContours(),在前面已經(jīng)提到.接著是cvStartFindContiors()函數(shù),它和cvFin的Contours()功能類似.但是cvStartFindContours()每次放回一個輪廓,而不像cvFinContours()那樣一次查找所有輪廓然后統(tǒng)一返回.調(diào)用cvStartFindContours()函數(shù)后,返回一個CvSequenceScanner結(jié)構(gòu).CvSequenceScanner結(jié)構(gòu)中包含一些狀態(tài)信息,這些信息不可讀.你可以通過在cvSequenceScabber結(jié)構(gòu)上依次調(diào)用cvFinNextContour()來查找剩余的輪廓.當(dāng)全部輪廓都被找完之后,cvFindNextContour()將放回NULL

cvSubstituteContour()函數(shù)用于替換scanner指向的輪廓.該函數(shù)的一個特性是,如果參數(shù) new_contour為NULL,那么當(dāng)前的輪廓將被從Scanner指定的樹或鏈表中刪除(受影響的序列會作適當(dāng)更新,來保證不會有指針指向不存在的物體).

函數(shù)cvEndFindContour()結(jié)束輪廓查找,并且將scanner設(shè)置為結(jié)束狀態(tài).注意,scanner并沒有被刪除,實際上該函數(shù)返回的是指針?biāo)感蛄械牡谝粋€元素.

最后一個函數(shù)cvApproxChains()函數(shù).該函數(shù)將Freeman鏈轉(zhuǎn)換為多邊形表示(精確轉(zhuǎn)換或者近似擬合).

Freeman鏈碼

一般情況下,通過cvFindCountours獲取的輪廓是一系列頂點的序列.另一種不同的表達(dá)是設(shè)置method參數(shù)為CV_CHAIN_CODE,然后生成輪廓.當(dāng)選者CV_CHAIN_CODE標(biāo)志的時候,檢測的輪廓通過Freemain鏈碼[Freeman67](圖8-4)的方式返回.在Freeman鏈碼中,多邊形被表示為一系列的位移,每一個位移有8個方向,這8個方向使用整數(shù)0到7表示.Freeman鏈碼對于識別一些形狀的物體很有幫助.如果得到的是Freeman鏈碼,可以通過以下兩個函數(shù)讀出每個點

voidcvStartReadChainPoints(CvChain*chain,

CvChainPtReader*reader);

CvPointcvReadChainPoint(CvChainPtReader*reader);

opencv用序列存儲輪廓

第一個函數(shù)用來初始化Freeman鏈CvChainPtReader結(jié)構(gòu),第二個函數(shù)通過CvChainptReader來讀每個點,CvChainPtReader對應(yīng)當(dāng)前狀態(tài).結(jié)構(gòu)CvChain從CvSeq擴(kuò)展得來.和CvContourScanner從多個輪廓間迭代一樣,CvChainPtReader用于迭代一個使用Freemain鏈碼表示輪廓中的每個點.CvChainPtReader和CvSeqReader的用法類似.如您所期望,當(dāng)所有點都讀完后,返回CvChainPtReader值為NULL.

繪制輪廓

一個經(jīng)常使用的功能是在屏幕上繪制檢測到的輪廓.繪制可以用cvDrawContours函數(shù)完成

/*Drawscontouroutlinesorfilledinteriorsontheimage*/

voidcvDrawContours(CvArr*img,CvSeq*contour,

CvScalarexternal_color,CvScalarhole_color,

intmax_level,

intthicknessCV_DEFAULT(1),

intline_typeCV_DEFAULT(8),

CvPointoffsetCV_DEFAULT(cvPoint(0,0)));

第一個參數(shù)為要繪制輪廓的圖像.第二個參數(shù)是要繪制的輪廓,他不像乍看上去那么簡單,他是輪廓樹的根節(jié)點.其他的參數(shù)(主要是max_level)將會控制如何繪制輪廓樹.下一個參數(shù)很容易理解,是繪制輪廓所用的顏色.但是hole_color那?請回憶輪廓的分類,有外輪廓,也有"洞"(圖8-2中的虛劃線和點線).無論繪制單個輪廓還是輪廓樹中的所有輪廓,標(biāo)記為"洞"的輪廓都會使用hole_color指定的顏色繪制.

通過max_level變量可以告訴cvDrawConturs() 如何處理通過節(jié)點樹變量連結(jié)到一個輪廓上的其他任何輪廓.此變量可以被設(shè)置為遍歷輪廓的最大深度.因此max_level = 0表示與輸入輪廓屬于同意等級的所有輪廓(更具體的說,輸入輪廓和與其相鄰的輪廓被畫出),max_level = 1表示與輸入輪廓屬于同一登記的所有輪廓與其子節(jié)點被畫出,以此類推.如果項要畫的輪廓是由cvFindContous()的CV_RETR_CCOMP或CV_RETR_TREE模式得到的話,max_level的負(fù)值也是被支持的.在這種情況下,max_level=-1表示只有輸入輪廓被畫出,以此類推,max_level = -2 表示輸入輪廓與其直系(僅直接相連的)子節(jié)點會被畫出,以此類推.

參數(shù)thickness和line_type就如其字面含義所示.最后,我們可以給繪圖程序一個偏移量,這樣輪廓可以被畫在指定的精確坐標(biāo)上.當(dāng)輪廓坐標(biāo)被轉(zhuǎn)換成質(zhì)心坐標(biāo)或其他局部坐標(biāo)系的時候,這個特性非常有用.如果在圖像上的不同感興趣的區(qū)域多次執(zhí)行cvFindContour(),然后又想將所有結(jié)果在原來大圖像上顯示出來,便宜量offset也很有用.相反,可以先從大圖提取出一個輪廓,然后在用offset和填充,在小圖像上形成和輪廓對應(yīng)的蒙板(mask);

輪廓例子

首先創(chuàng)建一個窗口用于顯示圖像,滑動條(trackbar)用于設(shè)置閾值,然后對采二值化后的圖像提取輪廓并繪制輪廓.當(dāng)控制參數(shù)的滑動條變換時,圖像被更新.

#include"stdafx.h"

#include

#include

IplImage*g_image=NULL;

IplImage*g_gray=NULL;

intg_thresh=100;

CvMemStorage*g_storage=nullptr;

voidon_trackbar(int)

{

if(g_storage==nullptr)

{

g_gray=cvCreateImage(cvGetSize(g_image),8,1);

g_storage=cvCreateMemStorage(0);

}

else

{

cvClearMemStorage(g_storage);

}

CvSeq*contours=NULL;

cvCvtColor(g_image,g_gray,CV_BGR2GRAY);

cvThreshold(g_gray,g_gray,g_thresh,255,CV_THRESH_BINARY);

cvFindContours(g_gray,g_storage,&contours);

cvZero(g_gray);

if(contours)

{

cvDrawContours(g_gray,contours,cvScalarAll(255),cvScalarAll(255),100);

}

cvShowImage("Contours",g_gray);

}

int_tmain(intargc,_TCHAR*argv[])

{

g_image=cvLoadImage("C:\\Users\\chenchao\\Desktop\\細(xì)胞圖象\\正常的紅細(xì)胞\\5.bmp");

cvNamedWindow("Contours",1);

cvCreateTrackbar("Threshold","Contours",&g_thresh,300,on_trackbar);

on_trackbar(0);

cvWaitKey(0);

printf("HELLO");

return0;

}

如果全局參數(shù)g_storage為NULL的話,則用cvCreateMemSotrage(0)創(chuàng)建一個內(nèi)存存儲器.g_gray被初始化為和g_image同樣大小的黑色圖像,但是為單通道圖像.如果g_storage非空的話,則先用cvClearMemStorage清空內(nèi)存存儲器的中間,這樣以便重復(fù)利用內(nèi)存存儲器中的資源.然后創(chuàng)建一個CvSeq*指針,該指針用來保存cvFindCountours()檢測到的輪廓.

然后g_image被轉(zhuǎn)換為灰度圖像,接著用g_thresh為參數(shù)進(jìn)行二值化處理,得到的二值圖像保存在g_gray中.cvFindContours從二值圖像g_gray查找輪廓,然后將得到的輪廓用cvDrawContours()函數(shù)繪制為白色到灰度圖像.最終圖像在窗口中顯示出來,并將在回調(diào)函數(shù)開始處申請的結(jié)構(gòu)釋放.

另一個輪廓的例子

在上例中,我們檢測出輸入圖像的輪廓,然后逐個繪制沒格輪廓.從這個例子中,我們可以了解到輪廓檢測方法(如代碼中是CV_RETR_LIST)以及max_depth(代碼中是0)等參數(shù)的細(xì)節(jié).如果設(shè)置的max_depth是一個比較大的值,你可以發(fā)現(xiàn)cvFindCountours()返回的輪廓是通過h_next連接被遍歷.對于其他一些拓?fù)浣Y(jié)構(gòu)(CV_RETR_TREE,CV_REER_CCOMP等),你會發(fā)現(xiàn)有些輪廓被畫過不只一次

例8-3 在輸入圖像上尋找并繪制輪廓

int_tmain(intargc,_TCHAR*argv[])

{

cvNamedWindow("src");

IplImage*img_8uc1=cvLoadImage("C:\\Users\\chenchao\\Desktop\\細(xì)胞圖象\\正常的紅細(xì)胞\\5.bmp",0);

IplImage*img_edge=cvCreateImage(cvGetSize(img_8uc1),8,1);

IplImage*img_8uc3=cvCreateImage(cvGetSize(img_8uc1),8,3);

cvThreshold(img_8uc1,img_edge,128,255,CV_THRESH_BINARY);

CvMemStorage*storage=cvCreateMemStorage(0);

CvSeq*first_contour=nullptr;

intNc=cvFindContours(img_edge,storage,&first_contour,sizeof(CvContour),CV_RETR_LIST);

intn=0;

printf("TotalContoursDetected:%d\n",Nc);

for(CvSeq*c=first_contour;c!=NULL;c=c->h_next)

{

cvCvtColor(img_edge,img_8uc3,CV_GRAY2BGR);

cvDrawContours(img_8uc3,c,cvScalar(0,255,0),cvScalar(0,0,255),0,2,8);

printf("contours#%d\n",n);

cvShowImage("src",img_8uc3);

printf("%delements:\n",c->total);

for(inti=0;itotal;++i)

{

CvPoint*p=CV_GET_SEQ_ELEM(CvPoint,c,i);

printf("(%d,%d)\n",p->x,p->y);

}

cvWaitKey(0);

n++;

}

printf("Finishedallcontours.\n");

cvCvtColor(img_8uc1,img_8uc3,CV_GRAY2BGR);

cvShowImage("src",img_8uc3);

cvWaitKey(0);

cvDestroyWindow("src");

cvReleaseImage(&img_8uc1);

cvReleaseImage(&img_8uc3);

cvReleaseImage(&img_edge);

return0;

}

深入分析輪廓

多邊形逼近

當(dāng)我們繪制一個多邊形或者進(jìn)行形狀分析的時候,通常需要使用多邊形畢竟一個輪廓,使頂點數(shù)目變少.有多種方法可以實現(xiàn)這個功能,OpenCV實現(xiàn)了其中的一種逼近算法.函數(shù)cvApproxPoly是該算法的一種實現(xiàn),可以處理輪廓的序列.

(CvSeq*)cvApproxPoly(constvoid*src_seq,

intheader_size,CvMemStorage*storage,

intmethod,doubleeps,

intrecursiveCV_DEFAULT(0));

我們可以傳遞一個列表或者數(shù)狀序列給cvApproxPoly,然后對其表示的輪廓進(jìn)行處理.函數(shù)返回值對應(yīng)第一個輪廓,同樣我們可用通過h_next(以及v_next)來訪問返回其他的輪廓.

因為cvApproxPoly在返回結(jié)果的時候需要創(chuàng)建新的對象,因此 需要指定一個內(nèi)存存儲器以及頭結(jié)構(gòu)大小.(一般為sizeof(CvContour)).

逼急算法目前只可使用CV_POLY_APPROx_DP.另外兩個參數(shù)為逼近算法參數(shù)(目前只用到第一個).eps參數(shù)指定逼近的精度.如果想了解這個參數(shù)如何起作用的的必須仔細(xì)了解具體的算法.最后一個參數(shù)指定是否針對全部的輪廓(通過h_next和v_next可達(dá)的)進(jìn)行逼近

如果為0,則表示只處理src_seq指向輪廓.

下面簡要介紹一下算法的工作原理.參考圖8-5,算法先從輪廓(圖b)選擇2個最遠(yuǎn)的點,然后將2個連成一個線段(圖c),然后再查找輪廓上到線段距離最遠(yuǎn)的點,添加到逼近后的心輪廓(圖d).算法反復(fù)迭代,不斷將最遠(yuǎn)點的添加到結(jié)果中.直到所有點的點到多邊形的最短距離小于eps參數(shù)指定的精度(圖f).從這里可以看出,精度和輪廓的周長,或者外包矩形周長的幾分之一比較合適.

opencv用序列存儲輪廓

曲線逼近的過程和尋找關(guān)掉點的過程密切相關(guān)。跟曲線上的其他點相比,關(guān)鍵點是那些包含曲線信息比較多的點。關(guān)鍵點在逼近算法以及其他應(yīng)用中都會涉及。函數(shù)cvFindDominantPoints()實現(xiàn)了被稱為IPAN*[Chetvreikov99]的算法.

CvSeqcvFindDominantPoints(CvSeq*contour,

CvMemStorage*storage,

intmetod=CV_DOMINANT_IPAN,

doubleparameter1=0,

doubleparameter2=0,

doubleparameter3=0,

doubleparameter4=0);

本質(zhì)上,IPAN算法通過掃描輪廓上并在曲線內(nèi)部使用可能頂點構(gòu)造三角形來實現(xiàn).對于三角形的大小和張角有特殊要求.在此某一特定的全局閾值和它的相鄰的張角小的情況下,具有大張角的點被保留.

函數(shù)cvFindDominantPoints()按照慣例使用參數(shù)CvSeq* 和CvMemStorage* .并且要求指定一個方法,和cvApproxPoly()相同,目前可供選擇的方法只有一個,就是CV_DOMINANT_IPAN.

opencv用序列存儲輪廓

接下來四個參數(shù)是:最短距離dmin,最長距離dmax,相鄰距離dn和最大角度θmax.如圖8-6所示,算法首先把所有兩邊距離rpa和rpb在dmin和dmax之間,θab

特性概括

輪廓處理中經(jīng)常遇到的另一個任務(wù)是計算一些輪廓變化的概括特性.這可能包括長度或者其他一些反映輪廓整體大小的度量.另一個有用的特性是輪廓的輪廓矩(contourmoment),可以用來概括輪廓的總形狀特性

長度

函數(shù)cvContourPerimeter()作用于一個輪廓并返回其長度.事實上,此函數(shù)是一個調(diào)用函數(shù)cvArcLength()的宏.

CVAPI(double)cvArcLength(constvoid*curve,

CvSlicesliceCV_DEFAULT(CV_WHOLE_SEQ),

intis_closedCV_DEFAULT(-1));

CV_INLINEdoublecvContourPerimeter(constvoid*contour)

{

returncvArcLength(contour,CV_WHOLE_SEQ,1);

}

cvArcLength()的第一參數(shù)是輪廓,其形式可以是點的序列(CvContour*或CvSeq*)或任一n×2的點的數(shù)組.后邊的參數(shù)是slice,以及表明是否將輪廓視為閉合的一個布爾類型(例如,是否將輪廓的最后一個點視為和第一個點有連接).slice可以讓我們只選擇曲線上的點的部分集合.

一個和cvArcLength()有緊密關(guān)系的函數(shù)是cvContourArea(),如其名稱所示,這個函數(shù)同于計算輪廓的面積.函數(shù)的參數(shù)contour和slice和cvArcLength()一樣.

CVAPI(double)cvContourArea(constCvArr*contour,

CvSlicesliceCV_DEFAULT(CV_WHOLE_SEQ),

intorientedCV_DEFAULT(0));

邊界框

當(dāng)然長度和面積只是輪廓的簡單特性,更復(fù)雜一些的特性描述應(yīng)該是矩形邊界框,圓形邊界框或橢圓形邊界框.有兩種方法可以得到矩形邊界框,圓形與橢圓形編輯框各只有一種方法.

CVAPI(CvRect)cvBoundingRect(CvArr*points,

intupdateCV_DEFAULT(0));

CVAPI(CvBox2D)cvMinAreaRect2(constCvArr*points,

CvMemStorage*storageCV_DEFAULT(NULL));

最簡單的方法是調(diào)用函數(shù)cvBoundingRect();它將放回一個包圍輪廓的CvRect.第一個參數(shù)points可以是由點組成的序列,一個輪廓(CvContour*)或者一個n×1雙通道的矩陣(CvMat*).為了理解第二個參數(shù)update,我們需要想想前面的描述,當(dāng)時說CvContour并不完全等于CvSeq;CvSeq能實現(xiàn)的CvContour都可以實現(xiàn),CvContour甚至能做的更多一點.其中一個附加功能就是CvRect成員可以記載輪廓自己的邊界框.如果調(diào)用函數(shù)cvBoundingRect()時參數(shù)update設(shè)置為0,便可以直接從CvCoutour的成員中獲取邊界框;如果將uodate設(shè)置為1,邊界框便會被計算出(CvContour成員的內(nèi)容也會被更新).

cvBoundingRect()得到的長方形的一個問題是,cvRect只能表現(xiàn)一個四邊水平和豎直的長方形.然而函數(shù)cvMinAreaRect2()可以返回一個包圍輪廓最小的長方形,這個長方形可能是傾斜的;請看圖8-7,該函數(shù)的參數(shù)和cvBoundingRect()的相似.opencv的數(shù)據(jù)類型CvBox2D就是用來表述這樣的長方形狀的.

typedefstructCvBox2D

{

CvPoint2D32fcenter;/*Centerofthebox.*/

CvSize2D32fsize;/*Boxwidthandlength.*/

floatangle;/*Anglebetweenthehorizontalaxis */

/*andthefirstside(i.e.length)indegrees*/

}

CvBox2D;

opencv用序列存儲輪廓

圓形和橢圓形邊界

接著我們來看函數(shù)cvMinEnclosingCircle().該函數(shù)和矩形邊界框的作用基本相同,輸入同樣很靈活,可以是點的序列,也可以是二維點的數(shù)組.

CVAPI(int)cvMinEnclosingCircle(constCvArr*points,

CvPoint2D32f*center,

float*radius);

OpenCV里沒有專門用來表示圓的結(jié)構(gòu),因此需要給函數(shù)cvMinEnclosingCircle()傳遞中心和浮點型半徑的兩個指針來獲取計算結(jié)果.

與最小包圍圓一樣,OpenCV提供一函數(shù)來擬合一組點,以獲取最佳擬合橢圓

CVAPI(CvBox2D)cvFitEllipse2(constCvArr*points);

cvMinEnclosingCircle()和cvFitEllipse2()的細(xì)微差別在于,前者只簡單計算完全包圍已有輪廓的最小圓,而后者使用擬合函數(shù)返回一個與輪廓最相近似的橢圓.這意味著并不是輪廓中所有的點都會被包在cvFitEllipse2()返回的橢圓中.該擬合由最小二乘擬合方法算出.

橢圓的擬合結(jié)果由CvBox2D結(jié)構(gòu)體返回,給出的矩形正好完全包圍橢圓,如圖8-8所示.

opencv用序列存儲輪廓

幾何

在處理CvBox2D或多邊形邊界的時候,經(jīng)常需要進(jìn)行多邊形以及邊界框的重疊判斷.OpenCV提供了一組方便的小函數(shù)用于此類測試.

CVAPI(CvRect)cvMaxRect(constCvRect*rect1,

constCvRect*rect );

CVAPI(void)cvBoxPoints(CvBox2Dbox,CvPoint2D32fpt[4]);

/*Initializessequenceheaderforamatrix(columnorrowvector)ofpoints-awrapperforcvMakeSeqHeaderForArray(itdoesnotinitializeboundingrectangle!!!)*/

CVAPI(CvSeq*)cvPointSeqFromMat(intseq_kind,

constCvArr*mat,

CvContour*contour_header,

CvSeqBlock*block);

/*Checkswhetherthepointisinsidepolygon,outside,onanedge(at avertex).Returnspositive,negativeorzerovalue,

correspondingly.Optionally,measuresasigneddistancebetween

thepointandthenearestpolygonedge(measure_dist=1)*/

CVAPI(double)cvPointPolygonTest(constCvArr*contour,

CvPoint2D32fpt,intmeasure_dist);

第一個函數(shù)cvMaxRect()根據(jù)輸入的2個矩形計算,他們的最小外包矩形.

下一個使用函數(shù)cvBoxPoints()用于計算CvBox2D結(jié)構(gòu)表示矩形的4個頂點.當(dāng)然你也可以自己通過三角函數(shù)計算,不過這令人頭大,而簡單調(diào)用一下這個函數(shù)則可求出.

第三實用函數(shù)cvPointSeqFromMat()從mat中初始化序列.這在你需要使用輪廓相關(guān)的函數(shù),但是函數(shù)又不支持矩陣參數(shù)的時候使用.第一個參數(shù)用于指定點序列類型,seq_kind可以為以下類型:點集為0;曲線為CV_SEQ_KIND_CURVE;封閉曲線為CV_SEQ_KIND_CURVE|Cv_SEQ_FLAG_CLOSED.第二個參數(shù)是輸入的矩陣,該參數(shù)是連續(xù)的1維向量.矩陣類型必須為cv_32C2或CV_32FC2.

下面的兩個參數(shù)是指針,指針指向的內(nèi)容通過該函數(shù)填充.contour_header參數(shù)對應(yīng)輪廓結(jié)構(gòu),一般要事先創(chuàng)建,不過由該函數(shù)負(fù)責(zé)初始化.block參數(shù)同樣如此,也是由該函數(shù)復(fù)雜初始化.最后,該函數(shù)放回一個類型為CvSeq*的序列指針,指向你輸入的序列頭*contour_header.返回值跟輸入?yún)?shù)相同只是為了使用該函數(shù)時更方便,因為這樣你就可以將該函數(shù)當(dāng)作某個輪廓函數(shù)的參數(shù)使用,代碼寫入同一行.

最后一個平面幾個相關(guān)的函數(shù)是cvPointPolygonTest(),用于測試一個點是否在多邊形的內(nèi)部.如果參數(shù)measure_dist非零,函數(shù)返回值是點到多邊形最近距離.如果measure_dist為0,函數(shù)返回+1,-1,0,分別表示在內(nèi)部,外部,在多邊形邊上.參數(shù)contour可以是序列,也可以是2通道矩陣向量.

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 存儲器
    +關(guān)注

    關(guān)注

    38

    文章

    7641

    瀏覽量

    166670
  • OpenCV
    +關(guān)注

    關(guān)注

    32

    文章

    642

    瀏覽量

    42569

原文標(biāo)題:opencv輪廓及點在輪廓內(nèi)判斷

文章出處:【微信號:C_Expert,微信公眾號:C語言專家集中營】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦
    熱點推薦

    創(chuàng)建包圍輪廓的矩形和圓形邊界框_《OpenCV3編程入門》書本配套源代碼

    OpenCV3編程入門》書本配套源代碼:創(chuàng)建包圍輪廓的矩形和圓形邊界框
    發(fā)表于 06-06 15:25 ?3次下載

    創(chuàng)建包圍輪廓的矩形邊界初級圖像混合_《OpenCV3編程入門》書本配套源代碼

    OpenCV3編程入門》書本配套源代碼:創(chuàng)建包圍輪廓的矩形邊界初級圖像混合
    發(fā)表于 06-06 15:39 ?1次下載

    創(chuàng)建包圍輪廓的圓形邊界_《OpenCV3編程入門》書本配套源代碼

    OpenCV3編程入門》書本配套源代碼:創(chuàng)建包圍輪廓的圓形邊界
    發(fā)表于 06-06 15:39 ?3次下載

    輪廓查找基礎(chǔ)_《OpenCV3編程入門》書本配套源代碼

    OpenCV3編程入門》書本配套源代碼:輪廓查找基礎(chǔ)
    發(fā)表于 06-06 15:39 ?4次下載

    OpenCV3編程入門-源碼例程全集-創(chuàng)建包圍輪廓的矩形邊界

    OpenCV3編程入門-源碼例程全集-創(chuàng)建包圍輪廓的矩形邊界
    發(fā)表于 09-17 22:54 ?1次下載

    OpenCV3編程入門-源碼例程全集-創(chuàng)建包圍輪廓的矩形和圓形邊

    OpenCV3編程入門-源碼例程全集-創(chuàng)建包圍輪廓的矩形和圓形邊界框
    發(fā)表于 09-17 22:54 ?2次下載

    OpenCV3編程入門-源碼例程全集-創(chuàng)建包圍輪廓的圓形邊界

    OpenCV3編程入門-源碼例程全集-創(chuàng)建包圍輪廓的圓形邊界
    發(fā)表于 09-17 22:54 ?0次下載

    OpenCV3編程入門-源碼例程全集-查找和繪制圖片輪廓

    OpenCV3編程入門-源碼例程全集-查找和繪制圖片輪廓
    發(fā)表于 09-17 22:54 ?2次下載

    OpenCV3編程入門-源碼例程全集-查找并繪制輪廓綜合示例

    OpenCV3編程入門-源碼例程全集-查找并繪制輪廓綜合示例
    發(fā)表于 09-17 22:54 ?6次下載

    輪廓查找基礎(chǔ)_OpenCV3編程入門-源碼例程

    OpenCV3編程入門-源碼例程全集-輪廓查找基礎(chǔ),感興趣的小伙伴們可以瞧一瞧。
    發(fā)表于 09-18 16:55 ?0次下載

    opencv輪廓提取原理與代碼的實現(xiàn)

    在檢測物體的輪廓時,我們通常會使用到opencv中的findcontour和drawcontour,比較常用而且效果不錯。那么findcontour是基于什么原理來實現(xiàn)輪廓的提取呢?在目標(biāo)識別中我們
    發(fā)表于 12-04 16:29 ?3.2w次閱讀

    如何才能提取二值圖像中的最大輪廓OpenCV程序免費下載

      本文檔的主要內(nèi)容詳細(xì)介紹的是如何才能提取二值圖像中的最大輪廓OpenCV程序免費下載。
    發(fā)表于 10-10 16:49 ?3次下載
    如何才能提取二值圖像中的最大<b class='flag-5'>輪廓</b><b class='flag-5'>OpenCV</b>程序免費下載

    opencv 輪廓放大_OpenCV開發(fā)筆記(六十六):紅胖子8分鐘帶你總結(jié)形態(tài)學(xué)操作-膨脹、腐蝕、開運(yùn)算、閉運(yùn)算、梯

    opencv 輪廓放大_OpenCV開發(fā)筆記(六十六):紅胖子8分鐘帶你總結(jié)形態(tài)學(xué)操作-膨脹、腐蝕、開運(yùn)算、閉運(yùn)算、梯......
    發(fā)表于 11-24 14:21 ?21次下載
    <b class='flag-5'>opencv</b> <b class='flag-5'>輪廓</b>放大_<b class='flag-5'>OpenCV</b>開發(fā)筆記(六十六):紅胖子8分鐘帶你總結(jié)形態(tài)學(xué)操作-膨脹、腐蝕、開運(yùn)算、閉運(yùn)算、梯

    使用輪廓分?jǐn)?shù)提升時間序列聚類的表現(xiàn)

    我們將使用輪廓分?jǐn)?shù)和一些距離指標(biāo)來執(zhí)行時間序列聚類實驗,并且進(jìn)行可視化
    的頭像 發(fā)表于 10-17 10:35 ?844次閱讀
    使用<b class='flag-5'>輪廓</b>分?jǐn)?shù)提升時間<b class='flag-5'>序列</b>聚類的表現(xiàn)

    OpenCV4之圖像的輪廓

    圖像的輪廓是指圖像中具有相同顏色或灰度值的連續(xù)點的曲線。輪廓和邊緣是有聯(lián)系的,邊緣是輪廓的基礎(chǔ),輪廓是邊緣的連續(xù)集合。
    的頭像 發(fā)表于 01-02 12:24 ?1004次閱讀
    主站蜘蛛池模板: 青草91 | 天天拍天天干天天操 | 影音先锋色偷偷米奇四色 | 三级视频欧美 | 一级午夜免费视频 | free性欧美高清另类 | 手机在线视频你懂的 | 黄网站在线观看高清免费 | 免费看黄资源大全高清 | 午夜精品福利在线 | 久久精品隔壁老王影院 | 国产午夜在线观看视频播放 | 天天狠狠弄夜夜狠狠躁·太爽了 | 亚洲一区不卡视频 | 亚洲网站免费 | 久久成人国产精品青青 | 国产在播放一区 | 日本v片免费一区二区三区 日本www.色 日本wwwwww | 亚洲三级在线视频 | 国产天堂网 | 色视频色露露永久免费观看 | 拍拍拍美女黄色1000视频 | 中文字幕 视频一区 | 男男失禁play 把尿bl | 天天摸天天舔天天操 | 国产精品免费一级在线观看 | 午夜性视频 | 国产精品1区2区3区在线播放 | 久久精品国产亚洲5555 | 久久精品国产99久久72 | 2020夜夜操| 男女在线免费视频 | 日本片巨大的乳456线观看 | 亚洲 欧美 日韩 在线 中文字幕 | 免看一级a毛片一片成人不卡 | www.成人av.com| 免费黄视频网站 | 精品国产成人三级在线观看 | 国产午夜在线观看视频播放 | 美女全黄网站免费观看 | 国产狂喷冒白浆免费视频 |