图像轮廓与图像分割修复(opencv3编程入门第八章)第二节 寻找物体的凸包
凸包
- 借用百度百科的解释:凸包(Convex Hull)是一个计算几何(图形学)中的概念。在一个实数向量空间V中,对于给定集合X,所有包含X的凸集的交集S被称为X的凸包。X的凸包可以用X内所有点(X1,…Xn)的凸组合来构造。在二维欧几里得空间中,凸包可想象为一条刚好包著所有点的橡皮圈。用不严谨的话来讲,给定二维平面上的点集,凸包就是将最外层的点连接起来构成的凸多边形,它能包含点集中所有的点。
“寻找凸包”的库函数
void convexHull(InputArray points,OutputArray hull,bool clockwise = false,bool returnPoints = true)
- InputArray points: 得到的点集,一般是用图像轮廓函数求得的轮廓点,Mat类型或者std::vector
- OutputArray hull: 输出的是凸包的二维xy点的坐标值,针对每一个轮廓形成的
- bool clockwise = false: 表示凸包的方向,顺时针或者逆时针
- bool returnPoint = true: 表示返回点还是点地址的索引
示例代码1
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
Mat image(600, 600, CV_8UC3);
RNG& rng = theRNG();
while(1)
{
char key;
int count = (unsigned)rng % 100 + 3; //随机生成点的数量
vector<Point> points(count);
//随机生成点的坐标
for(int i=0; i< count; i++)
{
Point point;
point.x = rng.uniform(image.cols / 4, image.cols * 3 / 4);
point.y = rng.uniform(image.rows / 4, image.rows * 3 / 4);
points[i] = point;
}
//检测凸包
vector<int> hull;
convexHull(Mat(points), hull, true);
//绘制出随机颜色的点
image = Scalar::all(0);
for(int i=0; i < count; i++)
{
circle(image, points[i], 3, Scalar(rng.uniform(0, 255), rng.uniform(0, 255),
rng.uniform(0, 255)), FILLED, LINE_AA);
}
//准备参数
int hullcount = (int)hull.size(); //凸包的边数
Point point0 = points[hull[hullcount - 1]]; //连接凸包边的坐标点
//绘制凸包的边
for(int i = 0; i < hullcount; i++)
{
Point point = points[hull[i]];
line(image, point0, point, Scalar(255, 255, 255), 2, LINE_AA);
point0 = point;
}
//显示效果图
imshow("凸包检测示例", image);
key = (char)waitKey();
if (key == 27)
break;
}
return 0;
}
结果展示:
示例代码2
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
#define WINDOW_NAME1 "【原始图窗口】"
#define WINDOW_NAME2 "【效果图窗口】"
Mat g_srcImage, g_grayImage;
int g_nThresh = 50;
int g_maxThresh = 255;
RNG g_rng;
Mat srcImage_copy = g_srcImage.clone();
Mat g_thresholdImage_output;
vector<vector<Point> > g_vContours;
vector<Vec4i> g_vHierarchy;
void on_ThreshChange(int, void*);
int main()
{
g_srcImage = imread("1.jpg");
//将原图像转化成灰度图并模糊
cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);
blur(g_grayImage, g_grayImage, Size(3, 3));
namedWindow(WINDOW_NAME1, WINDOW_KEEPRATIO);
imshow(WINDOW_NAME1, g_srcImage);
createTrackbar("阈值:", WINDOW_NAME1, &g_nThresh, g_maxThresh, on_ThreshChange);
on_ThreshChange(0, 0); //调用一次进行初始化
waitKey(0);
return 0;
}
void on_ThreshChange(int, void*)
{
threshold(g_grayImage, g_thresholdImage_output, g_nThresh, 255, THRESH_BINARY); //二值化
findContours(g_thresholdImage_output, g_vContours, g_vHierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);
//遍历每个轮廓,寻找其凸包
vector<vector<Point> > hull(g_vContours.size());
for (unsigned int i = 0; i < g_vContours.size(); i++)
{
convexHull(Mat(g_vContours[i]), hull[i]);
}
//绘出轮廓及凸包
Mat drawing = Mat::zeros(g_thresholdImage_output.size(), CV_8UC3);
for (unsigned int i = 0; i < g_vContours.size(); i++)
{
Scalar color = Scalar(g_rng.uniform(0, 255), g_rng.uniform(0, 255), g_rng.uniform(0, 255));
drawContours(drawing, g_vContours, i, color); //画轮廓
color = Scalar(g_rng.uniform(0, 255), g_rng.uniform(0, 255), g_rng.uniform(0, 255));
drawContours(drawing, hull, i, color); //画凸包图
}
namedWindow(WINDOW_NAME2, WINDOW_KEEPRATIO);
imshow(WINDOW_NAME2, drawing);
}
结果展示:
参考文献
- https://baike.baidu.com/item/凸包/179150?fr=aladdin
- OpenCV3编程入门 电子工业出版社 毛星云等编著。