1. 程式人生 > >OpenCV 學習筆記03 凸包convexHull、道格拉斯-普克算法Douglas-Peucker algorithm、approxPloyDP 函數

OpenCV 學習筆記03 凸包convexHull、道格拉斯-普克算法Douglas-Peucker algorithm、approxPloyDP 函數

strong header 布爾類型 com learn spa https 講解 分享

凸形狀內部的任意兩點的連線都應該在形狀裏面。

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 函數