说明 以指定的精度逼近多边形曲线。输出一个在给定的范围内逼近一个轮廓的每个位置的位置坐标。
函数cv :: approxPolyDP用一条具有较少顶点的曲线或多边形逼近一条曲线或多边形,以使它们之间的距离小于或等于指定的精度。它使用Douglas-Peucker算法
声明
void approxPolyDP( InputArray curve, OutputArray approxCurve, double epsilon, bool closed );参数
curve存储在std :: vector或Mat中的二维点的输入向量;一般是由图像的轮廓点组成的点集approxCurve近似结果。类型应与输入曲线的类型匹配;表示输出的多边形点集epsilon指定近似精度的参数。这是原始曲线与其近似值之间的最大距离。closed如果为true,则闭合近似曲线(已连接其第一个顶点和最后一个顶点)。否则,它不会关闭; 表示输出的多边形是否封闭说明 求包围二维点集的最小面积的圆使用迭代算法。
声明
void minEnclosingCircle( InputArray points, CV_OUT Point2f& center, CV_OUT float& radius );参数
points输入的2维点向量,保存在std::vector 或者Mat中center输出圆的圆心radius输出圆的半径说明 由一系列的2维向量拟合椭圆。
函数计算由一系列2维点拟合(用最小二乘法)出的椭圆。它返回内接椭圆的旋转矩形。开发人员应该记住,返回的ellipse/rotatedRect数据可能包含负索引,因为数据点接近包含Mat元素的边界。
声明
RotatedRect fitEllipse( InputArray points //输入的2维点向量,保存在std::vector 或者Mat中 ); 应用 int main() { Mat src = imread("D:/test/huahua.png", -1); imshow("src", src); pyrDown(src, src, Size(src.cols / 2, src.rows / 2), 4); imshow("pyrDown", src); //通过canny算法找轮廓 Mat canny; //void Canny( InputArray image, OutputArray edges, // double threshold1, double threshold2, // int apertureSize = 3, bool L2gradient = false ); // Canny(src, canny, 45, 127, 3, false); imshow("canny", canny); //寻找轮廓 vector<vector<Point>> contours; vector<Vec4i> hierachy; findContours(canny, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE,Point(-1,-1)); drawContours(src, contours, -1, Scalar(0, 0, 255), 2,8,hierachy); //定义圆形、方形、旋转矩形、椭圆的存储容器 //int sizes = contours.size(); //输出的多边形点集 vector<vector<Point>> contour_ploy(contours.size()); vector<Rect> rects_ploy(contours.size()); //存放圆的圆心 vector<Point2f> circle_centers(contours.size()); //存放圆的半径 vector<float> circle_radius(contours.size()); //存放旋转矩形 vector<RotatedRect> rotatedRect_ploy; vector<RotatedRect> ellipse_ploy; //将结果放在各自的容器中 for (int i = 0; i < contours.size(); i++) { //contour_ploy输出的多边形点集,与轮廓值最大相差5的每一个点的位置集 approxPolyDP(contours[i], contour_ploy[i], 5, true); //多边形点集的外接矩形 rects_ploy[i] = boundingRect(contour_ploy[i]); //每个轮廓的圆心和半径 minEnclosingCircle(contour_ploy[i], circle_centers[i], circle_radius[i]); if (contour_ploy[i].size() > 5) { //存放最小外接矩形 RotatedRect temp1 = minAreaRect(contour_ploy[i]); rotatedRect_ploy.push_back(temp1); RotatedRect temp2 = fitEllipse(contour_ploy[i]); ellipse_ploy.push_back(temp2); } } //定义最终绘制的图片 Mat draw_rect(src.size(), src.type(), Scalar::all(0)), draw_rotateRect(src.size(), src.type(), Scalar::all(0)), draw_circle(src.size(), src.type(), Scalar::all(0)), draw_ellipse(src.size(), src.type(), Scalar::all(0)); RNG rng(12345); for (int i = 0; i < contours.size(); i++) { Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)); rectangle(draw_rect, rects_ploy[i], color, 1, 8); circle(draw_circle, circle_centers[i], circle_radius[i], color, 1, 8); } imshow("draw_rect", draw_rect); imshow("draw_circle", draw_circle); //绘图椭圆形、旋转矩形 Point2f pot[4]; for (int i = 0; i < ellipse_ploy.size(); i++) { Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)); ellipse(draw_ellipse, ellipse_ploy[i], color, 1, 8); rotatedRect_ploy[i].points(pot); for (int j = 0; j < 4; j++) { line(draw_rotateRect, pot[j], pot[(j + 1) % 4], color); } } imshow("draw_ellipse", draw_ellipse); imshow("draw_rotateRect", draw_rotateRect); waitKey(); return 0; }const int w = 500; int levels = 3; vector<vector<Point> > contours; vector<Vec4i> hierarchy; static void on_trackbar(int, void*) { Mat cnt_img = Mat::zeros(w, w, CV_8UC3); int _levels = levels - 3; drawContours(cnt_img, contours, _levels <= 0 ? 3 : -1, Scalar(128, 255, 255),3, LINE_AA, hierarchy, std::abs(_levels)); imshow("contours", cnt_img); } int main(int argc, char** argv) { Mat img = Mat::zeros(w, w, CV_8UC1); //Draw 6 faces for (int i = 0; i < 6; i++) { int dx = (i % 2) * 250 - 30; int dy = (i / 2) * 150; const Scalar white = Scalar(255); const Scalar black = Scalar(0); if (i == 0) { for (int j = 0; j <= 10; j++) { double angle = (j + 5) * CV_PI / 21; line(img, Point(cvRound(dx + 100 + j * 10 - 80 * cos(angle)), cvRound(dy + 100 - 90 * sin(angle))), Point(cvRound(dx + 100 + j * 10 - 30 * cos(angle)), cvRound(dy + 100 - 30 * sin(angle))), white, 1, 8, 0); } } ellipse(img, Point(dx + 150, dy + 100), Size(100, 70), 0, 0, 360, white, -1, 8, 0); ellipse(img, Point(dx + 115, dy + 70), Size(30, 20), 0, 0, 360, black, -1, 8, 0); ellipse(img, Point(dx + 185, dy + 70), Size(30, 20), 0, 0, 360, black, -1, 8, 0); ellipse(img, Point(dx + 115, dy + 70), Size(15, 15), 0, 0, 360, white, -1, 8, 0); ellipse(img, Point(dx + 185, dy + 70), Size(15, 15), 0, 0, 360, white, -1, 8, 0); ellipse(img, Point(dx + 115, dy + 70), Size(5, 5), 0, 0, 360, black, -1, 8, 0); ellipse(img, Point(dx + 185, dy + 70), Size(5, 5), 0, 0, 360, black, -1, 8, 0); ellipse(img, Point(dx + 150, dy + 100), Size(10, 5), 0, 0, 360, black, -1, 8, 0); ellipse(img, Point(dx + 150, dy + 150), Size(40, 10), 0, 0, 360, black, -1, 8, 0); ellipse(img, Point(dx + 27, dy + 100), Size(20, 35), 0, 0, 360, white, -1, 8, 0); ellipse(img, Point(dx + 273, dy + 100), Size(20, 35), 0, 0, 360, white, -1, 8, 0); } //show the faces namedWindow("image", 1); imshow("image", img); //Extract the contours so that vector<vector<Point> > contours0; findContours(img, contours0, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE); contours.resize(contours0.size()); for (size_t k = 0; k < contours0.size(); k++) approxPolyDP(Mat(contours0[k]), contours[k], 3, true); namedWindow("contours", 1); createTrackbar("levels+3", "contours", &levels, 7, on_trackbar); on_trackbar(0, 0); waitKey(); return 0; }
学习:
OpenCV学习三十:approxPolyDP 多边拟合函数 OpenCV中几何形状识别与测量 opencv 轮廓特征椭圆拟合
opencv python 轮廓特征/凸包/外接矩形/外接圆/拟合矩形/拟合直线/拟合圆
