OpenCV成長之路 直線 輪廓的提取與描述

2021-07-30 01:56:16 字數 3836 閱讀 1000

基於內容的影象分析的重點是提取出影象中具有代表性的特徵,而線條、輪廓、塊往往是最能體現特徵的幾個元素,這篇文章就針對於這幾個重要的影象特徵,研究它們在opencv中的用法,以及做一些簡單的基礎應用。

canny邊緣檢測採用雙閾值值法,高閾值用來檢測影象中重要的、顯著的線條、輪廓等,而低閾值用來保證不丟失細節部分,低閾值檢測出來的邊緣更豐富,但是很多邊緣並不是我們關心的。最後採用一種查詢演算法,將低閾值中與高閾值的邊緣有重疊的線條保留,其他的線條都刪除。

本篇文章中不對canny的演算法原理作進一步說明,稍後會在影象處理演算法相關的文章中詳細介紹。

下面我們用opencv中的canny函式來檢測影象邊緣

int

main() 

顯示效果如下:

直線在影象中出現的頻率非常之高,而直線作為影象的特徵對於基本內容的影象分析有著很重要的作用,本文通過opencv中的hough變換來檢測影象中的線條。

我們先看最基本的hough變換函式houghlines,它的原型如下:

void houghlines(inputarray image, outputarray lines, double rho, double theta, int threshold, double 

srn=

0, double 

stn=

0); 

它的輸入是乙個二值的輪廓影象,往往是邊緣檢測得到的結果影象;它的輸出是乙個包含多個vec2f點的陣列,陣列中的每個元素是乙個二元浮點資料 對,rou代表直線離座標原點的距離,theta代表角度。第3和第4個引數代表步長,因為hough變換實際上是一 個窮舉的演算法,rho表示距離的步長,theta代表角度的步長。第5個引數是乙個閾值設定直接的最低投票個數,知道hough原理的,這個引數應該很容 易理解。

從 這個函式的輸出結果我們可以看出,得到的直線並沒有指定在影象中的開始點與結束點,需要我們自己去計算,如果我們想把直接顯示在影象中就會比較麻煩,而且 會有很多角度接近的直線,其實它們是重複的,為了解決上面這些問題,opencv又提供了乙個函式houghlinesp()。它的輸出是乙個 vector of vec4i。vector每乙個元素代表一條直線,是由乙個4元浮點陣列構成,前兩個點一組,後兩個點一組,代表了在影象中直線的起始和結束點。

void

houghlinesp(inputarray image, outputarray lines, 

double

rho, 

double

theta,

intthreshold, 

double

minlinelength=0, 

double

maxlinegap=0 ); 

解釋一下最後兩個引數,minlinelength指定了檢測直線中的最小寬度,如果低於最小寬度則捨棄掉,maxlinegap指定通過同一點的直線,如果距離小於maxlinegap就會進行合併。

下面是乙個用houghlinesp檢測直線的例子:

int

main() 

上面程式將檢測到的線條儲存在lines變數內,我們需要進一步將它們畫在影象上:

實 際上hough變換可以檢測很多固定的形狀,比如:圓、正方形等。它們的原理基本相同,都是構造乙個投票矩陣。opencv裡提供了檢測圓的函式 houghcircles,它的輸出是乙個vector of vec3i,vector的每個元素包含了3個浮點數,前2個是圓的中心座標,最後乙個是半徑。

在目標識別中我們首先要把感興趣的目標提取出來,而一般常見的步驟都是通過顏色或紋理提取出目標的前景圖(一幅黑白影象,目標以白色顯示在影象中),接下來我們要對前景圖進行分析進一步地把目標提取出來,而這裡常常用到的就是提取目標的輪廓。

opencv 裡提取目標輪廓的函式是findcontours,它的輸入影象是一幅二值影象,輸出的是每乙個連通區域的輪廓點的集 合:vector>。外層vector的size代表了影象中輪廓的個數,裡面vector的 size代表了輪廓上點的個數。下面我們通過例項來看函式的用法。

上面程式中包含了2個函式,第乙個是查詢輪廓函式,它的第三個引數說明查詢輪廓的型別,這裡我們使用的是外輪廓,還可以查詢所有輪廓,即包括一些孔洞的部 分,像影象人物胳膊與腰間形成的輪廓。第4個引數說明了輪廓表示的方法,程式中的引數說明輪廓包括了所有點,也可以用其他引數讓有點直線的地方,只儲存直 線起始與終點的位置點,具體引數用法可以參考手冊裡函式的介紹。

第二個函式drawcontours是乙個畫輪廓的函式,它的第3個引數程式裡設定-1表示所有的輪廓都畫,你也可以指定要畫的輪廓的序號。

提取到輪廓後,其實我們更關心的是如果把這些輪廓轉換為可以利用的特徵,也就是涉及到輪廓的描述問題,這時就有多種方法可以選擇,比如向量化為多邊形、矩形、橢圓等。opencv裡提供了一些這樣的函式。

// 輪廓表示為乙個矩形

rect r = boundingrect(mat(contours[0])); 

rectangle(result, r, scalar(255), 2); 

// 輪廓表示為乙個圓

float

radius; 

point2f center; 

minenclosingcircle(mat(contours[1]), center, radius); 

circle(result, point(center), static_cast

<

int>(radius), scalar(255), 2); 

// 輪廓表示為乙個多邊形

vectorpoly; 

); vector::const_iterator itp = poly.begin(); 

while

(itp != (poly.end() - 1)) 

line(result, *itp, *(poly.begin()), scalar(255), 2); 

// 輪廓表示為凸多邊形

vectorhull; 

convexhull(mat(contours[3]), hull); 

vector::const_iterator ith = hull.begin(); 

while

(ith != (hull.end() - 1)) 

line(result, *ith, *(hull.begin()), scalar(255), 2); 

程式中我們依次畫了矩形、圓、多邊形和凸多邊形。最終效果如下:

對連通區域的分析到此遠遠沒有結束,我們可以進一步計算每乙個連通區域的其他屬性,比如:重心、中心矩等特徵,這些內容以後有機會展開來寫。

以 下幾個函式可以嘗試:minarearect:計算乙個最小面積的外接矩形,contourarea可以計算輪廓內連通區域的面 積;pointpolygentest可以用來判斷乙個點是否在乙個多邊形內。mathshapes可以比較兩個形狀的相似性,相當有用的乙個函式。

OpenCV成長之路 8 直線 輪廓的提取與描述

基於內容的影象分析的重點是提取出影象中具有代表性的特徵,而線條 輪廓 塊往往是最能體現特徵的幾個元素,這篇文章就針對於這幾個重要的影象特徵,研究它們在opencv中的用法,以及做一些簡單的基礎應用。canny邊緣檢測採用雙閾值值法,高閾值用來檢測影象中重要的 顯著的線條 輪廓等,而低閾值用來保證不丟...

OpenCV中的輪廓發現和輪廓繪製

實現 import cv2 import numpy as np 輪廓發現和輪廓繪製 img是一張與binary類似的二值圖,contours是list列表結構每個元素包含乙個邊沿資訊,heriachy是乙個矩陣,用處作者也未知,可以 contours,heriachy cv2.findcontou...

OpenCV 輪廓的凸性

一 概括 理解物體形狀或輪廓的另外一種有用的方法是計算乙個物體的凸包 convex hull 然後計算其凸缺陷 convexity defects 很多複雜物體的特性能很好的被這種缺陷表現出來。二 相關函式 1 發現點集的凸外形 cvseq cvconvexhull2 const cvarr inp...