Python-Opencv实现魔方边缘识别
前言
同學(xué)要做擰魔方機(jī)器人,但是他對(duì)視覺(jué)識(shí)別方面的知識(shí)不太明白,于是我?guī)退瓿闪俗R(shí)別魔方色塊邊緣的功能,過(guò)程中學(xué)習(xí)了不少可以用于圖像處理的函數(shù)。下面我會(huì)先詳解每一個(gè)函數(shù),然后再給出整合后的代碼。
環(huán)境配置:我是在anaconda上配置的python3.8的環(huán)境,用Jupyter Notebook來(lái)編寫(xiě)運(yùn)行代碼。
函數(shù)詳解
魔方圖片:
先對(duì)目標(biāo)圖像進(jìn)行預(yù)處理:
imgobj = cv2.imread('CV_img/test2.jpg') gray = cv2.cvtColor(imgobj, cv2.COLOR_BGR2GRAY)blurred = cv2.GaussianBlur(gray, (3, 3), 0)canny = cv2.Canny(blurred, 20, 40)kernel = np.ones((3,3), np.uint8) dilated = cv2.dilate(canny, kernel, iterations=2) #閉運(yùn)算,先膨脹再腐蝕,可以填充孔洞(√) dilated=morphology.dilation(dilated,morphology.square(8)) dilated=morphology.erosion(dilated,morphology.square(8))cv2.imread先讀取測(cè)試圖片;
cv2.cvtColor(p1,p2) 是顏色空間轉(zhuǎn)換函數(shù),p1是需要轉(zhuǎn)換的圖片,p2是轉(zhuǎn)換成何種格式。cv2.COLOR_BGR2GRAY 是將BGR格式轉(zhuǎn)換成灰度圖片;
cv2.GaussianBlur是高斯濾波,是平滑濾波的一種方法,而Canny算子是邊緣檢測(cè)的一種算法,通過(guò)這兩個(gè)函數(shù)對(duì)圖像進(jìn)行濾波運(yùn)算。
dilate()函數(shù)可以對(duì)輸入圖像用特定結(jié)構(gòu)元素進(jìn)行膨脹操作,該結(jié)構(gòu)元素確定膨脹操作過(guò)程中的鄰域的形狀。先創(chuàng)造一個(gè)3*3的數(shù)組(也就是kernel),用于膨脹操作的結(jié)構(gòu)元素,使得處理后的圖片看起來(lái)更契合魔方的特征。iterations是被遞歸的次數(shù)。
dilation為膨脹,erosion為腐蝕,先膨脹再腐蝕是閉運(yùn)算,可以填充孔洞,而先腐蝕再膨脹是開(kāi)運(yùn)算,可以消除小物體小斑塊,效果由參數(shù)morphology.square(p1)中的p1決定,數(shù)值越大效果越明顯。
然后是提取輪廓:
contours, hierarchy = cv2.findContours(dilated,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)findContours函數(shù)是本程序中最核心的函數(shù),大家也可以自己去找其他的資料進(jìn)行更全面的了解。該函數(shù)的作用是檢測(cè)圖片中物體的輪廓。
先從findContours函數(shù)原型看起:
findContours( InputOutputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset=Point());各個(gè)參數(shù)解析:
image,目標(biāo)圖像,一般來(lái)說(shuō)灰度圖效果比較好。
contours是一個(gè)向量的集合,其中的每一個(gè)元素對(duì)應(yīng)著一條輪廓,每個(gè)元素保存了一組由連續(xù)的Point點(diǎn)構(gòu)成的點(diǎn)的集合,有多少輪廓,向量contours就有多少元素。你就把它當(dāng)做一個(gè)數(shù)組,數(shù)組中每一個(gè)元素就是一條輪廓,且這個(gè)元素包含了這條輪廓的所有信息。
hierarchy,也是一個(gè)向量,向量?jī)?nèi)每個(gè)元素保存了一個(gè)包含4個(gè)int整型的數(shù)組。向量hiararchy內(nèi)的元素和輪廓向量contours內(nèi)的元素是一一對(duì)應(yīng)的,向量的容量相同。hierarchy向量?jī)?nèi)每一個(gè)元素的4個(gè)int型變量——hierarchy[i][0] ~hierarchy[i][3],分別表示第i個(gè)輪廓的后一個(gè)輪廓、前一個(gè)輪廓、父輪廓、內(nèi)嵌輪廓的索引編號(hào)。
int型的mode,定義輪廓的檢索模式:
取值一:cv2.RETR_EXTERNAL只檢測(cè)最外圍輪廓,包含在外圍輪廓內(nèi)的內(nèi)圍輪廓被忽略。
取值二:cv2.RETR_LIST 檢測(cè)所有的輪廓,包括內(nèi)圍、外圍輪廓,但是檢測(cè)到的輪廓不建立等級(jí)關(guān)系,彼此之間獨(dú)立,沒(méi)有等級(jí)關(guān)系,這就意味著這個(gè)檢索模式下不存在父輪廓或內(nèi)嵌輪廓, 所以hierarchy向量?jī)?nèi)所有元素的第3、第4個(gè)分量都會(huì)被置為-1.
取值三:cv2.RETR_CCOMP 檢測(cè)所有的輪廓,但所有輪廓只建立兩個(gè)等級(jí)關(guān)系,外圍為頂層,若外圍內(nèi)的內(nèi)圍輪廓還包含了其他的輪廓信息,則內(nèi)圍內(nèi)的所有輪廓均歸屬于頂層。
取值四:cv2.RETR_TREE, 檢測(cè)所有輪廓,所有輪廓建立一個(gè)等級(jí)樹(shù)結(jié)構(gòu)。外層輪廓包含內(nèi)層輪廓,內(nèi)層輪廓還可以繼續(xù)包含內(nèi)嵌輪廓。
取值一:cv2.CHAIN_APPROX_NONE 保存物體邊界上所有連續(xù)的輪廓點(diǎn)到contours向量?jī)?nèi)。
取值二:cv2.CHAIN_APPROX_SIMPLE 僅保存輪廓的拐點(diǎn)信息,把所有輪廓拐點(diǎn)處的點(diǎn)保存入contours向量?jī)?nèi),拐點(diǎn)與拐點(diǎn)之間直線段上的信息點(diǎn)不予保留。
取值三和四:cv2.CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法。
我們這里mode取值cv2.RETR_TREE,method取值cv2.CHAIN_APPROX_SIMPLE.
然后處理contours中的數(shù)據(jù)以得到我們想要的結(jié)果。
candidates = [] for i in range(0,len(contours)):area = cv2.contourArea(contours[i])#計(jì)算面積if 40000<area<50000: #魔方色塊的面積candidates.append(contours[i]) cv2.drawContours(imgobj, candidates, -1, (0, 0, 255), 3)cv2.namedWindow("enhanced",0);cv2.resizeWindow("enhanced", 640, 640);cv2.imshow("enhanced",imgobj)cv2.waitKey(0)我的方案是通過(guò)計(jì)算每條輪廓所圍圖形的面積來(lái)確定哪些輪廓是我們所需要的。
candidates用來(lái)存放符合條件的輪廓。
面積值,我是把所有的輪廓的面積都算出來(lái)了,然后找到了相近的九個(gè)面積值來(lái)確定的。只要保持拍攝魔方的時(shí)候攝像頭外設(shè)的鏡頭與魔方距離固定應(yīng)該就可行。
append函數(shù)用于在列表末尾添加新的對(duì)象。
最終效果圖:
只要得到這些輪廓下面就好辦了,可以用過(guò)函數(shù)cv2.moments來(lái)查找到每條輪廓的中心點(diǎn),在通過(guò)中心點(diǎn)的HSV值來(lái)確定顏色,具體流程我這里就不贅述了,大家自己寫(xiě)一下。
完整代碼
我的代碼是使用攝像頭外設(shè)來(lái)實(shí)時(shí)實(shí)現(xiàn)識(shí)別魔方邊緣的。
注意改一個(gè)適當(dāng)?shù)拿娣e范圍。
總結(jié)
以上是生活随笔為你收集整理的Python-Opencv实现魔方边缘识别的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 如何做好基线配置
- 下一篇: java 获取图片像素_转:java提取