1.27【OpenCV圖像處理】尋找輪廓

輪廓尋找(find contours)是基於圖像邊緣提取的基礎上尋找對象輪廓的方法。所以邊緣提取的閾值選定會影響最終輪廓發現結果,由實際圖像效果來決定閾值多少。

1.27.2 API介紹

(1)在二值圖像上尋找輪廓(find contours)

findContours(

InputOutputArray binImg, // 輸入8-bit單通道圖像,非0的像素被看成1,0的像素值保持不變,因此圖像被視為二進位。

OutputArrayOfArrays contours, // 每組連續的輪廓點集為一個元素,元素都存儲到數組vector<vector<Point>> points;

OutputArray, hierarchy// 可選的輸出向量,該圖的拓撲結構(層次結構),可以不寫它,該輪廓發現演算法正是基於圖像拓撲結構實現的。vector<Vec4i> hierachy;

int mode, // 輪廓檢索演算法,(常用單層次RETR_EXTERNAL 、輪廓樹多層次RETR_TREE)

int method, // 輪廓近似方法,(常用存儲端點CHAIN_APPROX_SIMPLE)

Point offset=Point() // 每個檢測出的輪廓點被移動的可選偏移量,輪廓像素的位移,默認(0,0)沒有位移,Point還可以是負值,任一點加上該偏移量後不能超出圖像邊界

)

  • 第一個參數:image,單通道圖像矩陣,可以是灰度圖,但更常用的是二值圖像,一般是經過Canny、拉普拉斯等邊緣檢測運算元處理過的二值圖像;
  • 第二個參數:contours,定義為「vector<vector<Point>> contours」,是一個雙重向量,向量內每個元素保存了一組由連續的輪廓點構成的點的集合的向量,每一組Point點集就是一個輪廓。 有多少輪廓,向量contours就有多少元素。
  • 第三個參數:hierarchy,定義為「vector<Vec4i> hierarchy」,Vec4i的定義:typedef Vec<int, 4> Vec4i; 定義了一個「向量內每一個元素包含了4個int型變數」的向量。向量hiararchy內的元素和輪廓向量contours內的元素是一一對應的,向量的容量相同。hierarchy向量內每一個元素的4個int型變數——hierarchy[i][0] ~hierarchy[i][3],分別表示第i個輪廓的後一個輪廓、前一個輪廓、父輪廓、內嵌輪廓的索引編號。如果當前輪廓沒有對應的後一個輪廓、前一個輪廓、父輪廓或內嵌輪廓的話,則hierarchy[i][0] ~hierarchy[i][3]的相應位被設置為默認值-1。

各參數的效果區別見博客:blog.csdn.net/dcrmg/art

/*尋找輪廓*/nvector<vector<Point>> controus; //定義一個多維數組(速度較慢),用於儲存檢測到的輪廓點nvector<Vec4i> hierachy; //層次nfindContours(canny_output, controus, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0)); //尋找輪廓:輸入二值圖像,每個輪廓點都存儲到數組,輸出層次結構,輪廓檢索演算法(RETR_TREE多層次所有輪廓,RETR_EXTERNAL單層次外部輪廓),輪廓逼近演算法,輪廓點位移n//findContours(dist_8u, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0, 0)); //尋找輪廓,省去層次結構,檢索外部輪廓,輪廓拐點近似n

(2)輪廓繪製(draw contour)

對發現的輪廓數據繪製到輸出圖像上顯示:

drawContours(

InputOutputArray binImg, // 輸出圖像

outputArrayOfArrays contours,// 全部發現的輪廓對象

Int contourIdx// 輪廓索引號,i

const Scalar & color,// 繪製時候顏色

int thickness,// 繪製線寬

int lineType ,// 線的類型LINE_8、LINE_AA

InputArray hierarchy,// 拓撲結構圖(層次結構)

int maxlevel,// 最大層數, 0隻繪製當前的,1表示繪製當前及其內嵌的輪廓

Point offset=Point()// 輪廓位移,可選,默認(0, 0)沒有位移

drawContours(dst, controus, i, color, 2, 8, hierachy, 0, Point(0, 0));//繪製輪廓:輸入,輪廓點,輪廓索引號,顏色,線寬,線類型,層次,最大層數0隻繪製當前的,輪廓位移n

實現步驟:

1)轉灰度 - cvtColor()

cvtColor(src, src, CV_BGR2GRAY); //轉灰度nconst char* Trackbar_title = "Threshold Value";nnamedWindow(output_win, CV_WINDOW_AUTOSIZE); //必須有,否則跟蹤條不顯示ncreateTrackbar(Trackbar_title, output_win, &threshold_value, threshold_max, Demo_Contours); //跟蹤條控制邊緣提取的閾值n

2)使用Canny進行邊緣提取,得到二值圖像 - Canny()

/*Canny邊緣提取*/nMat canny_output;nCanny(src, canny_output, threshold_value, threshold_value * 2, 3, false); //Canny邊緣提取:3是Sobel運算元的大小,計算圖像梯度幅值false選L1帶絕對值的方法 nimshow("canny_output", canny_output); //顯示Canny邊緣提取二值化圖n

3)尋找輪廓 - findContours()

/*尋找輪廓*/nvector<vector<Point>> controus; //定義一個多維數組(速度較慢),用於儲存檢測到的輪廓點nvector<Vec4i> hierachy; //層次nfindContours(canny_output, controus, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0)); //尋找輪廓:輸入二值圖像,每個輪廓點都存儲到數組,輸出層次結構,輪廓檢索演算法,輪廓逼近演算法,輪廓點位移n

4)繪製輪廓 - drawContours()

/*繪製輪廓*/ndst = Mat::zeros(src.size(), CV_8UC3);nRNG rng(12345);nfor (size_t i = 0; i < controus.size(); i++) {nScalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)); //顏色隨機ndrawContours(dst, controus, i, color, 2, 8, hierachy, 0, Point(0, 0));//繪製輪廓:輸入,輪廓點,輪廓索引號,顏色,線寬,線類型,層次,最大層數0隻繪製當前的,輪廓位移n}nimshow(output_win, dst); //顏色相同的部分屬於同一個輪廓n


完整程序:

/*1.27 尋找輪廓*/n#include <opencv2/opencv.hpp>n#include <iostream> n#include <math.h>nusing namespace cv;nusing namespace std;nnMat src, dst;nconst char* output_win = "find contours";nint threshold_value = 100;nint threshold_max = 255;nRNG rng;nvoid Demo_Contours(int, void*);nnint main(int argc, char** argv) {n src = imread("E:/OpenCV/testimage/happyfish.png");nif (src.empty()) {n printf("could not load image...n");nreturn -1;n }nchar input_title[] = "input image";n namedWindow(input_title, CV_WINDOW_AUTOSIZE); n imshow(input_title, src);nn cvtColor(src, src, CV_BGR2GRAY); //轉灰度n imshow("gray image", src);nconst char* Trackbar_title = "Threshold Value";n namedWindow(output_win, CV_WINDOW_AUTOSIZE); //必須有,否則跟蹤條不顯示n createTrackbar(Trackbar_title, output_win, &threshold_value, threshold_max, Demo_Contours); //跟蹤條控制邊緣提取的閾值n Demo_Contours(0, 0);nn waitKey(0);nreturn 0;n}nnvoid Demo_Contours(int, void*) {n /*Canny邊緣提取*/nMat canny_output;n Canny(src, canny_output, threshold_value, threshold_value * 2, 3, false); //Canny邊緣提取:3是Sobel運算元的大小,計算圖像梯度幅值false選L1帶絕對值的方法 n imshow("canny_output", canny_output); //顯示Canny邊緣提取二值化圖nn /*尋找輪廓*/nvector<vector<Point>> controus; //定義一個多維數組(速度較慢),用於儲存檢測到的輪廓點nvector<Vec4i> hierachy; //層次n findContours(canny_output, controus, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0)); //尋找輪廓:輸入二值圖像,每個輪廓點都存儲到數組,輸出層次結構,輪廓檢索演算法(RETR_TREE多層次所有輪廓,RETR_EXTERNAL單層次外部輪廓),輪廓逼近演算法,輪廓點位移nn /*繪製輪廓*/n dst = Mat::zeros(src.size(), CV_8UC3);nRNG rng(12345);nfor (size_t i = 0; i < controus.size(); i++) {nScalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)); //顏色隨機n drawContours(dst, controus, i, color, 2, 8, hierachy, 0, Point(0, 0));//繪製輪廓:輸入,輪廓點,輪廓索引號,顏色,線寬,線類型,層次,最大層數0隻繪製當前的,輪廓位移n }n imshow(output_win, dst); //顏色相同的部分屬於同一個輪廓nn}n

運行結果:

以下各種圖結果的輪廓檢索演算法不同,各個的第一幅是RETR_TREE多層次所有輪廓,第二幅是RETR_EXTERNAL單層次外部輪廓:

推薦閱讀:

想用OpenCV做AR該如何入手?
opencv和pcl的區別?
OpenCV 與 OpenGL 的關係是什麼?
OpenCV玩九宮格數獨(零)——預告篇
【小林的OpenCV基礎課 0】一切為了學習!

TAG:OpenCV | 图像处理 | 计算机视觉 |