Opencv实现边缘检测与轮廓发现及绘制轮廓方法详解
作者:以后的事,以后再说
简介
Opencv边缘检测、轮廓发现、绘制轮廓
提取图像轮廓的2个步骤
1、 findContours函数找轮廓,
2、 drawContours函数画轮廓
轮廓的查找
cv::findContours()
函数cv::findContour是从二值图像中来计算轮廓的,它可以使用cv::Canny()函数处理的图像,因为这样的图像含有边缘像素;也可以使用cv::threshold()或者cv::adaptiveThreshold()处理后的图像,其边缘隐含在正负区域的交界处。
轮廓的层级结构
下图所示了cv::findCountour()的基本功能,图的上部是一幅测试图像,其背景为白色,并含有数个彩色的的区域(标签A到E)。图中也绘制出了由cv::findContours()所确定的轮廓。这些轮廓被标记为cX或hX,其中c代表“contour(轮廓)”,h代表“洞(hole)”,而X是一些数字。有些轮廓使用虚线表示的,他们表示白色区域(即非零区域)的外部边界。OpenCV和cv::findContour()对这些外部边界和图中的点线,即内部边界或者是洞的外部边界,进行区分的。
如图的下半部分,OpenCV可以将找到的轮廓组织成轮廓树,表示其轮廓结构的包围关系。对于测试图像中的轮廓,我们将根节点处的轮廓称为c0,而“洞”h00和h01是其子节点。反过来这些子节点又会包含新的子节点以此类推。
表示这种树的方式有很多种,OpenCV中使用数组(尤其是vectors)来表示这种树,其中数组中的每个条目都代表一个特定的轮廓,每个条目包含一个由4个整数组成的集合(通常表示为cv :: Vec4i类型的元素,就像四通道数组中的条目一样)。对于每个节点来说,四个元素所表示的含义分别如下:0号元素表示下一个轮廓(同一层级);1号元素表示前一个轮廓(同一层级);2号元素表示第一个子轮廓(下一层级);3号元素表示父轮廓(上一层级)
drawContours函数的作用
主要用于画出图像的轮廓
函数的调用形式
void drawContours(InputOutputArray image, InputArrayOfArrays contours, int contourIdx, const Scalar& color, int thickness=1, int lineType=8, InputArray hierarchy=noArray(), int maxLevel=INT_MAX, Point offset=Point() )
函数参数详解:
其中第一个参数image表示目标图像,
第二个参数contours表示输入的轮廓组,每一组轮廓由点vector构成,
第三个参数contourIdx指明画第几个轮廓,如果该参数为负值,则画全部轮廓,
第四个参数color为轮廓的颜色,
第五个参数thickness为轮廓的线宽,如果为负值或CV_FILLED表示填充轮廓内部,
第六个参数lineType为线型,
第七个参数为轮廓结构信息,
第八个参数为maxLevel
代码演示
/* * 轮廓发现 * 1:输入图像转为灰度图像 * 2使用Canny进行边缘提取,得到二值图像 * 3使用findContours寻找轮廓 * 4使用drawContours绘制轮廓 * */ #include <opencv.hpp> #include<iostream> #include <string> #include<conio.h> #include<time.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() { src = imread("E:\\Users\\opencvCoder\\image\\niu.jpg"); if (src.empty()) { printf("could not load image...\n"); return -1; } imshow("input_image", src); namedWindow("input_image", 0); namedWindow(output_win, 1); cvtColor(src, src, COLOR_BGR2GRAY); imshow("gray_image", src); 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边缘检测的步骤: *1、去噪。噪声会影响边缘检测的准确性,因此首先要将噪声过滤掉。 *2、计算梯度大小和方向。 *3、非极大值抑制。就是适当的让边缘'变瘦'。 *4、确定边缘。使用双阈值法确定最终的边缘信息。 */ 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); //canny_output 为图像掩码,将非零值复制给dst src.copyTo(dst, canny_output); //图像取反输出 //imshow(output_win, ~dst); //正常输出 imshow("mask image", dst); }
到此这篇关于Opencv实现边缘检测与轮廓发现及绘制轮廓方法详解的文章就介绍到这了,更多相关Opencv边缘检测 内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!