Canny等边缘检测算可以根据求导等计算差异来检测边缘,但是无法将轮廓合成一个整体,轮廓发现是奖边缘像素合成轮廓。
CHAIN_APPROX_TC89_KCOS
CHAIN_APPROX_TC89_L1
使用Teh-Chin链逼近算法hierarchy向量内每一个元素的4个int型变量——hierarchy[i][0] ~hierarchy[i][3],分别表示第i个轮廓 同级的下一条轮廓、同级的前一条轮廓、下级的第一个子节点、上级父节点。如果当前轮廓没有 同级的下一条轮廓、同级的前一条轮廓、下级的第一个子节点、上级父节点,则hierarchy[i][0] ~hierarchy[i][3]的相应位被设置为默认值-1。
实战演练:
#include<opencv2/opencv.hpp> #include<opencv2/core/mat.hpp> #include<iostream> #include<vector> using namespace std; using namespace cv; int threshold_value = 153; int threshild_max = 255; RNG rng; void Demo_Contours(int, void*); Mat src,dst; const char* output_image = "findcountours_demo"; int main() { src = imread("C:/Users/LBJ/Desktop/OpenCVTest/fish.jpg"); if (!src.data ) { cout << "The iamge is empty" << endl; return -1; } namedWindow(output_image, WINDOW_AUTOSIZE); namedWindow("Input_Image", WINDOW_AUTOSIZE); imshow("Input_Image", src); cvtColor(src, src, CV_BGR2GRAY); const char* tracker_label = "Threshold Value:"; createTrackbar(tracker_label, output_image, &threshold_value, threshild_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)); } for (size_t i = 0; i < hierachy.size(); i++) { cout << hierachy[i] << endl; } imshow(output_image, dst); }可以用轮廓间的关系定位二维码的三个定位点,他们都有两个子轮廓
#include<opencv2/opencv.hpp> #include<opencv2/core/mat.hpp> #include<iostream> #include<vector> using namespace std; using namespace cv; int threshold_value = 153; Mat src, dst; const char* output_image = "findcountours_demo"; int main() { src = imread("C:/Users/LBJ/Desktop/OpenCVTest/二维码.jpg"); if (!src.data) { cout << "The iamge is empty" << endl; return -1; } namedWindow(output_image, WINDOW_AUTOSIZE); namedWindow("Input_Image", WINDOW_AUTOSIZE); imshow("Input_Image", src); GaussianBlur(src, src, Size(5, 5), 0, 0); cvtColor(src, src, CV_BGR2GRAY); threshold(src, src, 0, 255, THRESH_BINARY | THRESH_OTSU); vector<Point> point; Mat canny_output; vector<vector<Point>> contours; vector<Vec4i> hierachy; Canny(src, canny_output, threshold_value, threshold_value * 2, 3, false); imshow("Canny_imge", canny_output); findContours(canny_output, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0)); int k=0; dst = Mat::zeros(src.size(), CV_8UC3); for (size_t i = 0; i < contours.size(); i++) { int j = i, temp = 0; while (hierachy[j][2] != -1) { temp++; j = hierachy[j][2]; } if (temp >= 4) { drawContours(dst, contours, i, Scalar(0, 0, 255), -1, 8, hierachy, 0, Point(0, 0)); cout << contours[i] << endl; } else { drawContours(dst, contours, i, Scalar(255, 255, 255), 1, 8, hierachy, 0, Point(0, 0)); } } imshow(output_image, dst); waitKey(0); return 0; }
void convexHull( InputArray points, OutputArray hull,//输入点来自findContours 输出凸包 bool clockwise = false, bool returnPoints = true ); //顺时针方向 //true表示返回点个数
用RDP算法,使轮廓的顶点数变少。
void approxPolyDP( InputArray curve, OutputArray approxCurve, double epsilon, //两点间的最小距离 bool closed ); //是否形成闭合曲线中心位置 x=m10/m00 y=y01/y00
//计算矩,返回的位Moments结构体,包括0-3阶 m,mu,nu。 Moments moments( InputArray array, bool binaryImage = false );//输入数据,是否是二值图像 //计算面积 double contourArea( InputArray contour, bool oriented = false ); //输入轮廓数据,返回绝对值 //计算长度 double arcLength( InputArray curve, bool closed ); //输入轮廓曲线,是否是封闭曲线。