[Python]OpenCV 輪廓逼近技術教學:使用 cv2.arcLength 與 cv2.approxPolyDP

更新於 發佈於 閱讀時間約 11 分鐘

在電腦視覺應用中,輪廓(Contour)常用來描述物體的邊界。

當圖像中有雜訊或物體邊緣過於複雜時,我們可以利用輪廓逼近技術,將輪廓簡化成較少點數的多邊形,這不僅有助於後續的形狀分析,也能提高處理速度。

本文將介紹如何使用 OpenCV 中的 cv2.arcLengthcv2.approxPolyDP 來進行輪廓逼近,並展示一些實際應用。


1. 理解輪廓與輪廓逼近

輪廓 (Contour):

  • 定義:輪廓是一系列連續點,通常用來表示二值圖像中物體的邊界。
  • 取得方式:透過 OpenCV 的 cv2.findContours 可以提取圖像中的輪廓。

輪廓逼近 (Contour Approximation):

  • 目的:簡化輪廓,去除不必要的細節,只保留代表形狀的關鍵點。
  • 優點
    • 降低計算量。
    • 有助於識別基本幾何形狀(如三角形、矩形、多邊形等)。
    • 減少雜訊影響,提高辨識精準度。

2. 計算輪廓周長:cv2.arcLength

在進行輪廓逼近前,我們先需要計算原始輪廓的周長,這可以透過 cv2.arcLength 完成。

peri = cv2.arcLength(cnt, True)
  • 參數說明
    • cnt:輸入的輪廓(通常是 cv2.findContours 返回的其中一個輪廓)。
    • True:表示輪廓是封閉的(即輪廓的起點與終點相連)。

3. 進行輪廓逼近:cv2.approxPolyDP

獲得周長後,便可以使用 cv2.approxPolyDP 進行輪廓逼近。

epsilon = epsilon_factor * peri
approx = cv2.approxPolyDP(cnt, epsilon, True)
  • 參數說明
    • cnt:原始輪廓。
    • epsilon:逼近精度,通常設為周長的某個比例。這個值越小,逼近結果越接近原始輪廓;值越大,簡化效果越明顯。
    • True:表示逼近後的輪廓依然是封閉的多邊形。
  • 工作原理
    • 該函數基於 Douglas-Peucker 演算法,透過遞歸方式去除那些對輪廓形狀影響較小的點,保留最能描述形狀的頂點。

4. 應用範例:形狀辨識

實際案例

假設我們要對圖像中的幾何形狀進行識別,透過輪廓逼近可以幫助我們判斷該形狀的頂點數量:

  • 3 個頂點:可能為三角形。
  • 4 個頂點:可能為矩形或正方形。
  • 多於 4 個頂點:可能為圓形或其他多邊形。

範例圖片

利用小畫家隨便畫幾個圖形來測試

raw-image

結果圖

奇怪為什麼星星怎判斷成圓形呢?,原因是因為程式碼當中,我們設定超過四個頂點就判成圓形,如果需要判斷成星星,需要先知道星星圖形頂點有幾個,在重新修改判斷邏輯

raw-image


範例程式碼

以下是一個完整範例,展示如何從圖像中提取輪廓、進行逼近,並根據逼近後的頂點數來辨識形狀:

import cv2
import numpy as np

# 讀取圖像並轉為灰階
image = cv2.imread('shapes.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 二值化處理:可以使用閾值或Canny邊緣檢測
_, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 或者使用 Canny: thresh = cv2.Canny(gray, 50, 150)

# 找到輪廓
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

for cnt in contours:
# 計算周長
peri = cv2.arcLength(cnt, True)

# 設定逼近精度,epsilon_factor 可根據實際需求調整
epsilon_factor = 0.02
epsilon = epsilon_factor * peri

# 輪廓逼近
approx = cv2.approxPolyDP(cnt, epsilon, True)

# 根據頂點數量判斷形狀
vertices = len(approx)
shape = "unidentified"
if vertices == 3:
shape = "Triangle"
elif vertices == 4:
# 進一步可以計算寬高比來區分正方形與矩形
shape = "Rectangle"
elif vertices > 4:
shape = "Circle" # 也可以進一步判斷圓形的程度

# 畫出逼近後的輪廓與形狀名稱
cv2.drawContours(image, [approx], -1, (0, 255, 0), 2)
# 計算中心點來顯示文字
M = cv2.moments(cnt)
if M["m00"] != 0:
cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])
else:
cX, cY = 0, 0
cv2.putText(image, shape, (cX - 20, cY), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2)

# 顯示結果
cv2.imshow("Shapes", image)
cv2.waitKey(0)
cv2.destroyAllWindows()

程式說明:

  1. 讀取與預處理:將圖像讀入並轉為灰階,再進行二值化處理,以便提取明顯輪廓。
  2. 輪廓提取:利用 cv2.findContours 找出所有外部輪廓。
  3. 輪廓逼近:對每個輪廓計算周長,並根據周長與設定的比例因子計算逼近精度,再透過 cv2.approxPolyDP 簡化輪廓。
  4. 形狀辨識:根據逼近後的頂點數量來判斷形狀,並在圖像上標示出來。

修正可判斷星星

修改部分程式碼 先只印出頂點數量,由結果圖得知星星頂點為10

    # 根據頂點數量判斷形狀
vertices = len(approx)

# 畫出逼近後的輪廓與形狀名稱
cv2.drawContours(image, [approx], -1, (0, 255, 0), 2)
# 計算中心點來顯示文字
M = cv2.moments(cnt)
if M["m00"] != 0:
cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])
else:
cX, cY = 0, 0
cv2.putText(image, str(vertices), (cX + 200, cY-200), cv2.FONT_HERSHEY_SIMPLEX,4, (255, 0, 0), 2)

顯示頂點結果圖

raw-image


修正邏輯

得知星星數量後,修正判斷邏輯

    # 根據頂點數量判斷形狀
vertices = len(approx)
shape = "unidentified"
if vertices == 3:
shape = "Triangle"
elif vertices == 4:
# 進一步可以計算寬高比來區分正方形與矩形
shape = "Rectangle"
elif vertices == 10:
shape = "Star" # 也可以進一步判斷圓形的程度
elif vertices > 4:
shape = "Circle" # 也可以進一步判斷圓形的程度

# 畫出逼近後的輪廓與形狀名稱
cv2.drawContours(image, [approx], -1, (0, 255, 0), 2)
# 計算中心點來顯示文字
M = cv2.moments(cnt)
if M["m00"] != 0:
cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])
else:
cX, cY = 0, 0
cv2.putText(image, shape, (cX + 200, cY-200), cv2.FONT_HERSHEY_SIMPLEX, 2, (255, 0, 0), 2)
raw-image

5. 應用場景

輪廓逼近技術不僅用於基本的形狀辨識,還有許多實際應用:

  • 物體偵測:在工業自動化中辨識和計數物體。
  • 文件分析:檢測文件邊界、校正傾斜的文件圖像。
  • 標誌辨識:例如交通標誌的識別,通過辨識輪廓形狀來進行分類。
  • 手勢識別:在手勢控制中,辨識手的輪廓和關鍵點。

6. 小結

本文介紹了如何使用 OpenCV 的 cv2.arcLengthcv2.approxPolyDP 進行輪廓逼近,並以實際程式範例說明了如何從圖像中提取輪廓、簡化輪廓及識別形狀。透過這項技術,不僅能夠減少雜訊影響,還可以提高形狀辨識的效率和精度。無論是在工業檢測、文件處理還是手勢識別等領域,輪廓逼近都是一個非常實用的工具。

avatar-img
134會員
222內容數
本業是影像辨識軟體開發,閒暇時間進修AI相關內容,將學習到的內容寫成文章分享。
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
螃蟹_crab的沙龍 的其他內容
中值濾波器(Adaptive Median Filter)是一種針對噪聲去除的圖像處理技術,主要應用於處理含有椒鹽雜訊的圖像,但在椒鹽雜訊過大時就會面臨,若為了處理掉雜訊,使用的處理窗口(kernel)就要大一點,會造成圖像的邊緣模糊掉。 後面為解決這個問題,就發展了自適應中值濾波器,其概念源自於
在影像處理中,形態學操作是非常重要的一種技術,能夠幫助我們去除噪點、強化特徵、修復物體的形狀等。形態學操作的核心是「結構元素」(kernel),不同形狀的結構元素會產生不同的處理效果。本文將介紹如何使用不同形狀的結構元素來進行圖像處理,並結合實際程式範例和測試圖片來說明其效果。
cv2.fastNlMeansDenoising() 是 OpenCV 中一個非常有效的去噪函數,基於非局部均值濾波算法(Non-Local Means Filtering)。它能夠有效地去除圖像中的隨機噪聲(如高斯噪聲),並保留圖像的細節,特別適合處理含有隨機噪聲的圖像,如拍攝時產生的感光元件噪聲
當影像中有雜訊時,使用直方圖均衡化來增強對比就會受雜訊的影響,從而影響到整體的結果。應對這個問題,可以考慮使用自適應直方圖均衡化來減少雜訊的影響,並增強對比度。 本文將比較直方圖均衡化與自適應直方圖均衡化的差異性。 [OpenCV基礎][Python]影像增強_直方圖均衡處理 直方圖均衡化的
在 OpenCV 中,將圖片從 BGR 色彩空間轉換為灰階圖像時常用cv2.COLOR_BGR2GRAY ,此函數使用了特定的權重來計算灰階值。這些權重是基於人眼對不同顏色的敏感度進行調整的。 Gray=0.299×R+0.587×G+0.114×B 本文介紹了用其他方式來提取色彩通道
cv2.countNonZero 是 OpenCV 中的一個函數,用來計算二值圖像(或單通道圖像)中非零像素的數量。這個函數對於圖像處理中的許多操作非常有用,例如計算某個區域內的白色像素數量,從而幫助我們了解圖像的內容或進行進一步的分析。 使用範例 假設您有一個二值圖像,其中白色像素
中值濾波器(Adaptive Median Filter)是一種針對噪聲去除的圖像處理技術,主要應用於處理含有椒鹽雜訊的圖像,但在椒鹽雜訊過大時就會面臨,若為了處理掉雜訊,使用的處理窗口(kernel)就要大一點,會造成圖像的邊緣模糊掉。 後面為解決這個問題,就發展了自適應中值濾波器,其概念源自於
在影像處理中,形態學操作是非常重要的一種技術,能夠幫助我們去除噪點、強化特徵、修復物體的形狀等。形態學操作的核心是「結構元素」(kernel),不同形狀的結構元素會產生不同的處理效果。本文將介紹如何使用不同形狀的結構元素來進行圖像處理,並結合實際程式範例和測試圖片來說明其效果。
cv2.fastNlMeansDenoising() 是 OpenCV 中一個非常有效的去噪函數,基於非局部均值濾波算法(Non-Local Means Filtering)。它能夠有效地去除圖像中的隨機噪聲(如高斯噪聲),並保留圖像的細節,特別適合處理含有隨機噪聲的圖像,如拍攝時產生的感光元件噪聲
當影像中有雜訊時,使用直方圖均衡化來增強對比就會受雜訊的影響,從而影響到整體的結果。應對這個問題,可以考慮使用自適應直方圖均衡化來減少雜訊的影響,並增強對比度。 本文將比較直方圖均衡化與自適應直方圖均衡化的差異性。 [OpenCV基礎][Python]影像增強_直方圖均衡處理 直方圖均衡化的
在 OpenCV 中,將圖片從 BGR 色彩空間轉換為灰階圖像時常用cv2.COLOR_BGR2GRAY ,此函數使用了特定的權重來計算灰階值。這些權重是基於人眼對不同顏色的敏感度進行調整的。 Gray=0.299×R+0.587×G+0.114×B 本文介紹了用其他方式來提取色彩通道
cv2.countNonZero 是 OpenCV 中的一個函數,用來計算二值圖像(或單通道圖像)中非零像素的數量。這個函數對於圖像處理中的許多操作非常有用,例如計算某個區域內的白色像素數量,從而幫助我們了解圖像的內容或進行進一步的分析。 使用範例 假設您有一個二值圖像,其中白色像素
你可能也想看
Google News 追蹤
提問的內容越是清晰,強者、聰明人越能在短時間內做判斷、給出精準的建議,他們會對你產生「好印象」,認定你是「積極」的人,有機會、好人脈會不自覺地想引薦給你
Thumbnail
用小畫家隨意畫三個圈分別用紅藍綠,我們利用cv2.inRange與搭配cv2.bitwise_and,將紅球過濾出來吧。 程式範例 因為OpenCV中cv2.imread讀取圖檔預設讀取是為[B,G,R]的格式,所以設置紅色範圍要注意設定在R的範圍內。
Thumbnail
介紹OpenCV中的cv2.matchTemplate和cv2.minMaxLoc函數的使用方法和參數,提供程式範例以及相關特徵匹配的詳細介紹,讓讀者對此有更深入的瞭解。
Thumbnail
[OpenCV應用][Python]找出圖像中的四個方位的邊緣點求出寬高 呈上篇應用Numpy找到的座標點,那我們如何捨棄掉差異過大的座標點呢? 可能圖像物件邊緣不佳,採樣就會差異過大,造成計算出的寬高是不準確的。 遇到這種狀況,就可以使用下方的程式範例來篩選座標點。 為求方便,此範例跟圖
Thumbnail
觀看本文將可以學習到如何利用Numpy求得物件的邊緣點,及算出物件的寬跟高。 有詳細的程式邏輯說明,及各函式用法說明。 綠點及紅點則是採樣到的邊界點,比較粗的點是偵測到的最大值 完整程式碼 import cv2 import numpy as np import matplotl
Thumbnail
瞭解二值化影像的應用和程式語法,包括物體檢測和分割、邊緣檢測、圖像分析和測量、文檔辨識,以及使用cv2.threshold的參數和程式範例。
Thumbnail
在影像處理中,我們總是想要讓特徵更加明顯一點,可以使用銳利化的方式將特徵的邊緣增強,提升影像的細節,圖像銳利後就會有提升解析度的感覺。 拉普拉斯運算子是一種常用於影像增強的方法之一,特別是用於提高影像的邊緣和細節。 在OpenCV中,你可以使用cv2.Laplacian函數來應用拉普拉斯運算子。
Thumbnail
直方圖是對圖像中像素強度分布的圖形表示。通過分析直方圖,我們可以獲得有關圖像對比度、亮度和色彩分佈的有用信息。
Thumbnail
大部分在求物件的寬度及高度,都會想到用OpenCV的findContours函式來做,從找到的輪廓中來計算物件的面積,周長,邊界框等屬性,從而得到物體的寬度與高度 [OpenCV應用][Python]利用findContours找出物件邊界框求出寬度及高度 本文將用不同的方法,利用Numpy
Thumbnail
本文將利用OpenCV的findContours函式,從找到的輪廓中來計算物件的面積,周長,邊界框等屬性,從而得到物體的寬度與高度。 一般來說,我們在進行輪廓檢測時,會先進行圖像二值化,將對象轉換為白色,背景為黑色。這樣,在找到輪廓後,輪廓的點就會以白色表示,背景為黑色。 結果圖 從圖中綠色框
Thumbnail
[影像處理_OpenCV Python]使用Python撰寫影像處理功能,圖片遮罩或濾除掉不要的地方,旋轉圖片 以下範例將呈現影像處理三種不同的應用: 遮罩的實現 濾除 旋轉
提問的內容越是清晰,強者、聰明人越能在短時間內做判斷、給出精準的建議,他們會對你產生「好印象」,認定你是「積極」的人,有機會、好人脈會不自覺地想引薦給你
Thumbnail
用小畫家隨意畫三個圈分別用紅藍綠,我們利用cv2.inRange與搭配cv2.bitwise_and,將紅球過濾出來吧。 程式範例 因為OpenCV中cv2.imread讀取圖檔預設讀取是為[B,G,R]的格式,所以設置紅色範圍要注意設定在R的範圍內。
Thumbnail
介紹OpenCV中的cv2.matchTemplate和cv2.minMaxLoc函數的使用方法和參數,提供程式範例以及相關特徵匹配的詳細介紹,讓讀者對此有更深入的瞭解。
Thumbnail
[OpenCV應用][Python]找出圖像中的四個方位的邊緣點求出寬高 呈上篇應用Numpy找到的座標點,那我們如何捨棄掉差異過大的座標點呢? 可能圖像物件邊緣不佳,採樣就會差異過大,造成計算出的寬高是不準確的。 遇到這種狀況,就可以使用下方的程式範例來篩選座標點。 為求方便,此範例跟圖
Thumbnail
觀看本文將可以學習到如何利用Numpy求得物件的邊緣點,及算出物件的寬跟高。 有詳細的程式邏輯說明,及各函式用法說明。 綠點及紅點則是採樣到的邊界點,比較粗的點是偵測到的最大值 完整程式碼 import cv2 import numpy as np import matplotl
Thumbnail
瞭解二值化影像的應用和程式語法,包括物體檢測和分割、邊緣檢測、圖像分析和測量、文檔辨識,以及使用cv2.threshold的參數和程式範例。
Thumbnail
在影像處理中,我們總是想要讓特徵更加明顯一點,可以使用銳利化的方式將特徵的邊緣增強,提升影像的細節,圖像銳利後就會有提升解析度的感覺。 拉普拉斯運算子是一種常用於影像增強的方法之一,特別是用於提高影像的邊緣和細節。 在OpenCV中,你可以使用cv2.Laplacian函數來應用拉普拉斯運算子。
Thumbnail
直方圖是對圖像中像素強度分布的圖形表示。通過分析直方圖,我們可以獲得有關圖像對比度、亮度和色彩分佈的有用信息。
Thumbnail
大部分在求物件的寬度及高度,都會想到用OpenCV的findContours函式來做,從找到的輪廓中來計算物件的面積,周長,邊界框等屬性,從而得到物體的寬度與高度 [OpenCV應用][Python]利用findContours找出物件邊界框求出寬度及高度 本文將用不同的方法,利用Numpy
Thumbnail
本文將利用OpenCV的findContours函式,從找到的輪廓中來計算物件的面積,周長,邊界框等屬性,從而得到物體的寬度與高度。 一般來說,我們在進行輪廓檢測時,會先進行圖像二值化,將對象轉換為白色,背景為黑色。這樣,在找到輪廓後,輪廓的點就會以白色表示,背景為黑色。 結果圖 從圖中綠色框
Thumbnail
[影像處理_OpenCV Python]使用Python撰寫影像處理功能,圖片遮罩或濾除掉不要的地方,旋轉圖片 以下範例將呈現影像處理三種不同的應用: 遮罩的實現 濾除 旋轉