一種基于opencv的分辨圓形,三角形,矩形的思路
上篇文章給大家講了基于openmv的思路,這篇文章大致講講如何用opencv來做,
我事先查了一下,我這個方法不知道有多少人早就用過了,(可能是因為當時我也是瘋狂查出來的,已經記憶模糊了)他們講的比我詳細多了,我就簡單說說思路,
我的思路是:色塊識別+輪廓提取+角點檢測
1. 色塊識別:
色塊識別是很基礎的一個操作了,也比較簡單,直接看代碼:
lower_red_1 = np.array([0, 80, 128]) #先找出HSV色彩空間紅綠藍三種顏色的大致范圍,紅色有兩個是因為hsv空間中,色相h最上面和最下面都是紅色,可以看下面這張圖你就懂了,
upper_red_1 = np.array([6, 255, 255])
lower_red_2 = np.array([170, 110, 128])
upper_red_2 = np.array([180, 255, 255])
lower_green = np.array([35, 80, 80])
upper_green = np.array([77, 255, 255])
lower_blue = np.array([90, 110, 110])
upper_blue = np.array([124, 255, 255])
hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV) #frame就是輸入的影像
red_mask_1 = cv.inRange(hsv,lower_red_1,upper_red_1) #將影像二值化,在lower和upper之間的顏色變為白色,其他全為黑色
red_mask_2 = cv.inRange(hsv,lower_red_2,upper_red_2)
red_mask = cv.bitwise_or(red_mask_1, red_mask_2) #兩種紅色統一
green_mask = cv.inRange(hsv, lower_green, upper_green)
blue_mask = cv.inRange(hsv, lower_blue, upper_blue)

上面這一段不懂的話可以看看這篇文章,這位博主講得很好(侵刪)
red_res = cv.bitwise_or(frame, frame, mask = red_mask) #或運算,將彩色影像中紅色部分選中,忽略其余顏色
green_res = cv.bitwise_and(frame, frame, mask = green_mask)
blue_res = cv.bitwise_and(frame, frame, mask = blue_mask)
red_gray = cv.cvtColor(red_res, cv.COLOR_BGR2GRAY) #轉灰度圖
green_gray = cv.cvtColor(green_res, cv.COLOR_BGR2GRAY)
blue_gray = cv.cvtColor(blue_res, cv.COLOR_BGR2GRAY)
final_gray = cv.bitwise_or(red_res, green_res) #將選出的紅色,藍色,綠色都集成起來
final_gray = cv.bitwise_or(final_gray, blue_res)
final_gray = cv.cvtColor(final_gray,cv.COLOR_BGR2GRAY) #得到最終的灰度圖,就是下一步輪廓提取的輸入
2. 輪廓提取
輪廓提取的話,opencv有自己的API,好用的很,
__, contours,hierarchy = cv.findContours(final_gray, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
#這個地方要注意一下,這個函式根據版本不同,回傳的值可能有兩個或者三個,如果opencv版本比較新,就只有后面兩個回傳值,如果比較舊(我代碼是在樹莓派上跑的,所以比較舊),就有三個回傳值,不過我們只用到countours這個回傳值就行,
for cnt in range(len(contours)): #對檢測到的每個輪廓遍歷
p = cv.arcLength(contours[cnt],True) #p是Perimeter周長的意思,當時偷懶了
area = cv.contourArea(contours[cnt]) #area是該輪廓的像素面積
3. 角點檢測
原理我也沒啥好說的,畢竟這也不是計算機視覺原理專欄,呼叫api就完事了,
for cnt in range(len(contours)):
p = cv.arcLength(contours[cnt],True)
area = cv.contourArea(contours[cnt])
if area > 2500:
mm = cv.moments(contours[cnt]) #計算影像輪廓中的中心矩,原理見代碼后鏈接
if mm['m00'] != 0: #如果算出了中心距(感覺這里應該用try,except,當時寫的不嚴謹)
cx = int(mm['m10'] / mm['m00']) #歸一化計算得出輪廓中心的橫縱坐標
cy = int(mm['m01'] / mm['m00'])
else:
continue
epsilon = 0.04 * cv.arcLength(contours[cnt], True) #多邊形擬合的距離引數,下一個函式要用到,原理見代碼后鏈接
approx = cv.approxPolyDP(contours[cnt], epsilon, True) #輪廓近似,將圓潤曲線折線化,以此得到該影像的角點坐標,
corners = len(approx) #得到角點數量
if corners == 3: #三個角點的就是三角形
shapes['triangle'] = shapes['triangle'] + 1
shapeLenth = p/3 #得到三角形邊長
elif corners == 4: #四個角點就是矩形
shapes['rectangle'] = shapes['rectangle'] + 1
shapeLenth = p/4 #得到正方形邊長
else: #圓有好多角點
shapes['circles'] = shapes['circles'] + 1
pi = 3.1415926
rad = p/(2*pi) #得到圓周長
解釋中心距(侵刪)概率論的知識了
解釋多邊形擬合(侵刪)
解釋角點檢測原理(侵刪)這兩篇文章都講的很清楚,一看就明白了,知道原理 然后拿來用就行,
??
??效果圖不小心被刪了,也懶得再去找樹莓派重跑了,有需要的可以自己拿去跑了試試,根據角點檢測的原理,五邊形,六邊形,七邊形等多邊形都可以識別出來,但是可能會和圓搞混,調一調epsilon 這個引數就行,
??
????????有問題可以評論區交流
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/188399.html
標籤:其他
上一篇:【大學篇】大學的意義
