opencv学习笔记28-轮廓周围绘制矩形框和圆形框

只用来记录学习笔记

在这里插入图片描述

Douglas-Peucker算法:

  1. 在曲线首尾两点间虚连一条直线,求出其余各点到该直线的距离,如右图(1)。
  2. 选其最大者与阈值相比较,若大于阈值,则离该直线距离最大的点保留,否则将直线两端点间各点全部舍去,如右图(2),第4点保留。
  3. 依据所保留的点,将已知曲线分成两部分处理,重复第1、2步操作,迭代操作,即仍选距离最大者与阈值比较,依次取舍,直到无点可舍去,最后得到满足给定精度限差的曲线点座标,如图(3)、(4)依次保留第6点、第7点,舍去其他点,即完成线的化简。

approxPolyDP(InputArray curve, OutputArray approxCurve, double epsilon, bool closed)

代码:(函数的解释全部写在注释中了)

定义:

Mat src, gray_src, temp, dst;
const char* input_title = "input";
const char* output_title = "output";
const char* trackbar_title = "output";
int threshold_value = 170;
int threshold_max = 255;
RNG rng(12345);
void Contours_Callback(int, void*);

主函数:

	int main(int argc, char** argv) {
	src = imread("C:/Users/Administrator/Pictures/p234.jpg");
	if (src.empty()) {
		cout << "no image" << endl;
		return -1;
	}
	namedWindow(input_title, CV_WINDOW_AUTOSIZE);
	namedWindow(output_title, CV_WINDOW_AUTOSIZE);
	imshow(input_title, src);

	cvtColor(src, gray_src, CV_BGR2GRAY); //转灰度图像
	blur(gray_src, gray_src, Size(3, 3), Point(-1, -1)); //模糊

	createTrackbar(trackbar_title, output_title, &threshold_value, threshold_max, Contours_Callback);//滑块改变阈值
	Contours_Callback(0, 0);

	waitKey(0);
	return 0;
}

方法:

void Contours_Callback(int, void*) {
	Mat binary_output;
	vector<vector<Point>> contours;  //轮廓集合,每个轮廓用点的集合表示
	vector<Vec4i> hierachy;

	threshold(gray_src, binary_output, threshold_value, threshold_max, THRESH_BINARY);//阈值操作
	findContours(binary_output, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(-1, -1));//轮廓发现

	vector<vector<Point>> contours_ploy(contours.size()); //折线结合,每个折线用点集表示
	vector<Rect> ploy_rects(contours.size()); //正矩形集合
	vector<Point2f> ccs(contours.size()); //圆心
	vector<float> radius(contours.size()); //半径
	vector<RotatedRect> minRects(contours.size());  //RotatedRect:包含中心点座标,以及矩形的长度和宽度还有矩形的偏转角度
	vector<RotatedRect> myellipse(contours.size()); //RotatedRect:包含中心点座标,以及矩形的长度和宽度还有矩形的偏转角度
	
	for (size_t i = 0; i < contours.size(); i++) { //循环所有轮廓
		approxPolyDP(Mat(contours[i]), contours_ploy[i], 3, true);  //多边拟合函数 ,目的是减少
		//Mat(contours[i]):输入曲线,数据类型可以为vector<Point>
		//contours_ploy[i]:输出折线,数据类型可以为vector<Point>
		//3:判断点到相对应的line segment 的距离的阈值。(距离大于此阈值则保留,小于此阈值则舍弃,epsilon越小,折线的形状越“接近”曲线。)
		//true:曲线是否闭合的标志位
		ploy_rects[i]=boundingRect(contours_ploy[i]);//计算轮廓的垂直边界最小矩形,矩形是与图像上下边界平行的
		minEnclosingCircle(contours_ploy[i], ccs[i], radius[i]); //寻找最小包围圆形
		//contours_ploy[i]:输入折线
		//ccs[i]:圆心
		//radius[i]:半径

		if (contours_ploy[i].size() > 5) { //只有大于等于6条线的才能拟合成椭圆
			myellipse[i] = fitEllipse(contours_ploy[i]); //二维点集的椭圆拟合,用椭圆将二维点包含起来
			minRects[i] = minAreaRect(contours_ploy[i]);//最小区域边界斜矩形
		}	
	}

	//绘制
	src.copyTo(dst);
	Point2f pts[4];
	for (size_t t = 0; t < contours.size(); t++) {//循环所有轮廓
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)); 
		//rectangle(dst, ploy_rects[t], color, 1, 8); //绘制正矩形框
		//circle(dst, ccs[t], radius[t], color, 1, 8);//绘制最小包围圆

		ellipse(dst, myellipse[t], color, 1, 8); //绘制椭圆
		minRects[t].points(pts);
		for (int r = 0; r < 4; r++) {//绘制斜矩形
			line(dst, pts[r], pts[(r + 1) % 4], color, 1, 8);
		}
	}
	imshow(output_title, dst);
}

效果图:(绘制正矩形和最小包围圆的代码已经注释掉了)
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章