OpenCV 學習筆記03 凸包convexHull、道格拉斯-普克算法Douglas-Peucker algorithm、approxPloyDP 函數
凸形狀內部的任意兩點的連線都應該在形狀裏面。
1 道格拉斯-普克算法 Douglas-Peucker algorithm
這個算法在其他文章中講述的非常詳細,此處就詳細撰述。
下圖是引用維基百科的。ε稱之為閾值 shreshold
圖一
靜態圖如下:
具體詳細的可以參考如下兩篇文章。
相關文章如下:
道格拉斯-普克 抽稀算法 附javascript實現,該文章只看他的文字講解就好,他的代碼不是通過python實現的。
道格拉斯-普克算法(Douglas–Peucker algorithm),該文章講的也比較詳細。
Ramer-Douglas-Peucker算法,維基百科的名詞詮釋
2 實現函數 cv2.approxPloyDP
作用:對目標圖像進行(按指定精度、閾值,兩者是一個概念)進行近似多邊形曲線擬合。
使用一個較少頂點的曲線/多邊形去擬合一個頂點較多的曲線/多邊形,兩曲線/多邊形間的距離小於或等於某一指定精度/閾值
cv2.approxPolyDP(curve, epsilon, closed) -> approxCurve
參數:
curve - 2D點矢量,為圖像的 “ 輪廓 ” 值。
epsilon - 指定近似精度的參數ε,這是原始曲線與其近似值之間的最大距離。參數越小,兩直線越接近
closed - 若為true,曲線第一個點與最後一個點連接形成閉合曲線,若為false,曲線不閉合。
返回值:
approxCurve - 曲線/多邊形近似結果。
備註:
為什麽已經有了一個能夠精確表示的輪廓 2D點矢量,卻還需要得到一個近似多邊形呢?
這主要是近似得到的多邊形是由一組直線構成的,故能夠在一個區域內定義多邊形,以便後續的操作和處理,該項操作在許多計算機視覺任務中非常重要。
代碼示例:
# epsilon 為近似度參數,該值需要輪廓的周長信息 # 多邊形周長與源輪廓周長之比就是epsilon epsilon = 0.01 * cv2.arcLength(cnt,True) approx= cv2.approxPolyDP(cnt, epsilon, True) # approx 為列表list,若approx為元組,則需要將其轉換成列表list # 為了安全起見,可將[approx]作為參數傳入函數 cv2.drawContours(img, [approx], -1, (255, 255, 0), 2)
運行:
當 epsilon 的取值不同時,會存在不同的擬合程度。
3 凸包convexHull
作用:找到2D點集的凸包
cv2.convexHull(points[, clockwise[, returnPoints]]]) -> hull
參數:
points - 2D點集 2D point set
clockwise - 布爾類型,默認false;若為true,輸出的凸包則為順時針方向;若為false,輸出的凸包則為逆時針方向。註意:這裏的坐標系是x軸方向指向右側,y軸方向指向上方。
returnPoints - 布爾類型,默認true,在矩陣情況下,若為true,則返回凸包點集;若為false,則返回整數向量的索引
返回值:
hull - 輸出的凸包,是整數向量的索引(an integer vector of indices)或點集向量(vector of points)
代碼示例:
hull = cv2.convexHull(cnt)
運行:
4 代碼綜合
4.1 保留原始圖像
將上述代碼進行綜合,示例如下
import cv2 import numpy as np img = cv2.imread(‘Mjolnir.jpg‘) gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY) contours, hierarchy = cv2.findContours(binary,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) for cnt in contours: # ----源輪廓------- cv2.drawContours(img, [cnt], -1, (0, 255, 0), 2) # 近似多邊形 # epsilon 為近似度參數,該值需要輪廓的周長信息 # 多邊形周長與源輪廓周長之比就是epsilon epsilon = 0.01 * cv2.arcLength(cnt,True) approx = cv2.approxPolyDP(cnt, epsilon, True) cv2.drawContours(img, [approx], -1, (255, 255, 0), 2) # 凸包 hull = cv2.convexHull(cnt) cv2.drawContours(img, [hull], -1, (0, 0, 255), 2) cv2.imshow("approx",img) cv2.waitKey(0) cv2.destroyAllWindows()
運行
4.2 在新建幕布上繪制輪廓
當然在書(OpenCV 3 計算機視覺)第三章 3.10 凸輪廓與Douglas-Peucker算法 中,是將三個輪廓放在了黑色圖像上。
實現代碼如下:
import cv2 import numpy as np img = cv2.imread(‘Mjolnir.jpg‘) gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY) contours, hierarchy = cv2.findContours(binary,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) # 生成黑色"幕布" black = cv2.cvtColor(np.zeros((img.shape[1], img.shape[0]), dtype=np.uint8), cv2.COLOR_GRAY2BGR) for cnt in contours: # ----源輪廓------- cv2.drawContours(black, [cnt], -1, (0, 255, 0), 2) # 近似多邊形 # epsilon 為近似度參數,該值需要輪廓的周長信息 # 多邊形周長與源輪廓周長之比就是epsilon epsilon = 0.01 * cv2.arcLength(cnt,True) approx = cv2.approxPolyDP(cnt, epsilon, True) cv2.drawContours(black, [approx], -1, (255, 255, 0), 2) # 凸包 hull = cv2.convexHull(cnt) cv2.drawContours(black, [hull], -1, (0, 0, 255), 2) cv2.imshow("approx",black) cv2.waitKey(0) cv2.destroyAllWindows()
運行
參考:
OpenCV入門之尋找圖像的凸包(convex hull)關於凸包,講的不錯。
Convex Hull在Python和C ++中使用OpenCV 講解的非常詳細以及每一步的實現語言
opencv學習(四十一)之尋找凸包convexHull() 雖然實現語言不同,但是講解還挺詳細的
Convex Hull 這個粉紅色的,是不是萌妹版
代碼圖像素材:
OpenCV 學習筆記03 凸包convexHull、道格拉斯-普克算法Douglas-Peucker algorithm、approxPloyDP 函數