2025年多指尖检测的简单方法。

多指尖检测的简单方法。新开的 CSDN 博客 准备开始写点东西 初学 CV 翻很多文献 找了很多指尖检测的实例 不懂数学的我其实遇到了很多困难 主要是从候选点获取指尖的算法上面 鲁棒性好像都不是很好 关于指尖检测 主要下面两种 1 用 Opencv 自带的凸包检测 主要步骤下 1 阈值操作 一般用 前景检测 或者 肤色检测

大家好,我是讯享网,很高兴认识大家。

新开的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=; } 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); } 

讯享网

 

小讯
上一篇 2025-02-22 09:29
下一篇 2025-02-24 15:52

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/53813.html