日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

OpenCV学习笔记(十七):查找并绘制轮廓:findContours(),drawContours(),approxPolyDP()

發布時間:2024/7/23 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 OpenCV学习笔记(十七):查找并绘制轮廓:findContours(),drawContours(),approxPolyDP() 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

OpenCV學習筆記(十七):查找并繪制輪廓:findContours()

1、findContours() 函數

該函數使用Suzuki85算法從二值圖像中檢索輪廓。輪廓線是一種用于形狀分析、目標檢測和識別的有效工具。
opencv輪廓檢測之FindContours函數算法解釋
該函數從二值圖像中檢索輪廓,并返回檢索到的輪廓數。函數將填充指針first_contour。它將包含指向第一個最外層輪廓的指針,如果沒有檢測到輪廓,則為空(如果圖像是完全黑色的)。可以使用h_next和v_next鏈接從first_contour到達其他輪廓。繪制等值線討論中的示例說明了如何使用等值線進行連接組件檢測。輪廓還可以用于形狀分析和對象識別-請參閱OpenCV示例目錄中的squares.c。

void findContours( InputOutputArray image, // 要繪制輪廓的圖像,8位單通道的圖像(256級灰度圖) OutputArrayOfArrays contours, // 所有輸入的輪廓,找到的輪廓,其中每個輪廓會被存儲為vector<Point>,// 所以contours的類型就是vector<vector<Point>>。 OutputArray hierarchy, // 層次結構,可選的輸出向量,包含關于圖像的拓撲結構信息。// 其具有跟輪廓數相同的元素個數,類型為vector<Vec4i>// 后一個輪廓、前一個輪廓、第一個子輪廓、父輪廓的索引編號,如果沒有對應項,該值設置為-1 int mode, // 檢索輪廓的模式分別表示 int method, // 為輪廓的近似辦法 Point offset=Point() // 代表輪廓點的偏移量,可以設置為任意值。 ); ==mode== RETR_EXTERNAL 表示只檢測外輪廓     RETR_LIST 檢測的輪廓不建立等級關系     RETR_CCOMP 建立兩個等級的輪廓,上面的一層為外邊界,里面的一層為內孔的邊 界信息。如果內孔內還有一個連通物體,這個物體的邊界也在頂層。     RETR_TREE 建立一個等級樹結構的輪廓。具體參考contours.c這個demo ==method== CHAIN_APPROX_NONE 存儲所有的輪廓點,相鄰的兩個點的像素位置差不超過1,即max(abs(x1-x2),abs(y2-y1))==1 CHAIN_APPROX_SIMPLE 壓縮水平方向,垂直方向,對角線方向的元素,只保留該方向的終點坐標,例如一個矩形輪廓只需4個點來保存輪廓信息 CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS 使用teh-Chinl chain 近似算法

2、drawContours()函數

該函數使用算法從二值圖像中檢索輪廓。繪制輪廓線或填充輪廓線。如果厚度≥0,該函數在圖像中繪制輪廓輪廓;如果厚度<0,則填充輪廓邊界區域。
參考博客:
輪廓的層級關系詳解
OpenCV中findcontours函數hierarchy輪廓層級詳解

void drawContours( InputOutputArray image, // 要繪制輪廓的圖像 InputArrayOfArrays contours, // 所有輸入的輪廓,每個輪廓被保存成一個point向量(vector<vector<Point>>) int contourIdx, // 指定要繪制輪廓的編號,如果是負數,則繪制所有的輪廓 const Scalar& color, // 繪制輪廓所用的顏色 int thickness=1, // 繪制輪廓的線的粗細,如果是負數,則輪廓內部被填充(CV_FILLED 填充內部) int lineType=8, // 繪制輪廓的線的連通性(LINE_AA 抗鋸齒線形) InputArray hierarchy=noArray(), // 關于層級的可選參數,只有繪制部分輪廓時才會用到(hierarchy=hierarchy,繪制所有輪廓) int maxLevel=INT_MAX, // 繪制輪廓的最高級別,這個參數只有hierarchy有效的時候才有效 Point offset=Point() // 代表輪廓點的偏移量,可以設置為任意值 ) ==maxLevel== maxLevel=0,繪制與輸入輪廓屬于同一等級的所有輪廓即輸入輪廓和與其相鄰的輪廓 maxLevel=1, 繪制與輸入輪廓同一等級的所有輪廓與其子節點。 maxLevel=2,繪制與輸入輪廓同一等級的所有輪廓與其子節點以及子節點的子節點

3、approxPolyDP()函數

以指定的精度近似生成多邊形曲線。
函數逼近一條曲線或另一條曲線/頂點較少的多邊形,使它們之間的距離小于或等于指定的精度。它使用Douglas-Peucker算法

void approxPolyDP( InputArray curve, // 輸入的點集(存儲在std::vector或Mat中的二維點的輸入向量) OutputArray approxCurve, // 輸出的點集,當前點集是能最小包容指定點集的。draw出來即是一個多邊形; double epsilon, // 指定的精度,也即是原始曲線與近似曲線之間的最大距離。 bool closed // 若為true,則說明近似曲線是閉合的,它的首位都是相連,反之,若為false,則斷開。 );

4、示例一:

#include <opencv2/opencv.hpp>using namespace cv; using namespace std;int main() {QCoreApplication a(argc, argv);// 1、加載源圖像//Mat srcImage = imread( "F:/C++/2. OPENCV 3.1.0/TEST/a.jpg", 1 );Mat srcImage = imread( "F:/C++/2. OPENCV 3.1.0/TEST/test3.png", 1 );if(!srcImage.data ) { printf("讀取圖片錯誤,請確定目錄下是否有imread函數指定圖片存在~! \n"); return false; }cvtColor(srcImage,srcImage,CV_BGR2GRAY);// 2、初始化結果圖Mat dstImage = Mat::zeros(srcImage.size(), CV_8UC3);Mat dstImage1 =dstImage.clone();// 3、srcImage取大于閾值119的那部分//threshold(srcImage,srcImage,119,255,THRESH_BINARY);srcImage = srcImage > 119; // 取 閾值大于119imshow( "取閾值后的原始圖", srcImage );// 4、定義輪廓和層次結構// 儲存所有輪廓(每個輪廓為一個點向量集)// 儲存每個輪廓的層次元素,hierarchy[i][0]~hierarchy[i][1] 分別表示后一個、前一個、父輪廓、內嵌輪廓的索引編號vector<vector<Point> > contours;vector<Vec4i> hierarchy;// 5、查找輪廓// RETR_EXTERNAL 表示只檢測外輪廓// RETR_LIST 檢測的輪廓不建立等級關系// RETR_CCOMP 建立兩個等級的輪廓,上面的一層為外邊界,里面的一層為內孔的邊 界信息。如果內孔內還有一個連通物體,這個物體的邊界也在頂層。// RETR_TREE 建立一個等級樹結構的輪廓。具體參考contours.c這個demo// CHAIN_APPROX_NONE 存儲所有的輪廓點,相鄰的兩個點的像素位置差不超過1,即max(abs(x1-x2),abs(y2-y1))==1// CHAIN_APPROX_SIMPLE 壓縮水平方向,垂直方向,對角線方向的元素,只保留該方向的終點坐標,例如一個矩形輪廓只需4個點來保存輪廓信息// CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS 使用teh-Chinl chain 近似算法findContours( srcImage, contours, hierarchy,CV_RETR_CCOMP ,CV_CHAIN_APPROX_SIMPLE );cout<<"輪廓數量:"<<contours.size()<<endl;// 6、遍歷所有頂層的輪廓, 以隨機顏色繪制出每個連接組件顏色// hierarchy[index][0] 表示該某輪廓點集的后一個輪廓點集 索引號// hierarchy[index][1] 表示該某輪廓點集的前一個輪廓點集 索引號// hierarchy[index][2] 表示該某輪廓點集的第一個子輪廓(內嵌)點集 索引號// hierarchy[index][3] 表示該某輪廓點集的父輪廓點集 索引號for( int index = 0; index >= 0; index = hierarchy[index][0] ) // 繪制輪廓//for( int index = 0; index < contours.size(); index ++ ) // 繪制所有內外輪廓{Scalar color( rand()&255, rand()&255, rand()&255 );drawContours( dstImage, contours, index, color, 1, 8,hierarchy ); //CV_FILLED}// // 7、檢測到的所有輪廓分別用不同顏色畫出來 // for(size_t j=0; j<contours.size(); j++) // { // Scalar color( rand()&255, rand()&255, rand()&255 ); // 為每個輪廓新建隨機顏色 // for (size_t i = 0; i < contours[j].size(); i++) // { // // 繪制邊緣 // line(dstImage1, contours[j][i], contours[j][(i + 1) % contours[j].size()], color, 1, 8); // } // }// 8、顯示最后的輪廓圖imshow( "輪廓圖", dstImage );//imshow( "邊緣圖", dstImage1 );waitKey(0);return 0; }

結果:


分析:
1)“0輪廓"的下一條輪廓是"1輪廓”;“1輪廓"的下一條"3輪廓”;
2)"2輪廓"和"3輪廓"的下一條沒有;
3)"0輪廓"和"2輪廓"上一條是-1表示沒有;
4)“1輪廓"的子輪廓是"2輪廓”,其他的輪廓沒有子輪廓。(1輪廓包含2輪廓)
5)"0、1、3輪廓"沒有父輪廓,說明其為最外層輪廓(且為同級輪廓)
PS:輪廓層次關系 看hierarchy[index][2]和hierarchy[index][3]的值

5、示例二:

#include <opencv2/opencv.hpp>using namespace cv; using namespace std;int levels = 3; // 精度等級 Mat img; RNG g_rng(12345); vector<vector<Point> > contours,contours0; vector<Vec4i> hierarchy;int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);// 1、 讀取圖片img = imread( "F:/C++/2. OPENCV 3.1.0/TEST/face.png", 0 );if(!img.data ) { printf("讀取圖片錯誤,請確定目錄下是否有imread函數指定圖片存在~! \n"); return false; }imshow( "image", img );// // 繪制6個人臉用于測試 // // 創建 500*500 單通道矩陣 灰度圖 // Mat img = Mat::zeros(w, w, CV_8UC1); // for( int i = 0; i < 6; i++ ) // { // int dx = (i%2)*250 - 30; // int dy = (i/2)*150; // const Scalar white = Scalar(255); // const Scalar black = Scalar(0); // if( i == 0 ) // { // for( int j = 0; j <= 10; j++ ) // { // double angle = (j+5)*CV_PI/21; // line(img, Point(cvRound(dx+100+j*10-80*cos(angle)), // cvRound(dy+100-90*sin(angle))), // Point(cvRound(dx+100+j*10-30*cos(angle)), // cvRound(dy+100-30*sin(angle))), white, 1, 8, 0); // } // } // ellipse( img, Point(dx+150, dy+100), Size(100,70), 0, 0, 360, white, -1, 8, 0 ); // ellipse( img, Point(dx+115, dy+70), Size(30,20), 0, 0, 360, black, -1, 8, 0 ); // ellipse( img, Point(dx+185, dy+70), Size(30,20), 0, 0, 360, black, -1, 8, 0 ); // ellipse( img, Point(dx+115, dy+70), Size(15,15), 0, 0, 360, white, -1, 8, 0 ); // ellipse( img, Point(dx+185, dy+70), Size(15,15), 0, 0, 360, white, -1, 8, 0 ); // ellipse( img, Point(dx+115, dy+70), Size(5,5), 0, 0, 360, black, -1, 8, 0 ); // ellipse( img, Point(dx+185, dy+70), Size(5,5), 0, 0, 360, black, -1, 8, 0 ); // ellipse( img, Point(dx+150, dy+100), Size(10,5), 0, 0, 360, black, -1, 8, 0 ); // ellipse( img, Point(dx+150, dy+150), Size(40,10), 0, 0, 360, black, -1, 8, 0 ); // ellipse( img, Point(dx+27, dy+100), Size(20,35), 0, 0, 360, white, -1, 8, 0 ); // ellipse( img, Point(dx+273, dy+100), Size(20,35), 0, 0, 360, white, -1, 8, 0 ); // }// 顯示 // namedWindow( "image", 1 ); // imshow( "image", img );// 2、提取輪廓findContours( img, contours0, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);// 3、對輪廓進行逼近 獲得多邊形曲線輪廓向量點集contours.resize(contours0.size());for( size_t k = 0; k < contours0.size(); k++ )approxPolyDP(Mat(contours0[k]), contours[k], 0.1, true);// 4、滑動條調用// 設置軌跡條,控制從-3到3的輪廓等級namedWindow( "contours", 1 );createTrackbar( "levels+3", "contours", &levels, 7, on_trackbar );on_trackbar(0,0);// 初次調用waitKey(0);return a.exec(); }

輪廓控制回調函數

static void on_trackbar(int, void*) {// 1、創建目標圖像Mat cnt_img = Mat::zeros(img.rows, img.cols, CV_8UC3);// 2、處理參數int _levels = levels - 3;// 3、繪制輪廓// _levels <= 0 ? 3 : -1Scalar color = Scalar( g_rng.uniform(0, 255), g_rng.uniform(0,255), g_rng.uniform(0,255) );//任意值drawContours( cnt_img, contours,_levels <= 0 ? 3 : -1, Scalar(128,255,255),1, LINE_AA, hierarchy, std::abs(_levels) ); imshow("contours", cnt_img); }

結果:


總結

以上是生活随笔為你收集整理的OpenCV学习笔记(十七):查找并绘制轮廓:findContours(),drawContours(),approxPolyDP()的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。