【繪制圖像輪廓|凸包特征檢測】圖像處理(OpenCV) -part7

15 繪制圖像輪廓

15.1 什么是輪廓

輪廓是一系列相連的點組成的曲線,代表了物體的基本外形。相對于邊緣,輪廓是連續的,邊緣不一定連續,如下圖所示。輪廓是一個閉合的、封閉的形狀。

  • 輪廓的作用

    • 形狀分析

    • 目標識別

    • 圖像分割

15.2 尋找輪廓

在OpenCV中,使用cv2.findContours()來進行尋找輪廓,其原理過于復雜,這里只進行一個簡單的介紹,具體的實現原理可參考:

https://zhuanlan.zhihu.com/p/107257870

尋找輪廓需要將圖像做一個二值化處理,并且根據圖像的不同選擇不同的二值化方法來將圖像中要繪制輪廓的部分置為白色其余部分置為黑色。也就是說,我們需要對原始的圖像進行灰度化、二值化的處理,令目標區域顯示為白色,其他區域顯示為黑色,如下圖所示。

之后,對圖像中的像素進行遍歷,當一個白色像素相鄰(上下左右及兩條對角線)位置有黑色像素存在或者一個黑色像素相鄰(上下左右及兩條對角線)位置有白色像素存在時,那么該像素點就會被認定為邊界像素點,輪廓就是有無數個這樣的邊界點組成的。

下面具體介紹一下cv2.findContours()函數,其函數原型為:

contours,hierarchy = cv2.findContours(image,mode,method)

返回值:[ 輪廓點坐標 ] 和 [ 層級關系 ]。

contours:表示獲取到的輪廓點的列表。檢測到有多少個輪廓,該列表就有多少子列表,每一個子列表都代表了一個輪廓中所有點的坐標。

hierarchy:表示輪廓之間的關系。對于第i條輪廓,hierarchy[i][0], hierarchy[i][1] , hierarchy[i][2] , hierarchy[i][3]分別表示其后一條輪廓、前一條輪廓、(同層次的第一個)子輪廓、父輪廓的索引(如果沒有相應的輪廓,則對應位置為-1)。該參數的使用情況會比較少。

image:表示輸入的二值化圖像。

mode:表示輪廓的檢索模式。

method:輪廓的表示方法。

15.2.1 mode參數

輪廓查找方式。返回不同的層級關系。

mode參數共有四個選項分別為:RETR_LIST,RETR_EXTERNAL,RETR_CCOMP,RETR_TREE。

RETR_EXTERNAL

表示只查找最外層的輪廓。并且在hierarchy里的輪廓關系中,每一個輪廓只有前一條輪廓與后一條輪廓的索引,而沒有父輪廓與子輪廓的索引。

2.3.4.會查找所有輪廓,但會有層級關系

RETR_LIST

表示列出所有的輪廓。并且在hierarchy里的輪廓關系中,每一個輪廓只有前一條輪廓與后一條輪廓的索引,而沒有父輪廓與子輪廓的索引。

RETR_CCOMP

表示列出所有的輪廓。并且在hierarchy里的輪廓關系中,輪廓會按照成對的方式顯示。

RETR_CCOMP 模式下,輪廓被分為兩個層級:

層級 0:所有外部輪廓(最外層的邊界)。

層級 1:所有內部輪廓(孔洞或嵌套的區域)。

RETR_TREE

表示列出所有的輪廓。并且在hierarchy里的輪廓關系中,輪廓會按照樹的方式顯示,其中最外層的輪廓作為樹根,其子輪廓是一個個的樹枝。

15.2.2 method參數

輪廓存儲方法。輪廓近似方法。決定如何簡化輪廓點的數量。就是找到輪廓后怎么去存儲這些點。

method參數有三個選項:CHAIN_APPROX_NONE、CHAIN_APPROX_SIMPLE、CHAIN_APPROX_TC89_L1。

CHAIN_APPROX_NONE表示將所有的輪廓點都進行存儲

CHAIN_APPROX_SIMPLE表示只存儲有用的點,比如直線只存儲起點和終點,四邊形只存儲四個頂點,默認使用這個方法;

對于mode和method這兩個參數來說,一般使用RETR_EXTERNAL和CHAIN_APPROX_SIMPLE這兩個選項。

15.3 繪制輪廓

輪廓找出來后,其實返回的是一個輪廓點坐標的列表,因此我們需要根據這些坐標將輪廓畫出來,因此就用到了繪制輪廓的方法。

cv2.drawContours(image, contours, contourIdx, color, thickness)

image:原始圖像,一般為單通道或三通道的 numpy 數組。

contours:包含多個輪廓的列表,每個輪廓本身也是一個由點坐標構成的二維數組(numpy數組)。

contourIdx:要繪制的輪廓索引。如果設為 -1,則會繪制所有輪廓。根據索引找到輪廓點繪制出來。默認是-1。

color:繪制輪廓的顏色,可以是 BGR 值或者是灰度值(對于灰度圖像)。

thickness:輪廓線的寬度,如果是正數,則畫實線;如果是負數,則填充輪廓內的區域。

?
img = cv.imread('images/de.jpg')
#灰度處理
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
#二值化 用反閾值法
ret, binary = cv.threshold(gray, 127, 255, cv.THRESH_BINARY_INV)
#查找輪廓 
contours, hierarchy = cv.findContours(binary, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
#繪制輪廓
cv.drawContours(img, contours, -1, (100, 100, 255), 3)
#顯示結果
cv.imshow('Original Image', img)
cv.imshow('Binary Image', binary)
cv.waitKey(0)
cv.destroyAllWindows()

16 凸包特征檢測

在進行凸包特征檢測之前,首先要了解什么是凸包。通俗的講,凸包其實就是將一張圖片中物體的最外層的點連接起來構成的凸多邊形,它能包含物體中所有的內容。

一般來說,凸包都是伴隨著某類點集存在的,也被稱為某個點集的凸包。

對于一個點集來說,如果該點集存在凸包,那么這個點集里面的所有點要么在凸包上,要么在凸包內。

凸包檢測常用在物體識別、手勢識別、邊界檢測等領域。

窮舉法

QuickHull法

1.窮舉法

將集中的點進行兩兩配對,并進行連線,對于每條直線,檢查其余所有的點是否處于該直線的同一側,如果是,那么說明構成該直線的兩個點就是凸包點,其余的線依次進行計算,從而獲取所有的凸包點。

用向量的思想,點都是有坐標的,連起來就可以構成一個向量。再以其中一個點,連接另一個點,構成另一個向量,讓兩個向量做外積,就是叉積。也就是std=|向量a|*|向量b|*sin(\theta),能控制std的正負的只能是\theta,如果計算出來的std的正負都相同,說明這些點都在這條直線的同一側,那么這兩個點就是凸包的邊界點。然后換兩個點,就是說換一條直線,換一個向量,繼續進行檢測,直到找到凸包的所有的邊界點。

缺點:時間復雜度高,不斷使用for循環,耗時。

2.QuickHull法

將所有點放在二維坐標系中,找到橫坐標最小和最大的兩個點P1和P2并連線。此時整個點集被分為兩部分,直線上為上包,直線下為下包

以上保暖為例,找到上包中的點距離該直線最遠的點P3,連線并尋找直線P1P3左側的點和P2P3右側的點,然后重復本步驟,直到找不到為止。對下包也是這樣操作。

我們以點集來舉例,假如有這么一些點,其分布如下圖所示:

那么經過凸包檢測并繪制之后,其結果應該如下圖所示:

可以看到,原圖像在經過凸包檢測之后,會將最外圍的幾個點進行連接,剩余的點都在這些點的包圍圈之內。那么凸包檢測到底是怎么檢測出哪些點是最外圍的點呢?

我們還是以上面的點集為例,假設我們知道這些點的坐標,那么我們就可以找出處于最左邊和最右邊的點,如下圖所示:

接著將這兩個點連接,并將點集分為上半區和下半區,我們以上半區為例:

找到上面這些點離直線最遠的點,其中,這條直線由于有兩個點的坐標,所以其表示的直線方程是已知的,并且上面的點的坐標也是已知的,那么我們就可以根據點到直線的距離公式來進行計算哪個點到直線的距離最遠,假設直線的方程為:A x+B y+C=0,那么點(x0,y0)到直線的距離公式為:

然后我們就可以得到距離這條線最遠的點,將其與左右兩點連起來,并分別命名為y1和y2,如下圖所示:

然后分別根據點的坐標求出y1和y2的直線方程,之后將上半區的每個點的坐標帶入下面公式中:

d=0時,表明該點在直線上;當d>0時,表明點在直線的上方,在這里就代表該點在上圖所圍成的三角形的外面,也就意味著該三角形并沒有完全包圍住上半區的所有點,需要重新尋找凸包點;當d<0時,表明點在直線的下方,在這里就代表該點在上圖所圍成的三角形的里面,也就代表著這類點就不用管了。

當出現d>0時,我們需要將出現這種結果的兩個計算對象:某點和y1或y2這條線標記,并在最后重新計算出現這種現象的點集到y1或y2的距離來獲取新的凸包點的坐標。在本例子中,也就是如下圖所示的點和y2這條直線:

由于本例子中只有這一個點在這個三角形之外,所以毫無疑問的它就是一個凸包點,因此直接將它與y2直線的兩個端點相連即可。當有很多點在y2直線外時,就需要計算每個點到y2的距離,然后找到離得最遠的點與y2構建三角形,并重新計算是否還有點在該三角形之外,如果沒有,那么這個點就是新的凸包點,如果有,那就需要重復上面的步驟,直到所有的點都能被包圍住,那么構建直線的點就是凸包點。這是上半區尋找凸包點的過程,下半區尋找凸包點的思路與此一模一樣,只不過是需要篩選d<0(也就是點在直線的下方)的點,并重新構建三角形,尋找新的凸包點。

上面的過程都是基于我們知道點的坐標進行的,實際上,對于未經處理的圖像,我們無法直接獲取點的坐標。特別是對于彩色圖像,我們需要將其轉換為二值圖像,并使用輪廓檢測技術來獲取輪廓邊界的點的坐標。然后,我們才能進行上述尋找凸包點的過程。因此,在處理圖像時,我們需要將彩色圖像轉換為二值圖像,并通過輪廓檢測技術來獲取輪廓邊界的點的坐標,然后才能進行凸包點的尋找過程

16.1 獲取凸包點

cv2.convexHull(points)

points:輸入參數,圖像的輪廓

16.2 繪制凸包

cv2.polylines(image, pts, isClosed, color, thickness=1)

image:要繪制線條的目標圖像,它應該是一個OpenCV格式的二維圖像數組(如numpy數組)。

pts:一個二維 numpy 數組,每個元素是一維數組,代表一個多邊形的一系列頂點坐標。

isClosed:布爾值,表示是否閉合多邊形,如果為 True,會在最后一個頂點和第一個頂點間自動添加一條線段,形成封閉的多邊形。

color:線條顏色,可以是一個三元組或四元組,分別對應BGR或BGRA通道的顏色值,或者是灰度圖像的一個整數值。

thickness(可選):線條寬度,默認值為1。

img = cv.imread('images/menghuwang.jpg')
#灰度圖
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
#二值化處理,閾值法 因為目標是白色我們需要白色
ret, binary = cv.threshold(gray, 200, 255, cv.THRESH_BINARY_INV)
#查找輪廓
contours, hierarchy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
for i in range(len(contours)):#查找凸包hull = cv.convexHull(contours[i])#繪制凸包cv.polylines(img, [hull], True, (100, 100, 255), 3)
print(hull)
cv.imshow('1', img)
cv.imshow('2', binary)
cv.waitKey(0)
cv.destroyAllWindows()

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/80203.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/80203.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/80203.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

uniapp中使用<cover-view>標簽

文章背景&#xff1a; uniapp中遇到了原生組件(canvas)優先級過高覆蓋vant組件 解決辦法&#xff1a; 使用<cover-view>標簽 踩坑&#xff1a; 我想實現的是一個vant組件庫中動作面板的效果&#xff0c;能夠從底部彈出框&#xff0c;讓用戶進行選擇&#xff0c;我直…

Kafka常見問題及解決方案

Kafka 是一個強大的分布式流處理平臺&#xff0c;廣泛用于高吞吐量的數據流處理&#xff0c;但在實際使用過程中&#xff0c;也會遇到一些常見問題。以下是一些常見的 Kafka 問題及其對應的解決辦法的詳細解答&#xff1a; 消息丟失 一、原因 1.生產端 網絡故障、生產者超時…

leetcode 二分查找應用

34. Find First and Last Position of Element in Sorted Array 代碼&#xff1a; class Solution { public:vector<int> searchRange(vector<int>& nums, int target) {int low lowwer_bound(nums,target);int high upper_bound(nums,target);if(low high…

【Docker】在容器中使用 NVIDIA GPU

解決容器 GPU 設備映射問題&#xff0c;實現 AI 應用加速 &#x1f517; 官方文檔&#xff1a;NVIDIA Container Toolkit GitHub 常見錯誤排查 若在運行測試容器時遇到以下錯誤&#xff1a; docker: Error response from daemon: could not select device driver ""…

通過Quartus II實現Nios II編程

目錄 一、認識Nios II二、使用Quartus II 18.0Lite搭建Nios II硬件部分三、軟件部分四、運行項目 一、認識Nios II Nios II軟核處理器簡介 Nios II是Altera公司推出的一款32位RISC嵌入式處理器&#xff0c;專門設計用于在FPGA上運行。作為軟核處理器&#xff0c;Nios II可以通…

JAVA設計模式——(三)橋接模式

JAVA設計模式——&#xff08;三&#xff09;橋接模式&#xff08;Bridge Pattern&#xff09; 介紹理解實現武器抽象類武器實現類涂裝顏色的行為接口具體顏色的行為實現讓行為影響武器修改武器抽象類修改實現類 測試 適用性 介紹 將抽象和實現解耦&#xff0c;使兩者可以獨立…

k8s 證書相關問題

1.重新生成新證書 kubeadm init phase certs apiserver-etcd-client --config ~/kubeadm.yaml這個命令表示生成 kube-apiserver 連接 etcd 使用的證書,生成后如下 -rw------- 1 root root 1.7K Apr 23 16:35 apiserver-etcd-client.key -rw-r--r-- 1 root root 1.2K Apr 23 …

比較:AWS VPC peering與 AWS Transit Gateway

簡述: VPC 對等連接和 Transit Gateway 用于連接多個 VPC。VPC 對等連接提供全網狀架構,而 Transit Gateway 提供中心輻射型架構。Transit Gateway 提供大規模 VPC 連接,并簡化了 VPC 間通信管理,相比 VPC 對等連接,支持大量 VPC 的 VPC 間通信管理。 VPC 對等連接 AWS V…

制造企業PLM深度應用:2025年基于PDCA循環的7項持續改進指標

制造企業的產品生命周期管理&#xff08;PLM&#xff09;在數字化轉型的浪潮中扮演著至關重要的角色。PLM深度應用不僅能夠提升產品研發效率、保證產品質量&#xff0c;還能增強企業在市場中的競爭力。隨著2025年智能制造目標的推進&#xff0c;基于PDCA循環的持續改進對于PLM的…

極狐GitLab 的壓縮和合并是什么?

極狐GitLab 是 GitLab 在中國的發行版&#xff0c;關于中文參考文檔和資料有&#xff1a; 極狐GitLab 中文文檔極狐GitLab 中文論壇極狐GitLab 官網 壓縮和合并 (BASIC ALL) 在你處理一個特性分支時&#xff0c;通常會創建一些小的、獨立的提交。這些小提交幫助描述構建特性…

解耦舊系統的利器:Java 中的適配器模式(Adapter Pattern)實戰解析

在現代軟件開發中&#xff0c;我們經常需要與舊系統、第三方庫或不一致接口打交道。這時候&#xff0c;如果能優雅地整合這些不兼容組件&#xff0c;又不破壞原有結構&#xff0c;就需要一位“翻譯官” —— 適配器模式。本文將通過 Java 實例&#xff0c;詳細講解適配器模式的…

03-谷粒商城筆記

一個插件的install和生命周期的報錯是不一樣的 Maven找不到ojdbc6和sqljdbc4依賴包 這時候我找到了jar包&#xff0c;然后我就先找到一個jar安裝到了本地倉庫。 在終端上進行命令了&#xff1a; mvn install:install-file -DfileD:\ojdbc6-11.2.0.4.jar -DgroupIdcom.oracle …

黑馬點評redis改 part 5

達人探店 發布探店筆記 那第一張表block表它里邊的結構呢是這個 首先呢第一個字段是i d&#xff0c;就是主鍵&#xff0c;第二個呢是shop id&#xff0c;就是商戶你發的這個比例啊&#xff0c;它是跟哪個商戶有關系的。第三個呢用戶id就是誰發的這篇筆記&#xff0c;第四個呢標…

【PCB工藝】運放電路中的負反饋機制

通過運算方法器電路設計詳細解釋負反饋機制&#xff08;Negative Feedback&#xff09; 負反饋 是控制系統、電子電路、神經系統等多個領域中非常核心的概念。特別在運算放大器&#xff08;Op-Amp&#xff09;電路中&#xff0c;負反饋是實現精確控制和高穩定性的關鍵機制。 …

聲紋振動傳感器在電力監測領域的應用

聲紋振動傳感器在電力監測領域有多種應用&#xff0c;主要包括以下幾個方面&#xff1a; 變壓器監測 故障診斷&#xff1a;變壓器在運行過程中會產生特定的聲紋和振動信號&#xff0c;當變壓器內部出現故障&#xff0c;如繞組短路、鐵芯松動、局部放電等&#xff0c;其聲紋和振…

7、sentinel

控制臺訪問地址&#xff1a;http://localhost:8080/ 依賴 <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency>配置文件 spring:cloud:sentinel:transpo…

線程封裝

目錄 makefile Thread.hpp main.cc 以面向對象的方式造輪子 #ifndef _THREAD_HPP__ // 如果沒有定義過 _THREAD_HPP__ #define _THREAD_HPP__ // 則定義 _THREAD_HPP__// 這里是頭文件的實際內容&#xff08;類、函數聲明等&#xff09;#endif // 結束條件…

【maven-7.1】POM文件中的屬性管理:提升構建靈活性與可維護性

在Maven項目中&#xff0c;POM (Project Object Model) 文件是核心配置文件&#xff0c;而屬性管理則是POM中一個強大但常被低估的特性。良好的屬性管理可以顯著提升項目的可維護性、減少重復配置&#xff0c;并使構建過程更加靈活。本文將深入探討Maven中的屬性管理機制。 1.…

極狐GitLab 的合并請求部件能干什么?

極狐GitLab 是 GitLab 在中國的發行版&#xff0c;關于中文參考文檔和資料有&#xff1a; 極狐GitLab 中文文檔極狐GitLab 中文論壇極狐GitLab 官網 合并請求部件 (BASIC ALL) 合并請求的 概述 頁面顯示了來自服務的狀態更新&#xff0c;這些服務會對您的合并請求執行操作。…

26、C# 中是否可以繼承String類?為什么?

在 C# 中&#xff0c;不能直接繼承 String 類&#xff08;System.String&#xff09;。這是由于以下幾個原因&#xff1a; 1、String 類是 sealed 的 String 類在 .NET 中被標記為 sealed&#xff0c;這意味著它是一個密封類&#xff0c;不能被繼承。 sealed 關鍵字的作用是防…