提及來,我仍是挺慚愧的,去年四月份連續在51CTO博客發表了一波技術文章,後來由於本身太忙就慢慢忘記更新拉,前兩天一看訪問量竟然突破100+萬拉,感謝各位的厚愛與支持,更以爲51CTO博客改版以後真的是很棒!因此又來更新了!html
最近一直有人向我提問不少二值圖像分析相關的問題,特別選擇了兩個典型的輪廓分析問題。進行分析與編碼實現與演示,廢話很少說,先看第一個問題。算法
問題描述以下app
想找到工具盤中間缺乏的幾個點,統計出能夠看到的工件數目ide
仔細分析圖像發現,中間都毫無另外的有個白色很亮的圓圈,這個給了我兩個思路工具
- 能夠經過霍夫變換檢測圓來提取到
- 能夠經過二值圖像分析來提取 + 輪廓分析來提取到這些點
獲得這些輪廓點以後經過分析整個輪廓區域獲得傾斜角度,進行糾偏,而後經過X與Y投影進行分割,獲得每一個零件的中心位置座標,根據每一行的間隔設置閾值,從而實現缺乏部分部分的標出與件數統計,肯定了這樣的思路之後,我就開始了寫代碼。代碼實現是基於輪廓分析的思路,由於這個方法,用的閾值比較少,有利於算法穩定性檢測。演示各部輸出。二值化處理以後(形態學處理):
輪廓發現與校訂角度以後學習
投影分析與統計結果以下編碼
此外基於霍夫也是能夠嘗試的,霍夫的二值化效果也比較好,顯示以下:
感興趣的同窗能夠本身繼續嘗試下去。code
描述以下:視頻
如何統計下圖中的對象個數,原圖以下htm
看到這個圖像以後,我的以爲解決十分簡單,基於最外層輪廓發現便可,無需樹形結構與層次分析,集合圖像形態學分析或者距離變換就能夠獲得,最終代碼的運行結果以下:
問題1的代碼以下(已經添加各步驟註釋了):
src = cv.imread("D:/images/zsxq/zsxq_01.jpg") cv.imshow("input", src) # 二值化處理 gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY) se = cv.getStructuringElement(cv.MORPH_RECT, (3, 3)) dst = cv.morphologyEx(gray, cv.MORPH_GRADIENT, se) ret, binary = cv.threshold(dst, 0, 255, cv.THRESH_OTSU | cv.THRESH_BINARY) # 形態學處理 se = cv.getStructuringElement(cv.MORPH_ELLIPSE, (5, 5)) binary = cv.morphologyEx(binary, cv.MORPH_OPEN, se) se = cv.getStructuringElement(cv.MORPH_ELLIPSE, (10, 10)) binary = cv.morphologyEx(binary, cv.MORPH_CLOSE, se) cv.imshow("binary", binary) # 輪廓分析 contours, hireachy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE) result = np.zeros_like(binary) total = 0 for cnt in range(len(contours)): area = cv.contourArea(contours[cnt]) if area < 55: continue rrt = cv.minAreaRect(contours[cnt]) cx, cy = rrt[0] cv.circle(result, (np.int32(cx), np.int32(cy)), 5, (255), -1) total += 1 # 幾何糾偏 h, w = result.shape pts = [] for row in range(h): for col in range(w): pv = result[row, col] if pv == 255: pts.append((col, row)) pts = np.array(pts) rrt = cv.minAreaRect(pts) print(rrt) M = cv.getRotationMatrix2D(((w-1)/2.0,(h-1)/2.0),rrt[2],1) dst = cv.warpAffine(result,M,(w,h)) src = cv.warpAffine(src,M,(w,h)) # Y方向投影 tbins = y_split(dst) # X 方向投影 print("y-step", tbins) for i in range(0, len(tbins), 1): if i == 0: roi = dst[0:tbins[i], 0:w] src_roi = src[0:tbins[i], 0:w, :] x_projection(roi, src_roi) cv.imshow("roi", roi) cv.waitKey(0) if i == len(tbins)-1: roi = dst[tbins[i]:h-1, 0:w] src_roi = src[tbins[i]:h-1, 0:w, :] x_projection(roi, src_roi) cv.imshow("roi", roi) cv.waitKey(0) if 0 < i < (len(tbins)-1): roi = dst[tbins[i-1]:tbins[i] - 1, 0:w] src_roi = src[tbins[i-1]:tbins[i] - 1, 0:w,:] x_projection(roi, src_roi) cv.imshow("roi", roi) cv.waitKey(0) # 顯示結果 cv.imshow("result", result) cv.imshow("dst", dst) cv.putText(src, "numbers: " + str(total), (50, 50), cv.FONT_HERSHEY_SIMPLEX, 1.0, (0, 0, 255), 2) cv.imshow("detection", src) cv.waitKey(0) cv.destroyAllWindows()
問題二:
import cv2 as cv import numpy as np src = cv.imread("D:/images/zsxq/zsxq_02.jpg") cv.imshow("input", src) src = cv.GaussianBlur(src, (3, 3), 0) gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY) edge = cv.Canny(src, 50, 100) se = cv.getStructuringElement(cv.MORPH_ELLIPSE, (10, 10)) binary = cv.morphologyEx(edge, cv.MORPH_CLOSE, se) contours, hireachy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE) count = 0 for cnt in range(len(contours)): area = cv.contourArea(contours[cnt]) if area < 100: continue count += 1 rrt = cv.minAreaRect(contours[cnt]) # rotated rectangle box = cv.boxPoints(rrt) box = np.intp(box) cv.drawContours(src, [box], 0, (255, 0, 0), 2) cv.imshow("binary", binary) cv.imshow("result", src) cv.waitKey(0) cv.destroyAllWindows()
解鎖更多圖像處理與視頻分析技能,
歡迎學習個人最新OpenCV4圖像處理與視頻分析視頻課程
感謝你們關注個人博客,我會繼續更新!有大家有動力!