只用来记录学习笔记
Douglas-Peucker算法:
- 在曲线首尾两点间虚连一条直线,求出其余各点到该直线的距离,如右图(1)。
- 选其最大者与阈值相比较,若大于阈值,则离该直线距离最大的点保留,否则将直线两端点间各点全部舍去,如右图(2),第4点保留。
- 依据所保留的点,将已知曲线分成两部分处理,重复第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
//contours_ploy[i]:输出折线,数据类型可以为vector
//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);
}