Opencv發現輪廓findContours


函數原型

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

參數1:二值圖像;

參數2: 輪廓的集合,有點像C#的LIst<List<Point>>,用於輸出輪廓集

contours定義為“vector<vector<Point>> contours”,是一個雙重向量

向量內每個元素保存了一組由連續的Point構成的點的集合的向量

,每一組點集就是一個輪廓,有多少輪廓,contours就有多少元素;

參數3:hierarchy定義為“vector<Vec4i> hierarchy”,

Vec4i的定義: 用於輸出輪廓類型

typedef Vec<int, 4> Vec4i;(向量內每個元素都包含了4個int型變量),所以從定義上看,hierarchy是一個向量,向量內每個元素都是一個包含4個int型的數組。向量hierarchy內的元素和輪廓向量contours內的元素是一一對應的,向量的容量相同。hierarchy內每個元素的4個int型變量是hierarchy[i][0] ~ hierarchy[i][3],

分別表示當前輪廓 i 的后一個輪廓、前一個輪廓、父輪廓和內嵌輪廓的編號索引。如果當前輪廓沒有對應的后一個輪廓、前一個輪廓、父輪廓和內嵌輪廓,則相應的hierarchy[i][*]被置為-1。

參數4:定義輪廓的檢索模式,

取值如下:

            CV_RETR_EXTERNAL:只檢測最外圍輪廓,包含在外圍輪廓內的內圍輪廓被忽略;

            CV_RETR_LIST:檢測所有的輪廓,包括內圍、外圍輪廓,但是檢測到的輪廓不建立等級關系,彼此之間獨立,沒有等級關系,這就意味着這個檢索模式下不存在父輪廓或內嵌輪廓,所以hierarchy向量內所有元素的第3、第4個分量都會被置為-1,具體下文會講到;

            CV_RETR_CCOMP: 檢測所有的輪廓,但所有輪廓只建立兩個等級關系,外圍為頂層,若外圍內的內圍輪廓還包含了其他的輪廓信息,則內圍內的所有輪廓均歸屬於頂層;

            CV_RETR_TREE: 檢測所有輪廓,所有輪廓建立一個等級樹結構。外層輪廓包含內層輪廓,內層輪廓還可以繼續包含內嵌輪廓。

參數5:定義輪廓的近似方法,取值如下:

            CV_CHAIN_APPROX_NONE:保存物體邊界上所有連續的輪廓點到contours向量內;

            CV_CHAIN_APPROX_SIMPLE:僅保存輪廓的拐點信息,把所有輪廓拐點處的點保存入contours向量內,拐點與拐點之間直線段上的信息點不予保留;

            CV_CHAIN_APPROX_TC89_L1:使用teh-Chinl chain 近似算法;

            CV_CHAIN_APPROX_TC89_KCOS:使用teh-Chinl chain 近似算法。

參數6:Point偏移量,所有的輪廓信息相對於原始圖像對應點的偏移量,相當於在每一個檢測出的輪廓點上加上該偏移量,並且Point還可以是負值

案例如下:

#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>

using namespace std;
using namespace cv;

Mat src, dst;
const char* output_win = "findcontours-demo";
int threshold_value = 100;
int threshold_max = 255;
RNG rng;
void Demo_Contours(int, void*);
int main(int argc, char** argv) {
	src = imread("D:/vcprojects/images/happyfish.png");
	if (src.empty()) {
		printf("could not load image...\n");
		return -1;
	}
	namedWindow("input-image", CV_WINDOW_AUTOSIZE);
	namedWindow(output_win, CV_WINDOW_AUTOSIZE);
	imshow("input-image", src);
	cvtColor(src, src, CV_BGR2GRAY);

	const char* trackbar_title = "Threshold Value:";
	createTrackbar(trackbar_title, output_win, &threshold_value, threshold_max, Demo_Contours);
	Demo_Contours(0, 0);

	waitKey(0);
	return 0;
}

void Demo_Contours(int, void*) {
	Mat canny_output;
	vector<vector<Point>> contours;
	vector<Vec4i> hierachy;
	Canny(src, canny_output, threshold_value, threshold_value * 2, 3, false);
	findContours(canny_output, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));

	dst = Mat::zeros(src.size(), CV_8UC3);
	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(dst, contours, i, color, 2, 8, hierachy, 0, Point(0, 0));
	}
	imshow(output_win, dst);
}

  運行結果

 尋找輪廓前要進行邊緣,或者二值化圖像,不然,他只會把像素值為255的取輪廓。如下圖所示:

 

 

 

參考:https://www.cnblogs.com/GaloisY/p/11062065.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM