C++中怎么用OpenCV实现手势识别

C++中怎么用OpenCV实现手势识别

本篇内容介绍了“C++中怎么用OpenCV实现手势识别”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

一、手部关键点检测

如图所示,为我们的手部关键点所在位置。第一步,我们需要检测手部21个关键点。我们使用深度神经网络DNN模块来完成这件事。通过使用DNN模块可以检测出手部21个关键点作为结果输出,具体请看源码。

1.1 功能源码

//手部关键点检测boolHandKeypoints_Detect(Matsrc,vector<Point>&HandKeypoints){//模型尺寸大小intwidth=src.cols;intheight=src.rows;floatratio=width/(float)height;intmodelHeight=368;//由模型输入维度决定intmodelWidth=int(ratio*modelHeight);//模型文件stringmodel_file="pose_deploy.prototxt";//网络模型stringmodel_weight="pose_iter_102000.caffemodel";//网络训练权重//加载caffe模型Netnet=readNetFromCaffe(model_file,model_weight);//将输入图像转成blob形式Matblob=blobFromImage(src,1.0/255,Size(modelWidth,modelHeight),Scalar(0,0,0));//将图像转换的blob数据输入到网络的第一层“image”层,见deploy.protxt文件net.setInput(blob,"image");//结果输出Matoutput=net.forward();intH=output.size[2];intW=output.size[3];for(inti=0;i<nPoints;i++){//结果预测MatprobMap(H,W,CV_32F,output.ptr(0,i));resize(probMap,probMap,Size(width,height));Pointkeypoint;//最大可能性手部关键点位置doubleclassProb;//最大可能性概率值minMaxLoc(probMap,NULL,&classProb,NULL,&keypoint);HandKeypoints[i]=keypoint;//结果输出,即手部关键点所在坐标}returntrue;}

1.2 功能效果

如图所示,我们已经通过DNN检测出21个手部关键点所在位置。接下来,我们需要使用这些关键点进行简单的手势识别。

二、手势识别

2.1算法原理

本案例实现手势识别是通过比较关键点位置确定的。首先拿出每个手指尖关键点索引(即4、8、12、16、20)。接下来,对比每个手指其它关键点与其指尖所在位置。

例如我们想确定大拇指现在的状态是张开的还是闭合的。如下图所示,由于OpenCV是以左上角为起点建立坐标系的。当大拇指处于张开状态时(掌心向内),我们可以发现,对比关键点4、关键点3所在位置。当4的x坐标大于3的x坐标时,拇指处于张开状态;当4的x坐标小于3的x坐标时,拇指处于闭合状态。

同理,其余四个手指,以食指为例。当关键点8的y坐标小于关键点6的y坐标时,此时食指处于张开状态;当关键点8的y坐标大于关键点6的y坐标时,此时食指处于闭合状态。

当手指处于张开状态时,我们计数1。通过统计手指的张开数达到手势识别的目的。具体请看源码。

2.2功能源码

//手势识别boolHandpose_Recognition(vector<Point>&HandKeypoints,int&count){vector<int>fingers;//拇指if(HandKeypoints[tipIds[0]].x>HandKeypoints[tipIds[0]-1].x){//如果关键点'4'的x坐标大于关键点'3'的x坐标,则说明大拇指是张开的。计数1fingers.push_back(1);}else{fingers.push_back(0);}//其余的4个手指for(inti=1;i<5;i++){if(HandKeypoints[tipIds[i]].y<HandKeypoints[tipIds[i]-2].y){//例:如果关键点'8'的y坐标小于关键点'6'的y坐标,则说明食指是张开的。计数1fingers.push_back(1);}else{fingers.push_back(0);}}//结果统计for(inti=0;i<fingers.size();i++){if(fingers[i]==1){count++;}}returntrue;}

三、结果显示

通过以上步骤,我们已经有了手部关键点所在坐标位置以及对应的手势结果,接下来就进行效果展示。

在这里,为了逼格高一点,我们将下面的手势模板图像作为输出结果放进我们的测试图中。具体操作请看源码。

3.1功能源码

//识别效果显示boolShowResult(Mat&src,vector<Point>&HandKeypoints,int&count){//画出关键点所在位置for(inti=0;i<nPoints;i++){circle(src,HandKeypoints[i],3,Scalar(0,0,255),-1);putText(src,to_string(i),HandKeypoints[i],FONT_HERSHEY_COMPLEX,0.8,Scalar(0,255,0),2);}//为了显示骚操作,读取模板图片,作为识别结果vector<string>imageList;stringfilename="images/";glob(filename,imageList);vector<Mat>Temp;for(inti=0;i<imageList.size();i++){Mattemp=imread(imageList[i]);resize(temp,temp,Size(100,100),1,1,INTER_AREA);Temp.push_back(temp);}//将识别结果显示在原图中Temp[count].copyTo(src(Rect(0,src.rows-Temp[count].rows,Temp[count].cols,Temp[count].rows)));putText(src,to_string(count),Point(20,60),FONT_HERSHEY_COMPLEX,2,Scalar(0,0,128),3);returntrue;}

3.2效果显示

除此之外,我们还可以将所有的图片整合成一张图,具体请看源码吧。

//将所有图片整合成一张图片boolStitching_Image(vector<Mat>images){Matcanvas=Mat::zeros(Size(1200,1000),CV_8UC3);intwidth=400;intheight=500;for(inti=0;i<images.size();i++){resize(images[i],images[i],Size(width,height),1,1,INTER_LINEAR);}intcol=canvas.cols/width;introw=canvas.rows/height;for(inti=0;i<row;i++){for(intj=0;j<col;j++){intindex=i*col+j;images[index].copyTo(canvas(Rect(j*width,i*height,width,height)));}}namedWindow("result",WINDOW_NORMAL);imshow("result",canvas);waitKey(0);returntrue;}

最终结果如图所示。以上就是整个案例的流程啦。。。

四、源码

#include<iostream>#include<opencv2/opencv.hpp>#include<opencv2/dnn.hpp>usingnamespacestd;usingnamespacecv;usingnamespacecv::dnn;//手部关键点数目constintnPoints=21;//手指索引constinttipIds[]={4,8,12,16,20};//手部关键点检测boolHandKeypoints_Detect(Matsrc,vector<Point>&HandKeypoints){//模型尺寸大小intwidth=src.cols;intheight=src.rows;floatratio=width/(float)height;intmodelHeight=368;//由模型输入维度决定intmodelWidth=int(ratio*modelHeight);//模型文件stringmodel_file="pose_deploy.prototxt";//网络模型stringmodel_weight="pose_iter_102000.caffemodel";//网络训练权重//加载caffe模型Netnet=readNetFromCaffe(model_file,model_weight);//将输入图像转成blob形式Matblob=blobFromImage(src,1.0/255,Size(modelWidth,modelHeight),Scalar(0,0,0));//将图像转换的blob数据输入到网络的第一层“image”层,见deploy.protxt文件net.setInput(blob,"image");//结果输出Matoutput=net.forward();intH=output.size[2];intW=output.size[3];for(inti=0;i<nPoints;i++){//结果预测MatprobMap(H,W,CV_32F,output.ptr(0,i));resize(probMap,probMap,Size(width,height));Pointkeypoint;//最大可能性手部关键点位置doubleclassProb;//最大可能性概率值minMaxLoc(probMap,NULL,&classProb,NULL,&keypoint);HandKeypoints[i]=keypoint;//结果输出,即手部关键点所在坐标}returntrue;}//手势识别boolHandpose_Recognition(vector<Point>&HandKeypoints,int&count){vector<int>fingers;//拇指if(HandKeypoints[tipIds[0]].x>HandKeypoints[tipIds[0]-1].x){//如果关键点'4'的x坐标大于关键点'3'的x坐标,则说明大拇指是张开的。计数1fingers.push_back(1);}else{fingers.push_back(0);}//其余的4个手指for(inti=1;i<5;i++){if(HandKeypoints[tipIds[i]].y<HandKeypoints[tipIds[i]-2].y){//例:如果关键点'8'的y坐标小于关键点'6'的y坐标,则说明食指是张开的。计数1fingers.push_back(1);}else{fingers.push_back(0);}}//结果统计for(inti=0;i<fingers.size();i++){if(fingers[i]==1){count++;}}returntrue;}//识别效果显示boolShowResult(Mat&src,vector<Point>&HandKeypoints,int&count){//画出关键点所在位置for(inti=0;i<nPoints;i++){circle(src,HandKeypoints[i],3,Scalar(0,0,255),-1);putText(src,to_string(i),HandKeypoints[i],FONT_HERSHEY_COMPLEX,0.8,Scalar(0,255,0),2);}//为了显示骚操作,读取模板图片,作为识别结果vector<string>imageList;stringfilename="images/";glob(filename,imageList);vector<Mat>Temp;for(inti=0;i<imageList.size();i++){Mattemp=imread(imageList[i]);resize(temp,temp,Size(100,100),1,1,INTER_AREA);Temp.push_back(temp);}//将识别结果显示在原图中Temp[count].copyTo(src(Rect(0,src.rows-Temp[count].rows,Temp[count].cols,Temp[count].rows)));putText(src,to_string(count),Point(20,60),FONT_HERSHEY_COMPLEX,2,Scalar(0,0,128),3);returntrue;}//将所有图片整合成一张图片boolStitching_Image(vector<Mat>images){Matcanvas=Mat::zeros(Size(1200,1000),CV_8UC3);intwidth=400;intheight=500;for(inti=0;i<images.size();i++){resize(images[i],images[i],Size(width,height),1,1,INTER_LINEAR);}intcol=canvas.cols/width;introw=canvas.rows/height;for(inti=0;i<row;i++){for(intj=0;j<col;j++){intindex=i*col+j;images[index].copyTo(canvas(Rect(j*width,i*height,width,height)));}}namedWindow("result",WINDOW_NORMAL);imshow("result",canvas);waitKey(0);returntrue;}intmain(){vector<string>imageList;stringfilename="test/";glob(filename,imageList);vector<Mat>images;for(inti=0;i<imageList.size();i++){Matsrc=imread(imageList[i]);vector<Point>HandKeypoints(nPoints);HandKeypoints_Detect(src,HandKeypoints);intcount=0;Handpose_Recognition(HandKeypoints,count);ShowResult(src,HandKeypoints,count);images.push_back(src);imshow("Demo",src);waitKey(0);}Stitching_Image(images);system("pause");return0;}

“C++中怎么用OpenCV实现手势识别”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注恰卡编程网网站,小编将为大家输出更多高质量的实用文章!

发布于 2022-04-03 22:34:28
收藏
分享
海报
0 条评论
41
上一篇:vue怎么使用echarts实现立体柱形图 下一篇:怎么使用docker安装nginx提供的web服务
目录

    0 条评论

    本站已关闭游客评论,请登录或者注册后再评论吧~

    忘记密码?

    图形验证码