一、图像的轮廓检测

 轮廓检测函数:
findContours(lnputArray image, OutputArrayOfArrays contours,OutputArray hierarchy, int mode, int method, Point offset = Point())
image:输入图像,数据类型为CV_8U的单通道灰度图像或者二值化图像。contours:检测到的轮廓,每个轮廓中存放着像素的坐标。
 mode:轮廓检测模式标志。
 method:轮廓逼近方法标志。
 offset:每个轮廓点移动的可选偏移量。这个函数主要用在从ROI图像中找出的轮廓并基于整个图像分析轮廓的场景中。
 轮廓绘制函数:
drawContours(InputoutputArray image, lnputArrayOfArrays contours,int contourldx, const Scalar & color, int thickness = 1, int lineType = LINE_8,hierarchy =, lnputArray noArray (), int maxLevel = INT_PAX, Point offset = Point())
image:绘制轮廓的目标图像。
 contours:所有将要绘制的轮廓。
 contourldx:要绘制的轮廓的参数,如果是负数,则绘制所有的轮廓。
 color:绘制轮廓的颜色。
 应用案例代码如下:
int main() {
	//更改输出界面的颜色
	system("color F0");
	//读取图片
	Mat src = imread("图片1.png");
	if (src.empty())
	{
		printf("不能打开空图片");
		return -1;
	}
	Mat gray, binary;
	//转化为灰度图
	cvtColor(src, gray, COLOR_BGR2GRAY);
	//高斯平滑滤波
	GaussianBlur(gray, gray, Size(13, 13), 4, 4);
	//自适应二值化
	threshold(gray, binary, 170, 255, THRESH_BINARY | THRESH_OTSU);
	//轮廓检测
	vector<vector<Point>>contours;
	//存放轮廓结构变量
	vector<Vec4i>hierarchy;
	findContours(binary, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point());
	//绘制轮廓
	for (int i = 0; i < hierarchy.size(); i++)
	{
		cout << hierarchy[i] << endl;
	}
	for (int t = 0; t < contours.size(); t++)
	{
		drawContours(src, contours, -1, Scalar(0, 0, 255), 2, 6);
		imshow("q", src);
		waitKey(0);
	}
	//输出轮廓结构描述
	return 0;
}
二、轮廓信息统计
轮廓面积计算函数:
contourArea(lnputArray contour, bool oriented = false)
contour:轮廓的像素点。
 oriented:区域面积是否具有方向的标志,true表示面积具有方向性,false表示不具有方向性,默认值为不具有方向性的false。
 轮廓长度计算函数:
arcLength(InputArray curve, bool closed)
curve:轮廓或者曲线的2D像素点。
 closed:轮廓或者曲线是否闭合标志,true表示闭合。
 应用案例如下:
int main() {
	//更改输出界面的颜色
	system("color F0");
	//读取图片
	Mat src = imread("图片1.png");
	if (src.empty())
	{
		printf("不能打开空图片");
		return -1;
	}
	Mat gray, binary;
	//转化为灰度图
	cvtColor(src, gray, COLOR_BGR2GRAY);
	//高斯平滑滤波
	GaussianBlur(gray, gray, Size(13, 13), 4, 4);
	//自适应二值化
	threshold(gray, binary, 170, 255, THRESH_BINARY | THRESH_OTSU);
	//轮廓检测
	vector<vector<Point>>contours;
	//存放轮廓结构变量
	vector<Vec4i>hierarchy;
	findContours(binary, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point());
	//输出轮廓面积
	for (int i = 0; i < contours.size(); i++)
	{
		double area1 = contourArea(contours[i]);
		cout << area1 << endl;
	}
	//输出轮廓长度
	for (int i = 0; i < contours.size(); i++)
	{
		double length1 = arcLength(contours[i], true);
		cout << length1 << endl;
	}
	return 0;
}
三、轮廓外接多边形拟合
轮廓外接矩形函数:
boundingRect(lnputArray array)
轮廓最小面积外界矩形:
minAreaRect(lnputArray points)
array:输入的灰度图像或者2D点集,数据类型为vector或者Mat。
轮廓多边形拟合:
approxPolyDP(InputArray curve, OutputArray approxCurve,double epsilon, bool closed)
curve:输入轮廓像素点。
 approxCurve:多边形逼近结果,以多边形顶点坐标的形式给出。
 epsilon:逼近的精度,即原始曲线和逼近曲线之间的最大距离。
 closed:逼近曲线是否为封闭曲线的标志,true表示曲线封闭,即最后一个顶点与第一个顶点相连。
 轮廓外接矩形函数、轮廓最小面积外界矩形应用案例:
int main() {
	//读取图片
	Mat src = imread("图片1.png");
	if (src.empty())
	{
		printf("不能打开空图片");
		return -1;
	}
	//深拷贝两张图像,用来做不同的外接图形操作
	Mat img1, img2;
	src.copyTo(img1);
	src.copyTo(img2);
	
	//canny的边缘检测
	Mat canny;
	Canny(src, canny, 80, 160, 3, false);
	//膨胀运算,去除细小缝隙
	Mat kernel = getStructuringElement(0, Size(3, 3));
	dilate(canny, canny, kernel);
	//轮廓检测
	vector<vector<Point>>contours;
	//存放轮廓结构变量
	vector<Vec4i>hierarchy;
	findContours(canny, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point());
	//寻找轮廓的外接矩形
	for (int n = 0; n < contours.size(); n++)
	{
		//最大外接矩形
		Rect rect = boundingRect(contours[n]);
		rectangle(img1, rect, Scalar(0, 0, 255), 2, 8, 0);
		//最小外接矩形
		RotatedRect rrect = minAreaRect(contours[n]);
		Point2f points[4];
		
		//读取最小外接矩形的四个顶点
		rrect.points(points);
		//最小外接矩形中心
		Point2f cpt = rrect.center;
		//绘制转转矩形与中心位置
		for (int i = 0; i < 4; i++)
		{
			if (i == 3)
			{
				line(img2, points[i], points[0], Scalar(0, 255, 0), 2, 8, 0);
				break;
			}
			line(img2, points[i], points[i+1], Scalar(0, 255, 0), 2, 8, 0);
		}
		//绘制矩形中心
		circle(img2, cpt, 4, Scalar(255, 0, 0), -1, 8, 0);
		imshow("q", img1);
		imshow("w", img2);
		waitKey(0);
		return 0;
	}
}
轮廓多边形拟合应用案例:
void drawapp(Mat result, Mat img2)
{
	for (int n = 0; n < result.rows; n++)
	{
		//将第一个点与最后一个点相连
		if (n == result.rows - 1)
		{
			Vec2i point1 = result.at<Vec2i>(n);
			Vec2i point2 = result.at<Vec2i>(0);
			line(img2, point1, point2, Scalar(0, 255, 0), 2, 8, 0);
			break;
		}
		Vec2i point1 = result.at<Vec2i>(n);
		Vec2i point2 = result.at<Vec2i>(n + 1);
		line(img2, point1, point2, Scalar(0, 255, 0), 2, 8, 0);
	}
}
int main() {
	//读取图片
	Mat src = imread("图片1.png");
	if (src.empty())
	{
		printf("不能打开空图片");
		return -1;
	}
	
	//canny的边缘检测
	Mat canny;
	Canny(src, canny, 80, 160, 3, false);
	//膨胀运算,去除细小缝隙
	Mat kernel = getStructuringElement(0, Size(3, 3));
	dilate(canny, canny, kernel);
	//轮廓检测
	vector<vector<Point>>contours;
	//存放轮廓结构变量
	vector<Vec4i>hierarchy;
	findContours(canny, contours, hierarchy, 0, 2, Point());
	//绘制多边形
	for (int i = 0; i < contours.size(); i++)
	{
		//用最小外接矩形求取轮廓中心
		RotatedRect rrect = minAreaRect(contours[i]);
		//最小外接矩形中心
		Point2f cpt = rrect.center;
		circle(src, cpt, 2, Scalar(255, 0, 0), 2, 8, 0);
		Mat result;
		//进行多边形拟合
		approxPolyDP(contours[i], result, 4, true);
		//绘制多边形
		drawapp(result, src);
	}
	imshow("q", src);
	waitKey(0);
	return 0;
}


















