日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

OpenCV图像的轮廓的匹配

發(fā)布時(shí)間:2023/12/10 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 OpenCV图像的轮廓的匹配 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一個(gè)跟輪廓相關(guān)的最常用到的功能是匹配兩個(gè)輪廓.如果有兩個(gè)輪廓,如何比較它們;或者如何比較一個(gè)輪廓和另一個(gè)抽象模板.

比較兩個(gè)輪廓最簡(jiǎn)潔的方式是比較他們的輪廓矩.這里先簡(jiǎn)短介紹一個(gè)矩的含義.簡(jiǎn)單的說(shuō),矩是通過(guò)對(duì)輪廓上所有點(diǎn)進(jìn)行積分運(yùn)算(或者認(rèn)為是求和運(yùn)算)而得到的一個(gè)粗略特征.通常,我們?nèi)缦露x一個(gè)輪廓的(p,q)矩:


在公式中p對(duì)應(yīng)x緯度上的矩,q對(duì)應(yīng)y維度上的矩,q對(duì)應(yīng)y維度上的矩,階數(shù)表示對(duì)應(yīng)的部分的指數(shù).該計(jì)算是對(duì)輪廓邊界上所有像素(數(shù)目為n)進(jìn)行求和.如果p和q全為0,那么m00實(shí)際上對(duì)輪廓邊界上點(diǎn)的數(shù)目.

下面的函數(shù)用于計(jì)算這些輪廓矩

void cvContoursMoments(CvSeq* contour,CvMoments* moments)

第一個(gè)參數(shù)是我們要處理的輪廓,第二個(gè)參數(shù)是指向一個(gè)結(jié)構(gòu),該結(jié)構(gòu)用于保存生成的結(jié)果.CvMonments結(jié)構(gòu)定義如下

/* Spatial and central moments */? typedef struct CvMoments? {? ??? double? m00, m10, m01, m20, m11, m02, m30, m21, m12, m03; /* spatial moments */? ??? double? mu20, mu11, mu02, mu30, mu21, mu12, mu03; /* central moments */? ??? double? inv_sqrt_m00; /* m00 != 0 ? 1/sqrt(m00) : 0 */? }? CvMoments;? 在cvContourMoments()函數(shù)中,只用到m00,m01,...,m03幾個(gè)參數(shù);以mu開頭的參數(shù)在其他函數(shù)中使用.

在使用CvMoment結(jié)構(gòu)的時(shí)候,我們可以使用以下的函數(shù)來(lái)方便地一個(gè)特定的矩:

CVAPI(double)? cvGetSpatialMoment( CvMoments* moments, int x_order, int y_order );? 調(diào)用cvContoursMonments()函數(shù)會(huì)計(jì)算所有3階的矩(m21和m12會(huì)被計(jì)算,但是m22不會(huì)被計(jì)算).

再論矩

剛剛描述的矩計(jì)算給出了一些輪廓的簡(jiǎn)單屬性,可以用來(lái)比較兩個(gè)輪廓.但是在很多實(shí)際使用中,剛才的計(jì)算方法得到的矩并不是做比較時(shí)的最好的參數(shù).具體說(shuō)來(lái),經(jīng)常會(huì)用到歸一化的矩(因此,不同大小但是形狀相同的物體會(huì)有相同的值).同樣,剛才的小節(jié)中的簡(jiǎn)單的矩依賴于所選坐標(biāo)系,這意味這物體旋轉(zhuǎn)后就無(wú)法正確匹配.

OpenCV提供了計(jì)算Hu不變矩[Hu62]以及其他歸一化矩的函數(shù).CvMoments結(jié)構(gòu)可以用cvmoments或者cvContourMoments計(jì)算.并且,cvContourMoments現(xiàn)在只是cvMoments
的一個(gè)別名.

一個(gè)有用的小技巧是用cvDrawContour()描繪一幅輪廓的圖像后,調(diào)用一個(gè)矩的函數(shù)處理該圖像.使用無(wú)論輪廓填充與否,你都能用同一個(gè)函數(shù)處理.

以下是4個(gè)相關(guān)函數(shù)的定義:

/* Calculates all spatial and central moments up to the 3rd order */? CVAPI(void) cvMoments( const CvArr* arr, CvMoments* moments, int binary CV_DEFAULT(0));? CVAPI(double)? cvGetCentralMoment( CvMoments* moments, int x_order, int y_order );? CVAPI(double)? cvGetNormalizedCentralMoment(CvMoments* moments,int x_order, int y_order);? /* Calculates 7 Hu's invariants from precalculated spatial and central moments */? CVAPI(void) cvGetHuMoments( CvMoments*? moments, CvHuMoments*? hu_moments );? 第一個(gè)函數(shù)除了使用的是圖像(而不是輪廓)作為參數(shù),其他方面和cvContoursMoments()函數(shù)相同,另外還增加了一個(gè)參數(shù).增加的參數(shù)isBinary如果為CV_TRUE,cvMoments將把圖像當(dāng)作二值圖像處理,所有的非0像素都當(dāng)作1.當(dāng)函數(shù)被調(diào)用的時(shí)候,所有的矩被計(jì)算(包含中心矩,請(qǐng)看下一段).除了x和y的值被歸一化到以0為均值,中心距本質(zhì)上跟剛才描述的矩一樣.

歸一化矩和中心矩也基本相同,除了每個(gè)矩都要除以m00的某個(gè)冪:

最后來(lái)介紹Hu矩,Hu矩是歸一化中心距的線性組合.之所以這樣做是為了能夠獲取代表圖像某個(gè)特性的矩函數(shù),這些矩函數(shù)對(duì)于某些變化如縮放,旋轉(zhuǎn)和鏡像映射(除了h1)具有不變性.Hu矩是從中心矩中計(jì)算得到,其計(jì)算公式如下所示:

參考圖8-9和表8-1,我們可以直觀地看到每個(gè)圖像對(duì)應(yīng)的7個(gè)Hu矩.通過(guò)觀察可以發(fā)現(xiàn),當(dāng)階數(shù)變高時(shí),Hu矩一般會(huì)變小.對(duì)于這一點(diǎn)不必感到奇怪,因?yàn)楦鶕?jù)定義,高階Hu矩由多個(gè)歸一化矩的高階冪計(jì)算得到,而歸一化矩都是小于1的,所以指數(shù)越大,計(jì)算所得的值越小.


需要特別注意的是"I",它對(duì)于180度旋轉(zhuǎn)和鏡面反射都是對(duì)稱的,它的h3到h7矩都是0;而"O"具有同樣的對(duì)稱特性,所有的Hu矩都是非0的.

使用Hu矩進(jìn)行匹配

/* Compares two contours by matching their moments */? CVAPI(double)? cvMatchShapes( const void* object1, const void* object2,? ????????????????????????????? int method, double parameter CV_DEFAULT(0)); 很自然,使用Hu矩我們想要比較兩個(gè)物體并且判明他們是否相似.當(dāng)然,可能有很多"相似"的定義.為了使比較過(guò)程變得簡(jiǎn)單,OpenCV的函數(shù)cvMatShapes()允許我們簡(jiǎn)單地提供兩個(gè)物體,然后計(jì)算他們的矩并根據(jù)我們提供的標(biāo)準(zhǔn)進(jìn)行比較.

這些物體可以是灰度圖圖像或者輪廓.如果你提供了圖像,cvMatchShape()會(huì)在對(duì)比的進(jìn)程之間為你計(jì)算矩.cvMatchShapes()使用的方法是表8-2中列出的三種中的一種.

?關(guān)于對(duì)比度量標(biāo)準(zhǔn)(metric)是如何被計(jì)算的,表8-2中的三個(gè)常量每個(gè)都用了不同的方法.這個(gè)度量標(biāo)準(zhǔn)最終決定了cvMatchShapes()的返回值.最后一個(gè)參數(shù)變量現(xiàn)在不能用,因此我們可以把它設(shè)成默認(rèn)值0.

等級(jí)匹配

我們經(jīng)常想要匹配兩個(gè)輪廓,然后用一個(gè)相似度量來(lái)計(jì)算輪廓所有匹配部分.使用概況參數(shù)的方法(比如矩)是相當(dāng)快的,但是他們能夠表達(dá)的信息卻不是很多.

為了找到一個(gè)更精確的相似度量度,首先考慮一下輪廓樹的結(jié)構(gòu)應(yīng)該會(huì)有幫助.請(qǐng)注意,此外的輪廓樹是用來(lái)表述一個(gè)特定形狀(不是多個(gè)特定形狀)內(nèi)各部分的等級(jí)關(guān)系.

類似于cvFindContours()著怎樣的函數(shù)放回多個(gè)輪廓,輪廓樹(contout tree)并不會(huì)把這些等級(jí)關(guān)系搞混,事實(shí)上,他正是對(duì)于某個(gè)特定輪廓形狀的登記描述.

理解了輪廓樹的創(chuàng)建會(huì)比較容易理解輪廓樹.從一個(gè)輪廓?jiǎng)?chuàng)建一個(gè)輪廓樹是從底端(葉節(jié)點(diǎn))到頂端(根節(jié)點(diǎn))的.首相搜索三角形突出或凹陷的形狀的周邊(輪廓上的每一個(gè)點(diǎn)都不是完全和它的相鄰點(diǎn)共線的).每個(gè)這樣的三角形被一條線段代替,這條線段通過(guò)連接非相鄰點(diǎn)的兩點(diǎn)得到;因此實(shí)際上三角形或者被削平(例如,圖8-10的三角形D)或者被填滿(三角形C).每個(gè)這樣的替代把輪廓的頂點(diǎn)減少1,并且給輪廓?jiǎng)?chuàng)建一個(gè)新節(jié)點(diǎn).如果這樣一個(gè)三角形的兩側(cè)有原始的邊,那么它就是得到的輪廓樹的葉子;如果一側(cè)是已存在三角形,那么他就是那個(gè)三角形的父節(jié)點(diǎn).這個(gè)過(guò)程的迭代最終把物體的外形剪成一個(gè)四邊形,這個(gè)四邊形也被剖開;得到的兩個(gè)三角形是根節(jié)點(diǎn)的兩個(gè)子節(jié)點(diǎn).

結(jié)果的二分樹(圖8-11)最終將原始輪廓的形狀信息編碼.每個(gè)節(jié)點(diǎn)被它對(duì)應(yīng)的三角形信息(比如三角形的大小,它的生成是被切出來(lái)還是被填進(jìn)去的,這樣的信息)所注釋

這些樹一旦被建立,就可以很有效的對(duì)比兩個(gè)輪廓.這個(gè)過(guò)程開始定義兩個(gè)樹節(jié)點(diǎn)的對(duì)應(yīng)關(guān)系,然后比較對(duì)應(yīng)節(jié)點(diǎn)的特性.對(duì)吼的結(jié)果就是兩個(gè)樹的相似度.

事實(shí)上,我們基本不需要理解這個(gè)過(guò)程.OpenCV提供了一個(gè)函數(shù)從普通的CvContour對(duì)象自動(dòng)生成輪廓樹并轉(zhuǎn)換返回;還提供一個(gè)函數(shù)用來(lái)對(duì)比兩個(gè)樹.不幸的是,建立的輪廓樹并不太魯棒(例如,輪廓上很小的改變可能會(huì)徹底改變結(jié)果的樹).同事,最初的三角形(樹的根節(jié)點(diǎn))是隨意選取的.因此,為了得到較好的描述實(shí)現(xiàn)使用函數(shù)cvApproxPoly()之后將輪廓排列(運(yùn)用循環(huán)移動(dòng))成最初的三角形不怎么受到旋轉(zhuǎn)影響的狀態(tài).

CvContourTree* cvCreateContourTree(const CvSeq* contour,CvMemStorage* storage,double ?threshold);

CvSeq * cvContourFromContourTree(const CvContourTree* tree,CvMemStorage* storage, CvTermCriteria ?criteris);

double cvMatchContourTrees(const CvContourTree* tree1,const CvContourTree* tree2,int method,double threshold);

這個(gè)代碼提到了CvTremCriteria(),該函數(shù)細(xì)節(jié)將在第9章給出.現(xiàn)在可以用下面的默認(rèn)值使用cvTermCriteria()簡(jiǎn)單建立一個(gè)結(jié)構(gòu)體.

CvTermCriteria termcrit = cvTermCriteria(CV_TERMCRIT_ITER | CV_TeRMCRT_EPS,5,1);



輪廓的凸包和凸缺陷

另一個(gè)理解物體形狀或輪廓的有用的方法是計(jì)算一個(gè)物體的凸包(convex hull)然后計(jì)算其凸缺陷(convexity defects)[Homma85].很多復(fù)雜物體的特性能很好的被這種缺陷表現(xiàn)出來(lái).

圖8-12用人手舉例說(shuō)明了凸缺陷這一概念.手周圍深色的線描畫出了凸包,A到H被標(biāo)出的區(qū)域是凸包的各個(gè)"缺陷".正如所看到的,這些凸度缺陷提供了手以及手狀態(tài)的特征表現(xiàn)的方法.

enum? {? ??? CV_CLOCKWISE???????? =1,? ??? CV_COUNTER_CLOCKWISE =2? };? /* Calculates exact convex hull of 2d point set */? CVAPI(CvSeq*) cvConvexHull2( const CvArr* input,? ???????????????????????????? void* hull_storage CV_DEFAULT(NULL),? ???????????????????????????? int orientation CV_DEFAULT(CV_CLOCKWISE),? ???????????????????????????? int return_points CV_DEFAULT(0));? /* Checks whether the contour is convex or not (returns 1 if convex, 0 if not) */? CVAPI(int)? cvCheckContourConvexity( const CvArr* contour );? /* Finds convexity defects for the contour */? CVAPI(CvSeq*)? cvConvexityDefects( const CvArr* contour, const CvArr* convexhull,? ?????????????????????????????????? CvMemStorage* storage CV_DEFAULT(NULL));?

OpenCV有三個(gè)關(guān)于凸包和凸缺陷的重要函數(shù).第一個(gè)函數(shù)簡(jiǎn)單計(jì)算已知輪廓的凸包,第二個(gè)函數(shù)用來(lái)檢查一個(gè)已知輪廓是否是凸的.第三個(gè)函數(shù)在已知輪廓是凸包的情況下計(jì)算凸缺陷.

函數(shù)cvConvexHull2()的第一個(gè)參數(shù)是點(diǎn)的數(shù)組,這個(gè)數(shù)組是一個(gè)n行2列的矩陣(n×2),或者是一個(gè)輪廓.如果是點(diǎn)矩陣,點(diǎn)應(yīng)該是32位整型(CV_32SC1)或者是浮點(diǎn)型(CV_32F1).下一個(gè)參數(shù)是指向內(nèi)存存儲(chǔ)的一個(gè)指針,為結(jié)果分配內(nèi)存空間.下一參數(shù)是CV_CLOCkWISE或者是CV_COUNTERCLOCkWISE中的一個(gè).這參數(shù)決定了程序返回點(diǎn)的排列方向.最后一個(gè)參數(shù)returnPoints,可以是0或1.如果設(shè)置為1,點(diǎn)會(huì)被存儲(chǔ)在返回?cái)?shù)組中.如果設(shè)置為0,只有索引被存儲(chǔ)在返回?cái)?shù)組中.索引是傳遞給cvConvexHull2()的原始數(shù)組索引.

讀著可能要問(wèn):"如果參數(shù)hull_storage是內(nèi)存存儲(chǔ),為什么它的類型是void* 而不是CvMemSotrage* ?",這是因?yàn)楹芏鄷r(shí)候作為凸包放回的點(diǎn)的形式,數(shù)組可能比序列更加有用.可慮到這一點(diǎn),參數(shù)hull_storage的另一個(gè)可能性是傳遞一個(gè)指向矩陣的指針CvMat*. 這種情況下,矩陣應(yīng)該是一維的且和輸入點(diǎn)的個(gè)數(shù)相同.當(dāng)cvConvexHull2()被調(diào)用的時(shí)候,它會(huì)修改矩陣頭來(lái)指明當(dāng)前的列數(shù).

有時(shí)候,已知一個(gè)輪廓但并不知道它是否是凸的.這種情況下,我們可以調(diào)用函數(shù)cvCheckContourConvexity().這個(gè)測(cè)試簡(jiǎn)單快速,但是如果傳遞的輪廓自身有交叉的時(shí)候不會(huì)得到正確的結(jié)果.

第三個(gè)函數(shù)cvConvexityDefects(),計(jì)算凸缺陷返回一個(gè)缺陷的序列.為了完成這個(gè)任務(wù),cvConvexityDefects()要求輸入輪廓,凸包和內(nèi)存空間,從這個(gè)內(nèi)存空間來(lái)獲得存放結(jié)果序列的內(nèi)存.前兩個(gè)參數(shù)是CvArr*,和傳遞給cvConvexHull2()的參數(shù)input的形式相同.

typedef struct CvConvexityDefect? {? ??? CvPoint* start; /* point of the contour where the defect begins */? ??? CvPoint* end; /* point of the contour where the defect ends */? ??? CvPoint* depth_point; /* the farthest from the convex hull point within the defect */? ??? float depth; /* distance between the farthest point and the convex hull */? } CvConvexityDefect;? 函數(shù)cvConvexityDefects()返回一個(gè)CvConvexityDefect結(jié)構(gòu)體的序列,其中包括一些簡(jiǎn)單的參數(shù)用來(lái)描述凸缺陷.start和end是凸包上的缺陷的起始點(diǎn)和終止點(diǎn).depth_point是缺陷中的距離凸包的邊(跟該缺陷有關(guān)的凸包便)最遠(yuǎn)的點(diǎn).最后一個(gè)參數(shù)depth是最遠(yuǎn)點(diǎn)和包的邊(edge)的距離.

成對(duì)幾何直方圖

Freeman鏈碼編碼是對(duì)一個(gè)多邊形的的序列如何"移動(dòng)"的描述,每個(gè)這樣的移動(dòng)有固定長(zhǎng)度和特定的方向.但是,我們并沒(méi)有更多說(shuō)明為什么需要用到這種描述.

Freeman鏈碼編碼的用處很多,但最常見的一種值得深入了解一下,因?yàn)樗С至顺蓪?duì)幾何直方圖(PGH)的基本思想.

PGH實(shí)際上是鏈碼編碼直方圖(CCH)的一個(gè)擴(kuò)展或延伸.CCH是一種直方圖,用來(lái)統(tǒng)計(jì)一個(gè)輪廓的Freeman鏈碼編碼每一種走法的數(shù)字.這種直方圖有一些良好的性質(zhì).最顯著的是,將物體旋轉(zhuǎn)45度,那么新的直方圖是老直方圖的循環(huán)平移(圖8-13).這就提供了一個(gè)不被此類旋轉(zhuǎn)影響的形狀識(shí)別方法.

PGH的構(gòu)成如下圖所示(圖8-14).多邊形的每一個(gè)邊被選擇成為"基準(zhǔn)邊".之后考慮其他的邊相對(duì)于這些基礎(chǔ)邊的關(guān)系,并且計(jì)算三個(gè)值:dmin,dmax和θ.dmin是兩條邊的最小距離,dmax是最大距離,θ是兩邊的夾角.PGH是一個(gè)二維直方圖,其兩個(gè)維度分別是角度和距離.對(duì)于每一對(duì)邊,有兩個(gè)bin,一個(gè)bin為(dmin,θ),另一個(gè)bin為(dmax,θ).對(duì)于這樣的每一組邊,這兩個(gè)bin都被增長(zhǎng),中間值d(dmin和dmax之間的值)同樣也被增長(zhǎng).

PGh的使用和FCC相似.一個(gè)重要不同是,PGH的描述能力更強(qiáng),因此在嘗試解決復(fù)雜問(wèn)題的時(shí)候很有用,比如說(shuō)大量形狀需要被辨識(shí),并且/或者有很多背景噪聲的時(shí)候.用來(lái)計(jì)算PGh的函數(shù)是

void cvCalcPGH(const CvSeq* contour,CvHistogram* hist)

在這里輪廓可以包含整數(shù)值的點(diǎn)的坐標(biāo);當(dāng)然直方圖必須是二維的.

???????????

再分享一下我老師大神的人工智能教程吧。零基礎(chǔ)!通俗易懂!風(fēng)趣幽默!還帶黃段子!希望你也加入到我們?nèi)斯ぶ悄艿年?duì)伍中來(lái)!https://blog.csdn.net/jiangjunshow

總結(jié)

以上是生活随笔為你收集整理的OpenCV图像的轮廓的匹配的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。