opencv圖像輪廓

1.1什么是輪廓? ?cv2.findContours()

輪廓可以簡單認(rèn)為成連續(xù)的點(diǎn)(連著邊界)連在一起的曲線并思,具有相同的顏色或者灰度。輪廓在形狀分析和物體的檢測和識(shí)別中很有用。為了準(zhǔn)確拔创,要使用二值化圖像。需要進(jìn)行閥值化處理或者Canny邊界檢測。查找輪廓的函數(shù)會(huì)修改原始圖像车吹。如果之后想繼續(xù)使用原始圖像,應(yīng)該將原始圖像儲(chǔ)存到其他變量中醋闭。在OpenCV中窄驹,查找輪廓就像在黑色背景中超白色物體。你應(yīng)該記住证逻,要找的物體應(yīng)該是白色而背景應(yīng)該是黑色乐埠。

如何在一個(gè)二值圖像中查找輪廓。

函數(shù)cv2.findContours()有三個(gè)參數(shù)囚企,第一個(gè)是輸入圖像丈咐,第二個(gè)是輪廓檢索模式,第三個(gè)是輪廓近似方法龙宏。返回值有三個(gè)棵逊,第一個(gè)是圖像,第二個(gè)是輪廓银酗,第三個(gè)是(輪廓的)層析結(jié)構(gòu)辆影。輪廓(第二個(gè)返回值)是一個(gè)Python列表,其中儲(chǔ)存這圖像中所有輪廓黍特。每一個(gè)輪廓都是一個(gè)Numpy數(shù)組蛙讥,包含對(duì)象邊界點(diǎn)(x,y)的坐標(biāo)灭衷。

1.2怎樣繪制輪廓?cv2.drawContours()

函數(shù)cv2.drawContours()可以被用來繪制輪廓次慢。它可以根據(jù)你提供的邊界點(diǎn)繪制任何形狀。它的第一個(gè)參數(shù)是原始圖像今布,第二個(gè)參數(shù)是輪廓经备,一個(gè)python列表,第三個(gè)參數(shù)是輪廓的索引(在繪制獨(dú)立輪廓是很有用部默,當(dāng)設(shè)置為-1時(shí)繪制所有輪廓)。接下來的參數(shù)是輪廓的顏色和厚度造虎。

在一幅圖像上繪制所有的輪廓:

img = cv2.imread('gray.png')

imgray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

ret,thresh = cv2.threshold(imgray,127,255,0)

image ,contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

#繪制所有輪廓

#imag = cv2.drawContours(img,contours,-1,(0,255,0),3)

#繪制獨(dú)立輪廓傅蹂,如第四個(gè)輪廓

# imag = cv2.drawContours(img,contours,3,(0,255,0),3)

#但是大多數(shù)時(shí)候,下面方法更有用

cnt = contours[3]

imag = cv2.drawContours(img, [cnt], 0, (0,255,0), 3)

while(1):

????cv2.imshow('img',img)

????cv2.imshow('imgray',imgray)

????cv2.imshow('image',image)

????cv2.imshow('imag',imag)

????if cv2.waitKey(1) == ord('q'): break

cv2.destroyAllWindows()


1.3輪廓的近似方法

之前提到輪廓是一個(gè)形狀具有相同灰度值的邊界,它會(huì)存儲(chǔ)形狀邊界上所有的(x,y)坐標(biāo)份蝴。實(shí)際上我們不需要所有的點(diǎn)犁功,當(dāng)需要直線時(shí),找到兩個(gè)端點(diǎn)即可婚夫。cv2.CHAIN_APPROX_SIMPLE可以實(shí)現(xiàn)浸卦。它會(huì)將輪廓上的冗余點(diǎn)去掉,壓縮輪廓案糙,從而節(jié)省內(nèi)存開支限嫌。

2. 輪廓特征

2.1矩??cv2.moments()

圖像的矩可以幫助我們計(jì)算圖像的質(zhì)心,面積等时捌。

函數(shù)cv2.moments()會(huì)將計(jì)算得到的矩以一個(gè)字典的形式返回怒医。

img = cv2.imread('rectangle.png',0)

ret,thresh = cv2.threshold(img,127,255,0)

image,contours,hierarchy=cv2.findContours(thresh,1,2)

cnt=contours[0]

M=cv2.moments(cnt)

print(M)

根據(jù)這些矩的值,我們可以計(jì)算出對(duì)象的重心:

cx=int(M['m10']/M['m00'])

cy=int(M['m01']/M['m00'])

2.2輪廓面積??cv2.contourArea()

可以使用函數(shù)cv2.contourArea()計(jì)算得到奢讨,也可以用矩(0階矩)稚叹,M['m00']。

area=cv2.contourArea(cnt)

2.3輪廓周長??cv2.arcLength()

也被稱為弧長拿诸“切洌可以使用函數(shù)cv2.arcLength()計(jì)算得到。這個(gè)函數(shù)的第二參數(shù)可以用來指定對(duì)象的形狀是閉合的(True)亩码,還是打開的(一條曲線)僚稿。

perimeter= cv2.arcLength(cnt,True)

2.4輪廓近似??cv2.approxPolyDP()

將輪廓形狀近似到另外一種由更少點(diǎn)組成的輪廓形狀,新輪廓的點(diǎn)的數(shù)目由我們?cè)O(shè)定的準(zhǔn)確度來決定蟀伸,使用的Douglas-Peucker算法蚀同。

算法步驟

連接曲線首尾兩點(diǎn)A、B形成一條直線AB啊掏;

計(jì)算曲線上離該直線段距離最大的點(diǎn)C蠢络,計(jì)算其與AB的距離d;

比較該距離與預(yù)先給定的閾值threshold的大小迟蜜,如果小于threshold刹孔,則以該直線作為曲線的近似,該段曲線處理完畢娜睛。

如果距離大于閾值髓霞,則用點(diǎn)C將曲線分為兩段AC和BC,并分別對(duì)兩段曲線進(jìn)行步驟[1~3]的處理畦戒。

當(dāng)所有曲線都處理完畢后方库,依次連接各個(gè)分割點(diǎn)形成折線,作為原曲線的近似障斋。

假設(shè)我們要在一幅圖像中查找一個(gè)矩形纵潦,但是由于圖像的種種原因我們不能得到一個(gè)完美的矩形徐鹤,而是一個(gè)“壞形狀”,現(xiàn)在就可以使用這個(gè)函數(shù)來近似這個(gè)形狀邀层,第二個(gè)參數(shù)是epsilon返敬,它是從原始輪廓到近似輪廓的最大距離,它是一個(gè)準(zhǔn)確度參數(shù)寥院。

epsilon=0.1*cv2.arcLength(cnt,True)

approx= cv2.approxPolyDP(cnt,epsilon,True)

temp = cv2.cvtColor(image.copy(), cv2.COLOR_GRAY2BGR)

cv2.drawContours(temp, [approx], -1, (0, 255, 0), 2)

epsilon2=0.01*cv2.arcLength(cnt,True)

approx2= cv2.approxPolyDP(cnt,epsilon2,True)

temp2 = cv2.cvtColor(image.copy(), cv2.COLOR_GRAY2BGR)

cv2.drawContours(temp2, [approx2], -1, (0, 255, 0), 2)

plt.subplot(231),plt.imshow(img,'gray'),plt.title('original')

plt.subplot(232),plt.imshow(temp,'gray'),plt.title(' epsilon = 10%')

plt.subplot(233),plt.imshow(temp2,'gray'),plt.title(' epsilon = 1%')

plt.show()

2.5凸包??cv2.convexHull()

凸包與輪廓近似相似劲赠,但不同,雖然有些情況下它們給出的結(jié)果是一樣的秸谢。函數(shù)cv2.convexHull()可以用來檢測一個(gè)曲線是否具有凸性缺陷凛澎,并能糾正缺陷。一般來說钮追,凸性曲線總是凸出來的预厌,至少是平的。如果有地方凹進(jìn)去了就被叫做凸性缺陷元媚。例如下圖中的手轧叽,紅色曲線顯示了手的凸包,凸性缺陷被雙箭頭標(biāo)出來了刊棕。

hull= cv2.convexHull(points,hull,clockwise,returnPoints)

參數(shù):

points我們要傳入的輪廓

hull輸出炭晒,通常不需要

clockwise方向標(biāo)志,如果設(shè)置為True甥角,輸出的凸包是順時(shí)針方向的网严,否則為逆時(shí)針方向。

returnPoints默認(rèn)值為True嗤无。它會(huì)返回凸包上點(diǎn)的坐標(biāo)震束,如果設(shè)置為False,就會(huì)返回與凸包點(diǎn)對(duì)應(yīng)的輪廓上的點(diǎn)当犯。

要獲得上圖的凸包垢村,可以用下面命令:

hull=cv2.convexHull(cnt)

但是如果你想獲得凸性缺陷,需要把returnPoints設(shè)置為False嚎卫。以上面矩形為例嘉栓,首先我們找到他的輪廓從cnt。現(xiàn)在把returnPoints設(shè)置為True查找凸包拓诸,得到的就是矩形的四個(gè)角點(diǎn)侵佃。把returnPoints設(shè)置為False,得到的是輪廓點(diǎn)的索引奠支。

2.6凸性檢測??cv2.isContourConvex()

函數(shù)cv2.isContourConvex()可以檢測一個(gè)曲線是不是凸的馋辈。它只能返回True或者False。

k=cv2.isContourConvex(cnt)

2.7邊界矩形? ?cv2.boundingRect()? ?cv2.minAreaRect()

直邊界矩形胚宦,一個(gè)直矩形首有,沒有旋轉(zhuǎn)燕垃。不會(huì)考慮對(duì)象是否旋轉(zhuǎn)枢劝。所以邊界矩形的面積不是最小的井联。可以使用函數(shù)cv2.boundingRect()查找得到

#(x,y)為矩形左上角的坐標(biāo)您旁,(w,h)是矩形的寬和高

x,y,w,h=cv2.boundingRect(cnt)

img=cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)

旋轉(zhuǎn)的邊界矩形烙常,這個(gè)邊界矩形是面積最小的,因?yàn)樗紤]了對(duì)象的旋轉(zhuǎn)鹤盒。用函數(shù)cv2.minAreaRect()蚕脏。返回的是一個(gè)Box2D結(jié)構(gòu),其中包含矩形最上角角點(diǎn)坐標(biāo)(x侦锯,y)矩形的寬和高(w,h)以及旋轉(zhuǎn)角度驼鞭。但是要繪制這個(gè)矩形需要矩形的4個(gè)角點(diǎn),可以通過函數(shù)cv2.boxPoints()獲得尺碰。

其中綠色的為直矩形挣棕,紅色為旋轉(zhuǎn)矩形。

2.8最小外接圓??cv2.minEnclosingCircle()

函數(shù)cv2.minEnclosingCircle()可以幫我們找到一個(gè)對(duì)象的外接圓亲桥。它是所有能夠包括對(duì)象的圓中面積最小的一個(gè)洛心。

(x,y),radius = cv2.minEnclosingCircle(cnt)

center = (int(x),int(y))

radius = int(radius)

img = cv2.circle(img,center,radius,(0,255,0),2)

2.9橢圓擬合??cv2.ellipse()

使用函數(shù)cv2.ellipse(),返回值其實(shí)就是旋轉(zhuǎn)邊界矩形的內(nèi)切圓题篷。

ellipse= cv2.fitEllipse(cnt)

img= cv2.ellipse(img,ellipse,(0,255,0),2)

2.10直線擬合

可以根據(jù)一組點(diǎn)擬合出一條直線词身,同樣我們也可以為圖像中的白色點(diǎn)擬合出一條直線。

rows,cols =img.shape[:2]

[vx,vy,x,y]=cv2.fitLine(cnt,cv2.DIST_L2,0,0.01,0.01)

lefty=int((x*vy/vx)+y)

righty=int(((cols-x)*vy/vx)+y)

img= cv2.line(img,(cols-1,righty),(0,lefty),(0,255,0),2)

3.輪廓的性質(zhì)

3.1長寬比? ?cv2.boundingRect()

邊界矩形的寬高比

x,y,w,h=cv2.boundingRect(cnt)

aspect_ratio = float(w)/h

3.2.Extent? ?cv2.contourArea()? ?cv2.boundingRect()

輪廓面積與邊界矩形面積的比

area=cv2.contourArea(cnt)

x,y,w,h=cv2.boundingRect(cnt)

rect_area=w*h

extent=float(area)/rect_area

3.3.Solidity? ??cv2.contourArea()? ??cv2.convexHull()

輪廓面積與凸包面積的比

area=cv2.contourArea(cnt)

hull=cv2.convexHull(cnt)

hull_area=cv2.contourArea(hull)

solidity=float(area)/hull_area

3.4.與輪廓面積相等的圓形的直徑? ?cv2.contourArea()?

area=cv2.contourArea(cnt)

equi_diameter=np.sqrt(4*area/np.pi)

3.5.方向??cv2.fitEllipse()

對(duì)象的方向番枚,下面的方法還會(huì)返回長軸和短軸的長度

(x,y),(MA,ma),angle=cv2.fitEllipse(cnt)

3.6.掩模和像素點(diǎn)

有時(shí)我們需要構(gòu)成對(duì)象的所有像素點(diǎn)

mask=np.zeros(imgray.shate,np.uint8)

#這里一定要使用參數(shù)-1法严,繪制填充的輪廓

cv2.drawContours(mask,[cnt],0,255,-1)

pixelpoints=np.transpose(np.nonzero(mask))

3.7.最大值和最小值及它們的位置??cv2.minMaxLoc()

可以使用掩模圖像得到這些參數(shù)

min_val,max_val,min_loc,max_loc=cv2.minMaxLoc(imgray,mask=mask)

3.8.平均顏色及平均灰度? ?cv2.mean()

同樣使用相同的掩模來求得

mean_val=cv2.mean(im,mask=mask)

3.9.極點(diǎn)

一個(gè)對(duì)象最上,最下葫笼,最左深啤,和最右的點(diǎn)

leftmost=tuple(cnt[cnt[:,:,0].argmin()[0])

rightmost=tuple(cnt[cnt[:,:,0].argmax()[0])

topmost=tuple(cnt[cnt[:,:,1].argmin()[0])

bottommost=tuple(cnt[cnt[:,:,1].argmax()[0])

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市渔欢,隨后出現(xiàn)的幾起案子墓塌,更是在濱河造成了極大的恐慌,老刑警劉巖奥额,帶你破解...
    沈念sama閱讀 222,590評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件苫幢,死亡現(xiàn)場離奇詭異,居然都是意外死亡垫挨,警方通過查閱死者的電腦和手機(jī)韩肝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來九榔,“玉大人哀峻,你說我怎么就攤上這事涡相。” “怎么了剩蟀?”我有些...
    開封第一講書人閱讀 169,301評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵催蝗,是天一觀的道長。 經(jīng)常有香客問我育特,道長丙号,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,078評(píng)論 1 300
  • 正文 為了忘掉前任缰冤,我火速辦了婚禮犬缨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘棉浸。我一直安慰自己怀薛,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評(píng)論 6 398
  • 文/花漫 我一把揭開白布迷郑。 她就那樣靜靜地躺著枝恋,像睡著了一般。 火紅的嫁衣襯著肌膚如雪三热。 梳的紋絲不亂的頭發(fā)上鼓择,一...
    開封第一講書人閱讀 52,682評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音就漾,去河邊找鬼呐能。 笑死,一個(gè)胖子當(dāng)著我的面吹牛抑堡,可吹牛的內(nèi)容都是我干的摆出。 我是一名探鬼主播,決...
    沈念sama閱讀 41,155評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼首妖,長吁一口氣:“原來是場噩夢啊……” “哼偎漫!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起有缆,我...
    開封第一講書人閱讀 40,098評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤象踊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后棚壁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體杯矩,經(jīng)...
    沈念sama閱讀 46,638評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評(píng)論 3 342
  • 正文 我和宋清朗相戀三年袖外,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了史隆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,852評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡曼验,死狀恐怖泌射,靈堂內(nèi)的尸體忽然破棺而出粘姜,到底是詐尸還是另有隱情,我是刑警寧澤熔酷,帶...
    沈念sama閱讀 36,520評(píng)論 5 351
  • 正文 年R本政府宣布孤紧,位于F島的核電站,受9級(jí)特大地震影響纯陨,放射性物質(zhì)發(fā)生泄漏坛芽。R本人自食惡果不足惜留储,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評(píng)論 3 335
  • 文/蒙蒙 一翼抠、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧获讳,春花似錦阴颖、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至帅矗,卻和暖如春偎肃,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背浑此。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評(píng)論 1 274
  • 我被黑心中介騙來泰國打工累颂, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人凛俱。 一個(gè)月前我還...
    沈念sama閱讀 49,279評(píng)論 3 379
  • 正文 我出身青樓紊馏,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蒲犬。 傳聞我的和親對(duì)象是個(gè)殘疾皇子朱监,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容