溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

OpenCV實(shí)現(xiàn)輪廓的發(fā)現(xiàn)

發(fā)布時(shí)間:2020-09-19 15:45:06 來(lái)源:腳本之家 閱讀:195 作者:AA_BUYI工作室 欄目:編程語(yǔ)言

前言:

        當(dāng)我們通過(guò)閾值分割提取到圖像中的目標(biāo)物體后,我們就需要通過(guò)邊緣檢測(cè)來(lái)提取目標(biāo)物體的輪廓,使用這兩種方法基本能夠確定物體的邊緣或者前景。接下來(lái),我們通常需要做的是擬合這些邊緣的前景,如擬合出包含前景或者邊緣像素點(diǎn)的最小外包矩形、圓、凸包等幾何形狀,為計(jì)算它們的面積或者模板匹配等操作打下堅(jiān)實(shí)的基礎(chǔ)。

一、查找、繪制輪廓

      首先了解一下輪廓的定義。一個(gè)輪廓代表一系列的點(diǎn)(像素),這一系列的點(diǎn)構(gòu)成一個(gè)有序的點(diǎn)集,所以可以把一個(gè)輪廓理解為一個(gè)有序的點(diǎn)集。

1.1 findContour()函數(shù)

        在OpenCV中,提供了一個(gè)函數(shù)返回或者輸出一個(gè)有序的點(diǎn)集或者有序的點(diǎn)集的集合(指多個(gè)有序的點(diǎn)集),函數(shù)findContour是從二值圖像中來(lái)計(jì)算輪廓的,它可以使用Canny()函數(shù)處理的圖像,因?yàn)檫@樣的圖像含有邊緣像素;也可以使用threshold()或者adaptiveThreshold()處理后的圖像,其邊緣隱含在正負(fù)區(qū)域的交界處。這個(gè)函數(shù)的聲明如下:

void findContours(InputOutputArray image,OutputArrayOfArrays contours,OutputArray hierarchy,int mode,int method,Point offset = Point());

其參數(shù)解釋如下:

(1)image:?jiǎn)瓮ǖ缊D像矩陣,可以是灰度圖,但更常用的是二值圖像,一般是經(jīng)過(guò)Canny、拉普拉斯等邊緣檢測(cè)算子處理過(guò)的二值圖像;

(2)contours:vector<vector<Point>>類(lèi)型,是一個(gè)向量,并且是一個(gè)雙重向量,向量?jī)?nèi)每個(gè)元素保存了一組由連續(xù)的Point點(diǎn)構(gòu)成的點(diǎn)的集合的向量,每一組Point點(diǎn)集就是一個(gè)輪廓。有多少輪廓,向量contours就有多少元素。

(3)hierarchy:vector<Vec4i> 類(lèi)型, Vec4i是Vec<int,4>的別名,即容器內(nèi)每一個(gè)元素都是一個(gè)包含了4個(gè)int型變量的向量,所以從定義上看,hierarchy也是一個(gè)向量,向量?jī)?nèi)每個(gè)元素保存了一個(gè)包含4個(gè)int整型的數(shù)組。向量hiararchy內(nèi)的元素和輪廓向量contours內(nèi)的元素是一一對(duì)應(yīng)的,向量的容量相同。hierarchy向量?jī)?nèi)每一個(gè)元素的4個(gè)int型變量——hierarchy[i][0] ~hierarchy[i][3],分別表示第i個(gè)輪廓的后一個(gè)輪廓、前一個(gè)輪廓、父輪廓、內(nèi)嵌輪廓的索引編號(hào)。如果當(dāng)前輪廓沒(méi)有對(duì)應(yīng)的后一個(gè)輪廓、前一個(gè)輪廓、父輪廓或內(nèi)嵌輪廓的話(huà),則hierarchy[i][0] ~hierarchy[i][3]的相應(yīng)位被設(shè)置為默認(rèn)值-1。

(4)mode:int類(lèi)型的,定義輪廓的檢索模式:

取值一:CV_RETR_EXTERNAL只檢測(cè)最外圍輪廓,包含在外圍輪廓內(nèi)的內(nèi)圍輪廓被忽略;

取值二:CV_RETR_LIST   檢測(cè)所有的輪廓,包括內(nèi)圍、外圍輪廓,但是檢測(cè)到的輪廓不建立等級(jí)關(guān)系,彼此之間獨(dú)立,沒(méi)有等級(jí)關(guān)系,這就意味著這個(gè)檢索模式下不存在父輪廓或內(nèi)嵌輪廓,所以hierarchy向量?jī)?nèi)所有元素的第3、第4個(gè)分量都會(huì)被置為-1,具體下文會(huì)講到;

 取值三:CV_RETR_CCOMP  檢測(cè)所有的輪廓,但所有輪廓只建立兩個(gè)等級(jí)關(guān)系,外圍為頂層,若外圍內(nèi)的內(nèi)圍輪廓還包含了其他的輪廓信息,則內(nèi)圍內(nèi)的所有輪廓均歸屬于頂層;

 取值四:CV_RETR_TREE, 檢測(cè)所有輪廓,所有輪廓建立一個(gè)等級(jí)樹(shù)結(jié)構(gòu)。外層輪廓包含內(nèi)層輪廓,內(nèi)層輪廓還可以繼續(xù)包含內(nèi)嵌輪廓。

(5) method:int類(lèi)型,定義輪廓的近似方法:

取值一:CV_CHAIN_APPROX_NONE 保存物體邊界上所有連續(xù)的輪廓點(diǎn)到contours向量?jī)?nèi);

取值二:CV_CHAIN_APPROX_SIMPLE 僅保存輪廓的拐點(diǎn)信息,把所有輪廓拐點(diǎn)處的點(diǎn)保存入contours向量?jī)?nèi),拐點(diǎn)與拐點(diǎn)之間直線(xiàn)段上的信息點(diǎn)不予保留;

取值三和四:CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法;

(6) Point:偏移量,所有的輪廓信息相對(duì)于原始圖像對(duì)應(yīng)點(diǎn)的偏移量,相當(dāng)于在每一個(gè)檢測(cè)出的輪廓點(diǎn)上加上該偏移量,并且Point還可以是負(fù)值。

注意事項(xiàng):

顯然,從函數(shù)名可以看出“尋找輪廓”的意思。我們可以通過(guò)邊緣檢測(cè)算法得到邊緣二值圖或者前景二值圖,二值圖的邊緣像素或者前景像素就可以被看出是由多個(gè)輪廓(點(diǎn)集)組成的。函數(shù)findContours的作用就是將二值圖的邊緣像素或者前景像素拆分成多個(gè)輪廓,便于分開(kāi)討論每一個(gè)輪廓,其中參數(shù)image代表一張二值圖,contours代表輸出的多個(gè)輪廓。對(duì)于該函數(shù)的C++API,對(duì)一個(gè)輪廓的描述用vector<Point>,那么多個(gè)輪廓(多個(gè)點(diǎn)集)如何表示呢?即參數(shù)contours是什么數(shù)據(jù)結(jié)構(gòu)呢?在C++API中,用vector<vector<Point>>描述多個(gè)輪廓,即將多個(gè)輪廓存在一個(gè)vector中。

1.2 drawContours()函數(shù)

OpenCV中也提供了一個(gè)函數(shù)來(lái)繪制findContours所找到的多個(gè)輪廓,其函數(shù)聲明如下:

void drawContours(InputOutputArray image,
InputArrayOfArrays contours,
int contourIdx,
const Scalar& color,
int thickness = 1,
int lineType = 8,
InputArray hierarchy = noArray(),
 
int maxLevel = INT_MAX,
 
Point offset = Point())

其參數(shù)解釋如下:

    (1)image: 代表輸入的圖像矩陣,將輪廓畫(huà)在該圖上;
    (2)contours:是得到的一系列點(diǎn)的集合,代表多個(gè)輪廓;
    (3)contourIdx:是一個(gè)索引,代表繪制contours中的第幾個(gè)輪廓;
    (4) color:被填充的顏色,單色可以設(shè)置為Scalar(255)等;
    (5)thickness: 所畫(huà)Contour的線(xiàn)條粗細(xì),如果該參數(shù)值小于0,則表示填充整個(gè)輪廓內(nèi)的區(qū)域;
    (6)lineType: 線(xiàn)的連通性;
    (7)hierarchy:可選層次信息結(jié)構(gòu),這里面是findContours所的到的基于Contours的層級(jí)信息;
    (8)maxLevel: 繪制輪廓的最大等級(jí)。如果等級(jí)為0,繪制單獨(dú)的輪廓。如果為1,繪制輪廓及在其后的相同的級(jí)別下輪廓。如果值為2,所有的輪廓。如果等級(jí)為2,繪制所有同級(jí)輪廓及所有低一級(jí)輪廓,諸此種種。如果值為負(fù)數(shù),函數(shù)不繪制同級(jí)輪廓,但會(huì)升序繪制直到級(jí)別為abs(max_level)-1的子輪廓

    (9)offset:照給出的偏移量移動(dòng)每一個(gè)輪廓點(diǎn)坐標(biāo).當(dāng)輪廓是從某些感興趣區(qū)域(ROI)中提取的然后需要在運(yùn)算中考慮ROI偏移量時(shí),將會(huì)用到這個(gè)參數(shù)。

二、 演示代碼

實(shí)例步驟

  • 轉(zhuǎn)灰度
  • canny得到二值圖像
  • findcontours尋找輪廓
  • drawcontours畫(huà)輪廓

我們編寫(xiě)演示代碼如下:

#include<opencv2\opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
Mat src1, src2,gray_img, dst;
int value = 100;
int max_value = 255;
void demo(int, void*);
int main()
{
 //發(fā)現(xiàn)輪廓--> cvtcolor-->canny得到二值圖像-->findcontours(尋找輪廓)-->drawcontous()
 src1 = imread("C:\\Users\\馬迎偉\\Desktop\\yuan1.jpg");
 //src2 = imread("C:\\Users\\馬迎偉\\Desktop\\heibao1.png");
 if (src1.empty())
 {
 printf("cannot load!!\n");
 system("pause");
 return -1;
 }
 namedWindow("input", CV_WINDOW_AUTOSIZE);
 imshow("input",src1);
 namedWindow("output", CV_WINDOW_AUTOSIZE);
 cvtColor(src1,gray_img,CV_BGR2GRAY);
 createTrackbar("creattrackbar","output",&value,max_value,demo);
 demo(0, 0);
 waitKey(0);
 return 0;
}
void demo(int, void*)
{
 //將圖像表現(xiàn)在src3上
 Mat src3 = Mat::zeros(src1.size(),CV_8UC3);
 vector<vector<Point>>contours;
 vector<Vec4i>hierarchy;
 Canny(gray_img,src2,value,value*2,3,false );
 findContours(src2,contours,RETR_TREE,CHAIN_APPROX_SIMPLE,Point(0,0));
 RNG rng(12345);
 for (size_t i = 0; i < contours.size(); i++)
 {
 Scalar color = Scalar(rng.uniform(0,255),rng.uniform(0,255),rng.uniform(0,255));
 drawContours(src3, contours, i,color,1,LINE_AA,hierarchy,0,Point(0,0));
 }
 imshow("output",src3);
}

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持億速云。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI