好久沒有更新了,原諒自己放了個假最近又在趕進度,所以。。。更新的內容是很靠后的第八章,因為最近工作要用就先跳了,后面會更新筆記編號。。。加油加油!
在二值圖像中尋找輪廓
void cv::findContours ( InputOutputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset = Point() )
- image: 輸入圖像,需為8位單通道圖像,圖像非0像素視為1。 可以用compare(), imrange(), threshold(), adaptivethreshold(), canny()等函數創建,注意:此函數會在提取圖像輪廓的同時修改圖像內容。
- If mode equals to RETR_CCOMP or RETR_FLOODFILL, the input can also be a 32-bit integer image of labels (CV_32SC1).
- contours: 檢測到的輪廓,每個輪廓存儲為一個點向量,即用point類型的vector,例如可為類型vector<vector<Point> >。
- hierarchy: 可選的輸出向量,包含圖像的拓撲信息。 每個輪廓contours[i],
- hierarchy[i][0] , 后一個輪廓,
- hierarchy[i][1] , 前一個輪廓,
- hierarchy[i][2] , 父輪廓,
- hierarchy[i][3], 內嵌輪廓的索引編號。
- 如果沒有對應項,hierarchy[i]中的對應項設為負數。
- mode: 檢索模式,可選模式包括
- RETR_EXTERNAL: 只監測最外層輪擴。hierarchy[i][2] = hierarchy[i][3] = -1
- RETR_LIST: 提取所有輪廓,並放置在list中。檢測的輪廓不建立等級關系。
- RETR_CCOMP: 提取所有輪廓,並將其組織為雙層結構,頂層為聯通域的外圍邊界,次層為空的內層邊界。
- RETR_TREE: 提取所有輪廓,並重新建立網狀的輪廓結構。
- method: 輪廓的近似辦法,包括
- CHAIN_APPROX_NONE: 獲取每個輪廓的每個像素,相鄰兩點像素位置差不超過1,max(abs(x1-x2),abs(y1-y2)) == 1
- CHAIN_APPROX_SIMPLE: 壓縮水平方向,垂直方向,對角線方向的元素,只保留該方向的終點坐標
- CHAIN_APPROX_TC89_LI /CHAIN_APPROX_TC89_KCOS: 使用Teh-Chinl鏈逼近算法中的一個
- [135] C-H Teh and Roland T. Chin. On the detection of dominant points on digital curves. Pattern Analysis and Machine Intelligence, IEEE Transactions on, 11(8):859–872, 1989.
- offSet: 每個輪廓點的可選偏移量,默認Point(), 當ROI圖像中找出的輪廓需要在整個圖中進行分析時,可利用這個參數。
繪制輪廓
void cv::drawContours ( InputOutputArray image, InputArrayOfArrays contours, int contourIdx, const Scalar & color, int thickness = 1, int lineType = LINE_8, InputArray hierarchy = noArray(), int maxLevel = INT_MAX, Point offset = Point() )
- image: 目標圖像
- contours: 輸入輪廓,每個輪廓存儲為一個點向量
- contourIdx: 需要繪制的輪廓的編號,如果為負,繪制所有輪廓
- color: 輪廓顏色
- thickness: 輪廓線條粗細度,如果為負值(如thickness==cv_filled),繪制在輪廓內部
- lineType: 線條類型
- 8: 8連通線型
- 4: 4連通線型
- LINE_AA (OpenCV2: CV_AA): 抗鋸齒線型
- hierarchy: 可選層次結構
- maxLevel: 繪制輪廓的最大等級
- offset: 可選輪廓偏移參數
事例程序1
#include <opencv2/opencv.hpp> #include <opencv2/highgui/highgui.hpp> #include <vector> // main int main( int argc, char** argv ) { // loading image cv::Mat srcImage = cv::imread("1.jpg", 0); imshow("original image", srcImage); // initialize result image cv::Mat dstImage = cv::Mat::zeros(srcImage.rows, srcImage.cols, CV_8UC3); // thresholding image srcImage = srcImage > 119; imshow("thresholding image", srcImage); // finding contours std::vector<std::vector<cv::Point> > contours; std::vector<cv::Vec4i> hierarchy; // for opencv 2 // cv::findContours(srcImage, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE); // for opencv 3 cv::findContours(srcImage, contours, hierarchy, cv::RETR_CCOMP, cv::CHAIN_APPROX_SIMPLE); // iterate through all levels, and draw contours in random color int index = 0; for (; index>=0; index = hierarchy[index][0]) { cv::Scalar color(rand()&255, rand()&255, rand()&255); // for opencv 2 // cv::drawContours(dstImage, contours, index, color, CV_FILLED, 8, hierarchy); // for opencv 3 cv::drawContours(dstImage, contours, index, color, cv::FILLED, 8, hierarchy); imshow("contours", dstImage); cv::waitKey(150); } cv::imwrite("result.jpg", dstImage); return 0; }
1.jpg
result.jpg
事例程序2
#include <opencv2/opencv.hpp> #include <opencv2/highgui/highgui.hpp> #include <iostream> #include <vector> #define WINDOW_NAME1 "original image" #define WINDOW_NAME2 "contours" // global variables cv::Mat g_srcImage; cv::Mat g_grayImage; cv::Mat g_cannyMat_output; int g_nThresh = 80; int g_nThresh_max = 255; cv::RNG g_rng(12345); std::vector<std::vector<cv::Point> > g_vContours; std::vector<cv::Vec4i> g_vHierarchy; // functions void on_ThreshChange(int, void*); // main int main( int argc, char** argv ) { // change the text color of console system("color 1F"); // loading image g_srcImage = cv::imread("1.jpg", 1); if (!g_srcImage.data){ std::cerr << "ERROR while loading image." << std::endl; return false; } // convert to gray-scale and blur cv::cvtColor(g_srcImage, g_grayImage, cv::COLOR_BGR2GRAY); cv::blur(g_grayImage, g_grayImage, cv::Size(3,3)); // create window cv::namedWindow(WINDOW_NAME1, cv::WINDOW_AUTOSIZE); imshow(WINDOW_NAME1, g_srcImage); // create tracker bar cv::createTrackbar("Canny Threshold", WINDOW_NAME1, &g_nThresh, g_nThresh_max, on_ThreshChange); on_ThreshChange(0, 0); cv::waitKey(0); return 0; } void on_ThreshChange(int, void*) { cv::Canny(g_grayImage, g_cannyMat_output, g_nThresh, g_nThresh*2, 3); cv::findContours(g_cannyMat_output, g_vContours, g_vHierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE); cv::Mat drawing = cv::Mat::zeros(g_cannyMat_output.size(), CV_8UC3); for (int i = 0; i<g_vContours.size(); i++) { cv::Scalar color(g_rng.uniform(0, 255), g_rng.uniform(0, 255), g_rng.uniform(0, 255)); cv::drawContours(drawing, g_vContours, i, color, 2, 8, g_vHierarchy); } imshow(WINDOW_NAME2, drawing); }
結果圖: