前兩天跟一個朋友吃飯,聊到他在作的圖像識別測量雪深,對此深感興趣,找時間就把 OpenCV 瞭解一下。python
識別標杆上紅色刻度的數量。spa
研究了一下午,話很少說,直接開始演示吧。code
import cv2 # 讀取圖片 img = cv2.imread("./snow.jpeg")
首先,將紅色部分提取,則須要將原圖進行顏色空間轉換,轉換類型使用 BGR2HSV 方法。圖片
HSV 是一種將RGB色彩模型中的點在圓柱座標系中的表示法。H 爲色相,是色彩的基本屬性,S 爲飽和度,V 爲明度。
從網上查了下,紅色區域的 H 值在 [0,10] 和 [170,180],使用 inRange 方法將紅色範圍內外的顏色區分開ip
hsv_img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) mask1 = cv2.inRange(hsv_img, np.array([0, 70, 50]), np.array([10, 255, 255])) mask2 = cv2.inRange(hsv_img, np.array([170, 70, 50]), np.array([180, 255, 255])) mask = mask1 | mask2
mask 顯示效果以下路由
此時,圖像上除了刻度外,還有些地方呈現白色,須要將這些雜質過濾掉,同時也要將垂直部分的白色去掉,須要通過先膨脹再腐蝕再膨脹三個過程。爲何要這樣呢?由於這樣才能過濾掉雜質以及垂直方向的紅線部分,以至達到效果,具體看下面的代碼和圖。get
dilated = cv2.dilate(mask, cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3)), iterations=2) # 建立一個水平的結構元素,進行腐蝕和膨脹 hline = cv2.getStructuringElement(cv2.MORPH_RECT, (int(dilated.shape[1] / 32), 1), (-1, -1)) # 腐蝕掉多餘的白色部分 temp = cv2.erode(dilated, hline) # 使白色部分膨脹 dst_img = cv2.dilate(temp, hline)
效果以下:博客
獲得提取後的部分,發現還有一個問題,左右刻度有些連結在了一塊兒,此時須要分割。分割的方式是先計算一下寬度,得出中點寬度值,在此原圖對應的中點寬度畫一條黑線(不過效率有點低啊😊it
def get_mid_width(mask): """ 獲取白色輪廓區域的中間寬度 """ min_width = mask.shape[1] max_width = 0 for line in mask: """ 處理圖片爲白色輪廓區域,計算輪廓區域寬度的中間值 """ indexes = list(filter(lambda i: line[i] != 0, range(len(line)))) if len(indexes) != 0: if min_width > indexes[0]: min_width = indexes[0] if max_width < indexes[-1]: max_width = indexes[-1] else: continue mid_width = int((min_width + max_width) / 2) return mid_width mid_width = get_mid_width(dst_img) # 在圖片上畫一條黑線,用來分割左右紅線區域,避免膨脹的時候連在一塊兒 cv2.line(img, (mid_width, 0), (mid_width, img.shape[0]), (0, 0, 0), 20)
獲得以下圖:io
而後重複上面的提取紅色部分並過濾的步驟,獲得以下圖:
此時已經完成90%了,剩下的就是獲取每一個輪廓,以及把輪廓在原圖上描繪出來
contours, _ = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 獲取輪廓 # 畫上全部輪廓 cv2.drawContours(img_source, contours, -1, (0, 0, 0), 3) imS = cv2.resize(img_source, (540, 960)) cv2.imshow('result', imS) cv2.waitKey(0) cv2.destroyAllWindows()
最終效果
是否是很簡單呢?!整理完才60行代碼,不過這只是簡單的實現,一旦涉及到有比較大的雜質或者標杆傾斜以及其餘狀況,都會影響識別率。
個人博客:時空路由器
原文地址:Python 60行代碼使用 OpenCV 識別雪深