objectivec
// 包含OpenCV图像处理头文件
#include <opencv2/imgproc.hpp>
// 包含OpenCV高层GUI(图形用户界面)操作的头文件
#include <opencv2/highgui.hpp>
// 包含标准输入输出头文件
#include <iostream>
// 使用命名空间cv避免每次都要加cv::
using namespace cv;
// 使用命名空间std避免每次都要加std::
using namespace std;
// 帮助信息函数声明,用于显示程序使用方法
static void help(char** argv)
{
// 打印帮助信息:程序使用说明、如何停止程序等
cout << "\nThis program demonstrates iterative construction of\n"
"delaunay triangulation and voronoi tessellation.\n"
"It draws a random set of points in an image and then delaunay triangulates them.\n"
"Usage: \n";
cout << argv[0];
cout << "\n\nThis program builds the triangulation interactively, you may stop this process by\n"
"hitting any key.\n";
}
// 绘制Delaunay点,辅助函数
static void draw_subdiv_point( Mat& img, Point2f fp, Scalar color )
{
// 在图像中画一个以fp为中心,大小为3的实心圆,颜色为color
circle( img, fp, 3, color, FILLED, LINE_8, 0 );
}
// 绘制Delaunay三角剖分的辅助函数
static void draw_subdiv( Mat& img, Subdiv2D& subdiv, Scalar delaunay_color )
{
#if 1
vector<Vec6f> triangleList;
// 获取Delaunay三角剖分后的三角形列表
subdiv.getTriangleList(triangleList);
vector<Point> pt(3);
// 遍历每个三角形
for( size_t i = 0; i < triangleList.size(); i++ )
{
Vec6f t = triangleList[i];
// 将Vec6f转换为Point,并绘制三角形的三条边
pt[0] = Point(cvRound(t[0]), cvRound(t[1]));
pt[1] = Point(cvRound(t[2]), cvRound(t[3]));
pt[2] = Point(cvRound(t[4]), cvRound(t[5]));
line(img, pt[0], pt[1], delaunay_color, 1, LINE_AA, 0);
line(img, pt[1], pt[2], delaunay_color, 1, LINE_AA, 0);
line(img, pt[2], pt[0], delaunay_color, 1, LINE_AA, 0);
}
#else
// Else分支的代码没有启用,以下为备选的绘制Delaunay边的方式
vector<Vec4f> edgeList;
subdiv.getEdgeList(edgeList);
for( size_t i = 0; i < edgeList.size(); i++ )
{
Vec4f e = edgeList[i];
Point pt0 = Point(cvRound(e[0]), cvRound(e[1]));
Point pt1 = Point(cvRound(e[2]), cvRound(e[3]));
line(img, pt0, pt1, delaunay_color, 1, LINE_AA, 0);
}
#endif
}
// 定位点并绘制相关联的三角形的辅助函数
static void locate_point( Mat& img, Subdiv2D& subdiv, Point2f fp, Scalar active_color )
{
int e0=0, vertex=0;
// 定位点在剖分中的位置
subdiv.locate(fp, e0, vertex);
// 如果点位于某个三角形内或边上
if( e0 > 0 )
{
int e = e0;
do
{
Point2f org, dst;
// 获取当前边的原点和目标点,并绘制边
if( subdiv.edgeOrg(e, &org) > 0 && subdiv.edgeDst(e, &dst) > 0 )
line( img, org, dst, active_color, 3, LINE_AA, 0 );
// 获取下一条边
e = subdiv.getEdge(e, Subdiv2D::NEXT_AROUND_LEFT);
}
// 遍历完所有与点fp相关的边
while( e != e0 );
}
// 绘制点fp
draw_subdiv_point( img, fp, active_color );
}
// 绘制Voronoi图的辅助函数
static void paint_voronoi( Mat& img, Subdiv2D& subdiv )
{
// Voronoi图的各个面
vector<vector<Point2f> > facets;
// 对应每个Voronoi面的中心点
vector<Point2f> centers;
subdiv.getVoronoiFacetList(vector<int>(), facets, centers);
vector<Point> ifacet;
vector<vector<Point> > ifacets(1);
// 遍历所有的Voronoi面
for( size_t i = 0; i < facets.size(); i++ )
{
ifacet.resize(facets[i].size());
for( size_t j = 0; j < facets[i].size(); j++ )
ifacet[j] = facets[i][j];
// 随机生成颜色
Scalar color;
color[0] = rand() & 255;
color[1] = rand() & 255;
color[2] = rand() & 255;
// 填充Voronoi面
fillConvexPoly(img, ifacet, color, 8, 0);
// 绘制Voronoi面的边界
ifacets[0] = ifacet;
polylines(img, ifacets, true, Scalar(), 1, LINE_AA, 0);
// 绘制Voronoi中心
circle(img, centers[i], 3, Scalar(), FILLED, LINE_AA, 0);
}
}
// 主函数
int main( int argc, char** argv )
{
// 解析命令行参数,尤其是检测是否有"help"参数
cv::CommandLineParser parser(argc, argv, "{help h||}");
if (parser.has("help"))
{
// 如果有"help"参数,则显示帮助信息并退出程序
help(argv);
return 0;
}
// 设置活跃面颜色和Delaunay边颜色
Scalar active_facet_color(0, 0, 255), delaunay_color(255,255,255);
// 设置图像的显示区域为600x600大小
Rect rect(0, 0, 600, 600);
// 初始化Subdiv2D对象,它是用于Delaunay三角剖分的
Subdiv2D subdiv(rect);
// 创建一个与显示区域大小相同的图像
Mat img(rect.size(), CV_8UC3);
// 设置图像的背景色为黑色
img = Scalar::all(0);
// 窗口名称
string win = "Delaunay Demo";
// 显示窗口
imshow(win, img);
// 随机生成200个点,并进行三角剖分
for( int i = 0; i < 200; i++ )
{
// 在范围内随机生成一个点
Point2f fp( (float)(rand()%(rect.width-10)+5),
(float)(rand()%(rect.height-10)+5));
// 定位点,并绘制相关联的三角形
locate_point( img, subdiv, fp, active_facet_color );
imshow( win, img );
// 如果检测到按键,则停止循环
if( waitKey( 100 ) >= 0 )
break;
// 将生成的点插入到三角剖分中
subdiv.insert(fp);
// 重绘图像和三角剖分
img = Scalar::all(0);
draw_subdiv( img, subdiv, delaunay_color );
imshow( win, img );
// 如果检测到按键,则停止循环
if( waitKey( 100 ) >= 0 )
break;
}
// 绘制最终的Voronoi图
img = Scalar::all(0);
paint_voronoi( img, subdiv );
imshow( win, img );
// 等待用户按键
waitKey(0);
// 程序正常结束
return 0;
}
该代码的功能是演示如何在图像中生成随机点集,并对这些点进行Delaunay三角剖分和Voronoi图的构建。它逐步显示了Delaunay三角剖分的构建过程,用户可以通过按任意键来停止过程。最后,它会显示最终的Voronoi图。这是计算几何和机器视觉中常用到的算法。