前面學習了opencv中圖像的一些處理,但對于opencv我們更多的還是對圖像做出一些判斷和識別,所以下面開始學習圖像的識別。
原圖:
一 圖像輪廓的識別
import cv2
pen=cv2.imread('pen.png',0)
ret,new_pen=cv2.threshold(pen,120,255,cv2.THRESH_BINARY)
cv2.imshow('pen',new_pen)
contours, hierarchy = cv2.findContours(new_pen,cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
print(hierarchy)
print(contours)
print(len(contours))
pen1=pen.copy()
Contours = cv2.cvtColor(pen1, cv2.COLOR_GRAY2BGR)
cv2.drawContours(Contours,contours,-1,(0,255,0),2)
cv2.imshow('pen1',Contours)
cv2.waitKey(0)
1 圖像二值處理
ret,new_pen=cv2.threshold(pen,120,255,cv2.THRESH_BINARY)
我們這里識別圖像的時候,轉化為了灰度圖,目的是為了后面做灰度處理,在識別輪廓之前我們要讓我們的圖像更加鮮明,所以我們做了一下二值處理
2 尋找輪廓
contours, hierarchy = cv2.findContours(new_pen,cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
這里會返回兩個參數,這里contours就是我們的輪廓。hierarchy這個表示層級之間的一種嵌套方式,不是特別重要。
我們這里查看下contours
這個是一個一個的坐標,我們要知道輪廓就是一個一個點組成的。然后我們可以通過drawContours來繪制。
3 繪制
注意到我們繪制之前我們還進行了一次的轉換,把我們的圖像轉化為了RGB圖像(我們前面轉換成了單維度的圖像),不然的話,我們使用灰度圖的線條繪制的不明顯。
Contours = cv2.cvtColor(pen1, cv2.COLOR_GRAY2BGR)
cv2.drawContours(Contours,contours,-1,(0,255,0),2)
這個里面有5個參數,第一個參數是表示我們要繪制到的目標圖像,第二個參數是我們繪制的輪廓信息,第三個表示我們要繪制的索引(-1表示繪制全部的輪廓),第四個表示我要繪制的輪廓顏色,第五個表示要繪制的粗度。
二 根據面積進行輪廓選擇
import cv2
pen1=cv2.imread('pen.png',0)
ret,pen=cv2.threshold(pen1,120,255,cv2.THRESH_BINARY)
cv2.imshow('pen',pen)
contours, hierarchy = cv2.findContours(pen,cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)pen1=pen.copy()
aa = cv2.cvtColor(pen1, cv2.COLOR_GRAY2BGR)
cv2.drawContours(aa,contours,-1,(0,255,0),2)
are=cv2.contourArea(contours[0])
print(are)
ls=[]
for i in contours:if cv2.contourArea(i) >10000:ls.append(i)
print(ls)
cv2.drawContours(aa,ls,-1,(0,0,255),2)
cv2.imshow('pen1',aa)
cv2.waitKey(0)
key=cv2.contourArea, reverse=True)[0]
cv2.drawContours(aa,[sorted_contours],contourIdx=-1,color=(0,0,255),thickness=3)
cv2.imshow('pen2',aa)
cv2.waitKey(0)
1 查看輪廓面積
cv2.contourArea(contours[0])
我們可以使用這個函數來查看一個輪廓的面積
2 利用面積篩選輪廓
我們對所有輪廓進行遍歷,找出面積大于10000的面積,然后添加到ls中,再畫出來,就找到了符合我們條件的輪廓。
ls=[]
for i in contours:if cv2.contourArea(i) >10000:ls.append(i)
print(ls)
cv2.drawContours(aa,ls,-1,(0,0,255),2)
# cv2.imshow('contours',contours)
cv2.imshow('pen1',aa)
cv2.waitKey(0)
3 先對輪廓面積進行排序
我們使用sorted對所有輪廓面積進行排序,然后打印出最大的那一個。注意我們繪制的時候也要對sorted_contours加上一個中括號,不然畫出來的圖像是斷斷續續的。
sorted_contours = sorted(contours, key=cv2.contourArea, reverse=True)[0]
cv2.drawContours(aa,[sorted_contours],contourIdx=-1,color=(0,0,255),thickness=3)
cv2.imshow('pen2',aa)
cv2.waitKey(0)
三 畫出輪廓的外界圓和外接矩形
1 外接圓
import cv2
pen1=cv2.imread('pen.png',0)
ret,pen=cv2.threshold(pen1,120,255,cv2.THRESH_BINARY)
cv2.imshow('pen',pen)
contours, hierarchy = cv2.findContours(pen,cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
pen1=pen.copy()
aa = cv2.cvtColor(pen1, cv2.COLOR_GRAY2BGR)
cv2.drawContours(aa,contours,-1,(0,255,0),2)
cnt=contours[7]
[x,y],r=cv2.minEnclosingCircle(cnt)
ab=cv2.circle(aa,(int(x),int(y)),int(r),(255,0,0),2)
cv2.imshow('pen3',ab)
cv2.waitKey(0)
這里選取了第七個輪廓也就是那個鉛筆,然后使用cv2.minEnclosingCircle(cnt)來獲取這個輪廓的外界圓的外界圓,會返回兩個值,一個是坐標的圓心,一個是半徑,然后就可以通過cv2.circle專門的畫圓工具來繪制了。
cnt=contours[7]
[x,y],r=cv2.minEnclosingCircle(cnt)
ab=cv2.circle(aa,(int(x),int(y)),int(r),(255,0,0),2)
cv2.imshow('pen3',ab)
cv2.waitKey(0)
2 外接矩形
import cv2
pen1=cv2.imread('pen.png',0)
ret,pen=cv2.threshold(pen1,120,255,cv2.THRESH_BINARY)
cv2.imshow('pen',pen)
contours, hierarchy = cv2.findContours(pen,cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
pen1=pen.copy()
aa = cv2.cvtColor(pen1, cv2.COLOR_GRAY2BGR)
cv2.drawContours(aa,contours,-1,(0,255,0),2)
cnt=contours[7]
x,y,w,h=cv2.boundingRect(cnt)
ac=cv2.rectangle(aa,(x,y),(x+w,y+h),(0,0,255),2)
cv2.imshow('pen4',ac)
cv2.waitKey(0)
還是和上面的那個一樣,選取鉛筆的筆桿輪廓,然后使用boundingRect獲取我們要畫的坐標起點了,寬和高,然后就可以畫出來了。
四 繪制近似輪廓
import cv2
pen1=cv2.imread('pen.png',0)
ret,pen=cv2.threshold(pen1,120,255,cv2.THRESH_BINARY)
cv2.imshow('pen',pen)
contours = cv2.findContours(pen,cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)[-2]
# cv2.imshow('contours',contours)
# cv2.waitKey(0)
es=0.01*cv2.arcLength(contours[0],True)
approx=cv2.approxPolyDP(contours[0],0.01*cv2.arcLength(contours[0],True),True)
phone_new=pen1.copy()
aa = cv2.cvtColor(phone_new, cv2.COLOR_GRAY2BGR)
image_contours=cv2.drawContours(aa,[approx],-1,(0,255,0),2)
cv2.imshow('phone_new',image_contours)
cv2.waitKey(0)
先給結果圖
我們可以看到,結果圖中我們的手機的角角的地方,本來彎的變成了菱形,是因為這里采用了
es=0.01*cv2.arcLength(contours[0],True)
approx=cv2.approxPolyDP(contours[0],0.01*cv2.arcLength(contours[0],True),True)
這個es表示一個距離,就是這個地方的d如果大于我們設置的,就會直接用這個直線來取代。