opencv4 c++ 提取图片中的白色区域_【从零学习OpenCV 4】点集拟合

a4fde9250fcbe3adfc1f020e611dd269.png

本文首发于“小白学视觉”微信公众号,欢迎关注公众号

本文作者为小白,版权归人民邮电出版社发行所有,禁止转载,侵权必究!


经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门书籍《OpenCV 4开发详解》。为了更让小伙伴更早的了解最新版的OpenCV 4,小白与出版社沟通,提前在公众号上连载部分内容,请持续关注小白。

有时我们关注的区域是一些面积较小数目较多的连通域或者像素点,并且这些区域相对的集中在一起。此时如果寻找轮廓并对每个轮廓进行外接多边形逼近,结果会有较多的多边形。为了避免这个情况,我们可以将这些连通域或者像素点看成一个大的区域,此时我们可以寻找包围将这些区域的规则图形,例如三角形、圆形等,三角形包围2D点集的示意图如图7-27所示。本节将重点介绍如何寻找包围2D点集的规则图形,包括三角形和圆形。OpenCV 4提供了用于寻找包围2D点集的规则图形的函数,接下来将介绍这些函数的函数原型以及使用方法。

02e775d43bc1ce9ac30f3a8fed370cf3.png
图7-27 点集三角形拟合示意图

OpenCV 4提供了minEnclosingTriangle()函数用于寻找2D点集的最小包围三角形,函数的函数原型在代码清单7-34中给出。

代码清单7-34 minEnclosingTriangle()函数原型
1.  double cv::minEnclosingTriangle(InputArray  points,
2.                                        OutputArray  triangle 
3.                                        )
  • points:待寻找包围三角形的2D点集。
  • triangle:拟合出的三角形三个顶点坐标。

该函数能够找到包含给定2D点集的最小区域的三角形,函数返回值为double类型的三角形面积。函数只有两个参数,第一个参数是待寻找包围三角形的2D点集,2D点可以存放在vector<>或者Mat类型的变量中,数据类型为CV_32S或CV_32F;第二个参数是包含所有2D点的面积最小的三角形的三个顶点坐标,输出的数据类型为CV_32F,存放在vector类型的变量中。该函数的使用方式在代码清单7-36的示例程序中给出。

OpenCV 4还提供了minEnclosingCircle()函数用于寻找2D点集的最小包围圆形,该函数的函数原型在代码清单7-35中给出。

代码清单7-35 minEnclosingCircle()函数原型
1.  void cv::minEnclosingCircle(InputArray  points,
2.                                    Point2f &  center,
3.                                    float &  radius 
4.                                    )
  • points:待寻找包围圆形的2D点集。
  • center:圆形的圆心。
  • radius:圆形的半径。

该函数使用迭代算法寻找2D点集的最小包围圆形。函数的第一个参数是待寻找包围圆形的2D点集,2D点可以存放在vector<>或者Mat类型的变量中。函数第二个参数和第三个参数分别是2D点集最小包围圆的圆心和半径,圆心的数据类型为Point2f,半径的数据类型为float。该函数的使用方式在代码清单7-36的示例程序中给出。

在代码清单7-36的程序中随机生成100以内的点,并随机分布在图像中的指定区域内,之后通过minEnclosingTriangle()函数和minEnclosingCircle()函数寻找包围这些点的三角形和圆形。为了能够反复的查看结果,程序设置了while循环,直到按下“q”、“Q”或者“ESC”按键时程序跳出循环。程序的运行结果如图7-28所示,由于程序中像素点是随机生成的,因此每次运行结果会有不同。

代码清单7-36 myTriangleAndCircle.cpp点集外包轮廓
1.  #include <opencv2opencv.hpp>
2.  #include <iostream>
3.  #include <vector>
4.  
5.  using namespace cv;
6.  using namespace std;
7.  
8.  int main()
9.  {
10.     Mat img(500, 500, CV_8UC3, Scalar::all(0));
11.     RNG& rng = theRNG();  //生成随机点
12. 
13.     while (true)
14.     {
15.         int i, count = rng.uniform(1, 101);
16.         vector<Point> points;
17.         //生成随机点
18.         for (i = 0; i < count; i++)
19.         {
20.             Point pt;
21.             pt.x = rng.uniform(img.cols / 4, img.cols * 3 / 4);
22.             pt.y = rng.uniform(img.rows / 4, img.rows * 3 / 4);
23.             points.push_back(pt);
24.         }
25. 
26.         //寻找包围点集的三角形 
27.         vector<Point2f> triangle;
28.         double area = minEnclosingTriangle(points, triangle);
29. 
30.         //寻找包围点集的圆形
31.         Point2f center;
32.         float radius = 0;
33.         minEnclosingCircle(points, center, radius);
34. 
35.         //创建两个图片用于输出结果
36.         img = Scalar::all(0);
37.         Mat img2;
38.         img.copyTo(img2);
39. 
40.         //在图像中绘制坐标点
41.         for (i = 0; i < count; i++)
42.         {
43.             circle(img, points[i], 3, Scalar(255, 255, 255), FILLED, LINE_AA);
44.             circle(img2, points[i], 3, Scalar(255, 255, 255), FILLED, LINE_AA);
45.         }
46.             
47.         //绘制三角形
48.         for (i = 0; i < 3; i++)
49.         {
50.             if (i==2)
51.             {
52.                 line(img, triangle[i], triangle[0], Scalar(255, 255, 255), 1, 16); 
53.                 break;
54.             }
55.             line(img, triangle[i], triangle[i + 1], Scalar(255, 255, 255), 1, 16); 
56.         }
57. 
58.         //绘制圆形
59.         circle(img2, center, cvRound(radius), Scalar(255, 255, 255), 1, LINE_AA);
60. 
61.         //输出结果
62.         imshow("triangle", img);
63.         imshow("circle", img2);
64. 
65.         //按q键或者ESC键退出程序
66.         char key = (char)waitKey();
67.         if (key == 27 || key == 'q' || key == 'Q')
68.         {
69.             break;
70.         }
71.     }
72.     return 0;
73. }

936e9f3c6d88235f8b1afd345fb68d54.png
图7-28 myTriangleAndCircle.cpp程序运行结果

经过几个月的努力,市面上第一本OpenCV 4入门书籍《OpenCV 4开发详解》将春节后由人民邮电出版社发行。如果小伙伴觉得内容有帮助,希望到时候多多支持!

关注小白的小伙伴可以提前看到书中的内容,我们创建了学习交流群,欢迎各位小伙伴添加小白微信加入交流群,添加小白时请备注“学习OpenCV 4”。

https://u.wechat.com/MJ-57nVtXgxUyL3dTwWd014 (二维码自动识别)

71af5d7726e90faa15fcb2459c1b85ee.png
OpenCV,轮廓多边形拟合是通过寻与轮廓点集最接近的多边形边界来实现的。这在处理形状识别和轮廓分析时非常有用。在C++,可以使用`approxPolyDP`函数来对轮廓进行多边形拟合。以下是一个简单的例子,展示如何使用`approxPolyDP`函数。 首先,你需要包含必要的头文件,并且确保已经正确安装了OpenCV库。 ```cpp #include <opencv2/opencv.hpp> #include <vector> int main() { // 假设已经加载了一张图片,并且得到了它的轮廓contours std::vector<std::vector<cv::Point>> contours; // 这里省略了获取轮廓的代码 // 遍历所有轮廓 for (size_t i = 0; i < contours.size(); i++) { // 使用approxPolyDP函数进行多边形拟合 // 参数分别为:轮廓点集拟合后的多边形点集、轮廓周长与拟合多边形周长的最大差值(epsilon)、曲线是否闭合(true为闭合) std::vector<cv::Point> approx; double epsilon = 0.01 * cv::arcLength(contours[i], true); cv::approxPolyDP(contours[i], approx, epsilon, true); // 此时approx存储的就是拟合后的多边形顶点 // 可以根据顶点数量判断拟合的形状类型 int num_vertices = approx.size(); if (num_vertices == 3) { std::cout << "轮廓是三角形" << std::endl; } else if (num_vertices == 4) { std::cout << "轮廓是四边形" << std::endl; } else { std::cout << "轮廓是多边形,顶点数:" << num_vertices << std::endl; } } // 其他处理代码... return 0; } ``` 在上面的代码,我们首先计算了轮廓的周长,然后根据周长计算出`epsilon`值,这是控制拟合精度的一个参数。`epsilon`值越大,拟合得到的多边形越平滑,反之则越接近原始轮廓。`true`参数表示我们希望得到的是一个闭合的多边形。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值