Python OpenCV 实现魔方识别+复原
簡介
本項(xiàng)目運(yùn)用了基礎(chǔ)的 Opencv 圖像處理算法 來實(shí)現(xiàn)魔方色塊的識(shí)別并判斷顏色。 用戶可以通過將魔方舉在攝像機(jī)的前方來讓機(jī)器自動(dòng)將魔方的色塊錄入數(shù)據(jù),然后系統(tǒng)將會(huì)依靠用戶錄入的數(shù)據(jù)來產(chǎn)生當(dāng)前魔方的解法,并以動(dòng)畫的形式展現(xiàn)出來。
圖形用戶界面展示:
如何使用
使用到的庫:
在 Anaconda 環(huán)境下安裝庫:
conda install -c anaconda tk conda install -c conda-forge numpy conda install -c conda-forge opencv配置完環(huán)境后:
在已具備所有需要的庫之后,到 Rubik-s-Cube-Scanner-Solver 將該repo下的 RubiksCubeScanner 路徑克隆到電腦中,然后使用python3 運(yùn)行 client_gui.py 即可。
當(dāng)該代碼第一次運(yùn)行時(shí),系統(tǒng)需要?jiǎng)?chuàng)建解魔方需要使用到的表格,一般需要花半個(gè)小時(shí)到一個(gè)小時(shí),請(qǐng)耐心等待,并且會(huì)占用額外的80MB左右的硬盤空間。此后執(zhí)行則不需要?jiǎng)?chuàng)建列表,圖形化用戶界面會(huì)直接顯示。
當(dāng)用戶界面顯示,用戶可以直接用客戶端里的色盤來給魔方上色,也可以點(diǎn)擊 “Turn on cam" 來打開攝像頭,讓攝像頭來自動(dòng)識(shí)別+讀入當(dāng)前魔方的內(nèi)容。
在整個(gè)魔方已經(jīng)被填充后,點(diǎn)擊 ”Solve“ 系統(tǒng)將會(huì)連接到之前已經(jīng)創(chuàng)建的列表并開始解輸入的魔方。輸出的解法的步驟數(shù)會(huì)在20步以內(nèi)。
在魔方已經(jīng)被解完后,點(diǎn)擊 ”Animate“ 即可讓魔方“動(dòng)起來”,作者提前制作的魔方動(dòng)畫將會(huì)開始播放解法。左下角可拖動(dòng)的塊可以用來調(diào)節(jié)動(dòng)畫播放的速度。
實(shí)現(xiàn)步驟
本項(xiàng)目可以大致地分為三個(gè)步驟 :
1. 檢測(cè)并錄入魔方的內(nèi)容
2. 生成已錄入魔方的解法
3. 創(chuàng)建可以展示給用戶的魔方動(dòng)畫
接下來的文章將會(huì)對(duì)每一個(gè)步驟,尤其是第一個(gè)步驟進(jìn)行詳細(xì)的分解。
1. 檢測(cè)并錄入魔方的內(nèi)容
識(shí)別魔方色塊
為了減少不必要的運(yùn)算,在窗體程序的攝像機(jī)讀取的視屏中間畫有一個(gè)正方形,所有算法在該正方形中運(yùn)行。使用 ROI(Region of Interest) 提升運(yùn)算效率是非常實(shí)用的算法優(yōu)化。
一張普通的彩色圖片在每個(gè)像素含有一個(gè) (0-255,0-255,0-255) 的數(shù)組, 也就是說在一個(gè)像素可以有 256x256x256 = 1703936 種不同的顏色變換。然而一張二值化后的圖在每個(gè)像素僅僅包含 0 或者 1 兩種可能。一張彩色圖片所包含的信息遠(yuǎn)遠(yuǎn)大于它的二值化后的圖片,二值圖所包含的主要信息僅僅是圖片中物體的輪廓。我們識(shí)別魔方色塊只需要物體的輪廓信息,所以我們的第一個(gè)步驟是將讀取到的圖像二值化。
在Python OpenCV 中, 二值化圖片的代碼為:
// 首先將彩色圖片處理成灰度圖 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)// img(gray): 待處理的圖片 // threshold1(130): 將低于該值的像素歸為 0 // threshold2(230): 將高于該值的像素歸為 0 // option: 二值化選項(xiàng) // thresh1: 返回的二值化后的圖片 ret,thresh1 = cv2.threshold(gray,130,230,cv2.THRESH_BINARY)在圖片已經(jīng)被二值化后,我們還需要進(jìn)行一些圖像處理讓我們獲得的數(shù)據(jù)更加可靠:
// kenel 是一個(gè)算子,它可以是我們自定義的形狀,Opencv 將以它的形狀進(jìn)行填充以及腐蝕 // dilate 是opencv的膨脹算法,將它運(yùn)用在有時(shí)模糊的數(shù)據(jù)中可以讓該數(shù)據(jù)更加穩(wěn)定 kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(2,2)) binary_dilated = cv2.dilate(binary_Image,kernel,iterations = 5)下面的圖片: 左邊為膨脹前,右邊為膨脹后
將我們的圖片膨脹完后,即可開始提取輪廓線,在opencv中算法:
接下來可以在contours 矩陣中尋找為四邊形的輪廓線,為此opencv提供了算法:
for cnt in contours: approx = cv2.approxPolyDP(cnt,0.12*cv2.arcLength(cnt,True),True)x = approx.ravel()[0]y = approx.ravel()[1]if (len(approx) == 4 and 245<x<395 and 105<y<255):這個(gè)循環(huán)會(huì)把contours中的每一個(gè)輪廓線都過一遍,如果該輪廓線不能被估作一個(gè)四邊形,則舍棄;如果可以,則進(jìn)入下一步繼續(xù)判斷該四邊形是否為正方形:
if approx_is_square(approx) == Trueapprox_is_square(approx) 是作者自己寫的函數(shù),它非常簡單。通過比對(duì)這個(gè)四邊形四個(gè)邊的長度是否在其中任意一邊的90%~110%之間,再通過比對(duì)這四個(gè)邊之間的角度是否都在80度到100度;這個(gè)算法可以粗略地判斷輸入的形狀是否是正方形。
在識(shí)別完正方形后,我們即可數(shù)當(dāng)前圖片ROI 中的正方形的數(shù)量,如果等于9,就將他們標(biāo)識(shí)出來,最基礎(chǔ)的色塊識(shí)別已經(jīng)完成!
識(shí)別某個(gè)色塊的顏色
對(duì)于我們而言,一個(gè)色塊可以是“綠“,”紅”,“藍(lán)”,“白“ 等等。 然而對(duì)于一個(gè)機(jī)器而言一個(gè)色塊的顏色僅僅是一個(gè)RGB值。我們?yōu)榱酥酪粋€(gè)色塊歸屬于魔方的哪一面則需要知道當(dāng)前色塊的區(qū)域的rgb值代表什么顏色。
第一步是遍歷該色塊,把所有屬于本色塊的像素的顏色全部加起來,然后除以加起來的像素的數(shù)量,這樣獲得一個(gè)當(dāng)前色塊的平均顏色。
接下來我們可以提前設(shè)立很多閥值來判斷一個(gè)色塊的平均顏色到底屬于什么顏色:
red_low = [30,30,100] #bgr 格式下紅色的最低值 red_high = [150,150,255] #bgr 格式下紅色的最高值如果: red_low < 平均顏色 < red_high 則: 該顏色是紅色好了,這樣我們就完成了顏色的判斷!我們已經(jīng)可以把顏色填入GUI中的矩陣中了!
總結(jié)
以上是生活随笔為你收集整理的Python OpenCV 实现魔方识别+复原的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 机器人三大定律的发展和演进概述
- 下一篇: java--两个巨大素数(质数)的乘积