一、什么是轮廓
轮廓可以简单认为成将连续的点(连着边界)连在一起的曲线,具有相同的颜色或者灰度。轮廓在形状分析和物体的检测和识别中很有用。
二、如何寻找轮廓
- 为了更加准确,要使用二值化图像。在寻找轮廓之前,要进行阈值化处理或者 Canny 边界检测。
- 查找轮廓的函数会修改原始图像。如果你在找到轮廓之后还想使用原始图像的话,你应该将原始图像存储到其他变量中。
- 在 OpenCV 中,查找轮廓就像在黑色背景中超白色物体。你应该记住,要找的物体应该是白色而背景应该是黑色
findContour函数简介
虽然然canny之类的边缘检测算法可以根据像素间的差异检测出轮廓边界的像素,但是它并没有将轮廓作为一个整体。下一步是要把这些像素组装成轮廓,这个函数就是findcontours()
void findContours( InputArray image, OutputArrayOfArrays contours,
OutputArray hierarchy, int mode,
int method, Point offset = Point());
contours:为获取的轮廓信息,轮廓信息定义务必是vector<vector<Point>> 形式的
hierarchy:为层级关系,定义为vector<Vec4i>和Mat都可以。每个轮廓有四个层级信息,分别为:上一个轮廓序号、下一个轮廓序号、子轮廓序号、父轮廓序号
mode :官方是“轮廓检索算法的模式”,可以理解为获取怎样的层级信息
method:定义轮廓的近似方法
offset:偏移量,所有的轮廓信息相对于原始图像对应点的偏移量,相当于在每一个检测出的轮廓点上加上该偏移量,并且Point还可以是负值
三、绘制轮廓
drawContours
主要流程
1、加载源图像
2、转成灰度图并模糊化降噪
3、用Canny算子检测边缘,得到二值图像
4、使用findContours寻找轮廓
5、使用drawContours绘出轮廓图
例子
#include <iostream>
#include <vector>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
using namespace cv;
using std::vector;
int main()
{
cv::Mat srcImage; //原始图像
srcImage = cv::imread("F:\\4.jpg");
if (!srcImage.data)
{
std::cout << "read image error!" << std::endl;
return -1;
}
cv::imshow("srcImage", srcImage);
//1.灰度转换
cv::Mat gray;
cv::cvtColor(srcImage, gray, CV_RGB2GRAY);
cv::imshow("gray", gray);
//2.二值化
cv::Mat binary;
cv::threshold(gray, binary, 150, 255, cv::THRESH_BINARY_INV); //65.255(会导致出错,这里要选择合适的阈值) 220.255
cv::imshow("binary", binary);
//3.定义轮廓和层次机构
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
//4.轮廓查找
cv::findContours(binary, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE);
int index = 0;
for (; index >= 0; index = hierarchy[index][0])
{
//cv::Scalar color(rand()&255, rand()&255, rand()&255);
//5.轮廓绘制
//cv::drawContours(binary, contours, index, cv::Scalar(255), 2,8,hierarchy,0,Point());
//cv::drawContours(binary, contours, -1, cv::Scalar(255)); //法1
cv::Mat dst(srcImage.size(),CV_8U,cv::Scalar(0)); //法2
cv::drawContours(dst,contours,index,cv::Scalar(255),CV_FILLED); //法3
}
cv::drawContours(binary, contours, -1, cv::Scalar(255));
waitKey(0);
return 0;
}
参考:
https://blog.csdn.net/juliarjuliar/article/details/84030500