图像处理之寻找物体的凸包

280 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第33天

1 凸包

凸包(Convex Hull)是一个计算几何(图形学)中常见的概念。简单来说,给定二维平面上的点集,凸包就是将最外层的点连接起来构成的凸多边型,它是能包含点集中所有点的。理解物体形状或轮廓的一种比较有用的方法便是计算一个物体的凸包,然后计算其凸缺陷(convexity defects)。很多复杂物体的特性能很好地被这种缺陷表现出来。

如图8.9所示,我们用人手图来举例说明凸缺陷这一概念。手周围深色的线描画出了凸包,A到H被标出的区域是凸包的各个“缺陷”。正如看到的,这些凸度缺陷提供了手以及手状态的特征表现的方法。

2.png

新版OpenCV中,convexHull函数用于寻找图像点集中的凸包,我们一起来看一下这个函数。

2 寻找凸包:convexHull()函数

上文已经提到过,convexHull()函数用于寻找图像点集中的凸包,其原型声明如下。

C++:

void convexHull(InputArray points, OutputArray hull, bool clockwise=false, bool returnPoints=true)

  • 第一个参数,InputArray类型的points,输入的二维点集,可以填Mat类型或者 std::vector。
  • 第二个参数,OutputArray类型的hull,输出参数,函数调用后找到的凸包。
  • 第三个参数,bool类型的clockwise,操作方向标识符。当此标识符为真时,输出的凸包为顺时针方向。否则,就为逆时针方向。并且是假定坐标系的x轴指向右,y轴指向上方。
  • 第四个参数,bool类型的 returnPoints,操作标志符,默认值true。当标志 符为真时,函数返回各凸包的各个点。否则,它返回凸包各点的指数。当输出数组是std::vector时,此标志被忽略。

3 示例

代码:

//---------------------------------【头文件、命名空间包含部分】----------------------------
//		描述:包含程序所使用的头文件和命名空间
//---------------------------------------------------------------------------------------
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
using namespace cv;

//-----------------------------------【ShowHelpText( )函数】----------------------------------
//          描述:输出一些帮助信息
//-------------------------------------------------------------------------------------------
static void ShowHelpText()
{
	//输出欢迎信息和OpenCV版本
	printf("\n\n\t\t\t非常感谢购买《OpenCV3编程入门》一书!\n");
	printf("\n\n\t\t\t此为本书OpenCV2版的第71个配套示例程序\n");
	printf("\n\n\t\t\t   当前使用的OpenCV版本为:" CV_VERSION );
	printf("\n\n  ----------------------------------------------------------------------------\n");
	//输出一些帮助信息
	printf("\n\t欢迎来到【凸包检测】示例程序~\n\n"); 
	printf("\n\t按键操作说明: \n\n" 
		"\t\t键盘按键【ESC】、【Q】、【q】- 退出程序\n\n" 
		"\t\t键盘按键任意键 - 重新生成随机点,并进行凸包检测\n"  );  

}


//--------------------------------------【main( )函数】-----------------------------------------
//          描述:控制台应用程序的入口函数,我们的程序从这里开始执行
//---------------------------------------------------------------------------------------------
int main( )
{
	//改变console字体颜色
	system("color 1F"); 

	//显示帮助文字
	ShowHelpText();

	//初始化变量和随机值
	Mat image(600, 600, CV_8UC3);
	RNG& rng = theRNG();

	//循环,按下ESC,Q,q键程序退出,否则有键按下便一直更新
	while(1)
	{
		//参数初始化
		char key;//键值
		int count = (unsigned)rng%100 + 3;//随机生成点的数量
		vector<Point> points; //点值

		//随机生成点坐标
		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.push_back(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)), CV_FILLED, CV_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, CV_AA);
			point0 = point;
		}

		//显示效果图
		imshow("凸包检测示例", image);

		//按下ESC,Q,或者q,程序退出
		key = (char)waitKey();
		if( key == 27 || key == 'q' || key == 'Q' ) 
			break;
	}

	return 0;
}

效果图:

0.PNG