函數原型
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的取輪廓。如下圖所示: