多指尖检测的简单方法。

新开的CSDN 博客。准备开始写点东西


初学CV,翻很多文献。找了很多指尖检测的实例。不懂数学的我其实遇到了很多困难。


主要是从候选点获取指尖的算法上面。鲁棒性好像都不是很好。


关于指尖检测

主要下面两种



1.用Opencv 自带的凸包检测


主要步骤下


1.阈值操作 (一般用 前景检测 或者 肤色检测)


2.寻找轮廓

3.寻找凸包 

4.选出指尖

凸包结构的点


1.Start

2.Depth_point

3.End 


约束的条件

1.Depth 的角度 < 90 度

2.当前组 Start 点 与上一组 End 点的距离 < 20 (第一组 与 最后一组比较 )


则当前组的start点可以认为是指尖

检测效果如下


2.计算重心到轮廓边缘的距离



主要步骤(16年更新:我之前高中没有学过计算几何方面的内容。之前的代码完全靠想象)


1.阈值操作 (一般用 前景检测 或者 肤色检测)

2.寻找轮廓

3.寻找重心

计算一阶矩


4.列举重心到边缘的距离

5.选出指尖点


网上随便找了一张手的图






做完阈值操作后

寻找轮廓

计算重心的坐标

然后获取重心到轮廓距离。

下面这张图

横坐标是点的顺序

纵坐标是重心到轮廓边缘的距离


可以看出图中有 5 个峰值点。

这五个峰值点表示对应的就是 五个手指的位置。

检测效果图如下 


换一张



检测结果还是比较精确的 。大拇指的点可能不满足条件未检测到。

如果用最小二乘拟合峰值附近的点几个点 可以获取亚像素精度的指尖点。

void gethandpoint(Mat frame){
	Mat show_img;
	frame.copyTo(show_img);
	Mat derivative_img=cvCreateMat(300,900,show_img.type());
	derivative_img.setTo(255);


GaussianBlur(frame, frame, Size(3, 3), 0);
threshold(frame,frame,240,255,THRESH_BINARY_INV);
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours(frame, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
//获取轮廓
int index;
double area, maxArea(0);
for (int i=0; i < contours.size(); i++)
{
	area = contourArea(Mat(contours[i]));
	if (area > maxArea)
	{
		maxArea = area;
		index = i;
	}			
}

//drawContours(frame, contours, index, Scalar(0, 0, 255), 2, 8, hierarchy );

Moments moment = moments(frame, true);
Point center(moment.m10/moment.m00, moment.m01/moment.m00);
//获取重心
//circle(show_img, center, 8 ,Scalar(0, 0, 255), CV_FILLED);

vector<Point> couPoint = contours[index];
float current(0), depth(50000),mosthigher(0);

//count Num
int q(0),m(0),k(0),j(0),notice(0),spos(0);

Point fingerTips_single;
Point p, n, r;


for(int i=1;i < couPoint.size();i++){



	float pn = sqrt(float((couPoint[i].x - center.x) * (couPoint[i].x - center.x) + (couPoint[i].y - center.y) * (couPoint[i].y - center.y)) ); //计算重心到轮廓边缘的距离

	
	line(derivative_img,cvPoint(i,300),cvPoint(i,300-pn/3),Scalar(0,0,0,0));

		//line(show_img,couPoint[i],center,Scalar(0,0,0,0));

   //cout<<int(pn)<<endl;
 if (pn>=current)
   {
	   current=pn;//找出第一次的峰值
	   

   }
   else
   {
	   m++;
	   if(m ==1 ){
		   	 notice=i;
		   fingerTips_single=couPoint[i];

			      depth=500000;
	   }


	   if (depth>=pn)
	   {
depth=pn;
k++;
//从峰值向下开始爬。

	   }
	   else
	   {  
		 
			
		   if(k>20)
	   {
//如果爬的步长 > 20  则认为是指尖的候选点。
		  // spos=notice;
		   if(notice<10)
		   {
			   notice= 10;

		   }
//更进一步的获取精确的指尖位置	枚举候选点周围的 10 个点 选出距离重心最大的点
	
	 for (int k = notice-10;k<notice+10;k++)
	 {
		 current = sqrt(float((couPoint[k].x - center.x) * (couPoint[k].x - center.x) + (couPoint[k].y - center.y) * (couPoint[k].y - center.y)) );
		 if(current>mosthigher){
		 mosthigher = current;
		 spos = k ;

		 }

		    
	 }
	 mosthigher=0;
	fingerTips_single =couPoint[spos];
//获得的指尖
	cout<<"["<<fingerTips_single.x<<","<<fingerTips_single.y<<"]"<<endl;

		   circle(show_img,couPoint[spos],3,Scalar(0,0,0,0),5,CV_AA);

	

			 	
	   }
		 
		    
		   current=0 ;

		   m=0;
		   k=0;
		   k=0;
		 

	   }

   }

   
  //waitKey(0);
   	 
}
imshow("hand",show_img);
imshow("derivative_img",derivative_img);
}


 20130611

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值