AI入门之神经网络(9)基于c++、opencv的dnn模块的视频手势识别

基于c++、opencv的dnn模块的手势识别

先看效果:
pose

老规矩话不多,实现的方法步骤,细节全在我的代码注释里面,只你跟着注释写,相信你也写得出来的!

#include <opencv2/dnn.hpp>
#include<opencv2/opencv.hpp>
#include<Windows.h>
#include <iostream>

using namespace std;
using namespace cv;
using namespace dnn;

//大致步骤:加载网络文件,输入到网络去,加载检测的图片,图片预处理,处理的图片送入网络,网络返回结果,再结果中找到点,点的位置再拟合到原图中,展示原图 

int nPoints = 22;//21个关键带你
string protoFile = "H:\\openpose_data\\0.prototxt";//prototxt表示模型的配置文件
string weightsFile = "H:\\openpose_data\\1.caffemodel";//caffeModel表示模型的权重二进制文件


const int POSE_PAIRS[20][2] =//手指姿势数组
{//每个手指4个关键点(一点两个位置坐标参数)(5个手指每个手指4个关键点加一个手掌点等于21,故【20】【2】的数组)
    {0,1}, {1,2}, {2,3}, {3,4},         // 拇指
    {0,5}, {5,6}, {6,7}, {7,8},         // 食指
    {0,9}, {9,10}, {10,11}, {11,12},    // 中指
    {0,13}, {13,14}, {14,15}, {15,16},  // 无名指
    {0,17}, {17,18}, {18,19}, {19,20}   // 小指
};



int main()
{
    Mat img;
    VideoCapture cap;
    cap.open("H:\\openpose_data\\my_hand.mp4");
    if(!cap.isOpened())
    {
        cout << "video can not open " << endl;
    }
    //cap.set(CAP_PROP_FOURCC, VideoWriter::fourcc('M', 'J,', 'P', 'G'));
    //cap.set(CAP_PROP_FRAME_WIDTH, 640);
    //cap.set(CAP_PROP_FRAME_HEIGHT, 480);

    namedWindow("pose", WINDOW_AUTOSIZE);

   

    int a = 0;
    while (true)
    {
        a += 30;
        if (a >= cap.get(CAP_PROP_FRAME_COUNT))//得到总的帧数
        {
            cout << "检测完成" << endl;
            break;
        }
        cap.set(CAP_PROP_POS_FRAMES, a);  //(跳帧)优化图片,缩减尺寸和提高图片质量(直方图均衡化),设置缓冲区,处理时间小于帧差间隔(重点)
        if (cap.get(CAP_PROP_POS_MSEC) != 0)//暂停几秒,让图片完成装载
        {
             Sleep(100);
        }

        cap >> img;
        //resize(img, img, Size(640,480));//缩减尺寸

        float aspect_ratio = img.cols / (float)img.rows;//获取图片的宽高比
        int inHeight = 368;
        int inWidth = (int)(aspect_ratio * inHeight);//感觉这里的*8/8没用啊
        float thresh = 0.01;//定义关键点的阈值

        Net net = readNetFromCaffe(protoFile, weightsFile);//加载网络模型函数
        net.setPreferableBackend(DNN_BACKEND_OPENCV);//此函数是加速网络推理的设置
        Mat inpBlob = blobFromImage(img, 1.0 / 255, Size(inWidth, inHeight), Scalar(0, 0, 0), false, false);//用于图片识别时图片预处理,图片缩放和减均值处理

        //模型推理过程就是神经网络模型进行一次前向传播,在OpenCV中,用以下可读性非常强的两行代码即可完成
        net.setInput(inpBlob);
        Mat output = net.forward();// 返回预测结果(类别,置信度,2个坐标位置(x、y))
        //类别的对应清单,从classification_classes_ILSVRC2012.txt获取
        //forward函数返回一个Mat变量,返回值是指输入的layername首次出现的输出默认输出整个网络的运行结果

        int H = output.size[2];
        int W = output.size[3];
        //这里的H、W是在预测的关键点位置信息


       // 寻找关键点
        vector<Point> points(nPoints);//赋值22给points(22->0-21就是上面手的21个关键点)
        for (int n = 0; n < nPoints; n++)//遍历
        {
            // 相应身体部分的概率图
            Mat probMap(H, W, CV_32F, output.ptr(0, n));//将关键点x作为H、y作为W构建一个矩阵,再将21个关键点输入进这个矩阵中
            resize(probMap, probMap, Size(img.cols, img.rows));//裁剪相应的大小,恢复成原图的大小,也便确定点的位置
            Point maxLoc; // 获取位置
            double prob; //取最大的概率数据
            minMaxLoc(probMap, 0, &prob, 0, &maxLoc);//在数组中找到全局最小和最大值
            //参数1输入的数组若是图像需为单通道图像、参数2返回最小值的指针若无需返回此值设为 NULL、参数3返回最大值的指针若无需返回此值设为 NULL
            //参数4返回最小值位置的指针(二维情况下)若无需返回此值设为 NULL、参数5返回最大值位置的指针(二维情况下)若无需返回此值设为 NULL、参数6可选的掩膜操作
            points[n] = maxLoc;//把最大概率的点的位置装入动态数组内,为接下来画线做准备
        }

        //关键点之间画线
        int nPairs = sizeof(POSE_PAIRS) / sizeof(POSE_PAIRS[0]);
        for (int n = 0; n < nPairs; n++)
        {
            // 查找 2 个连接的身体/手部部件
            Point2f partA = points[POSE_PAIRS[n][0]];
            Point2f partB = points[POSE_PAIRS[n][1]];

            if (partA.x <= 0 || partA.y <= 0 || partB.x <= 0 || partB.y <= 0)
                continue;

            line(img, partA, partB, Scalar(0, 255, 255), 2);//画线函数
            circle(img, partA, 8, Scalar(0, 0, 255), -1);
            circle(img, partB, 8, Scalar(0, 0, 255), -1);
        }
        imshow("pose", img);
        waitKey(30);
    }   

    cap.release();
	return 0;
}
//对关键点之间的操作映射为鼠标事件
//就可以使用手势来实现一些电脑上的操作

识别效果:
B站(这个也是我的账号呦)

总结:2天写出来,1天改代码优化,效率还可以吧!但是最后视频还是有卡顿,感觉有3秒1帧,这里说一下我分析的卡顿的原因:1、视频读入速度快,图片处理慢 2、视频出来的图片没处理好 3、没用GPU跑代码 4、也没有用线程去处理 总之项目是可以了的,也是由于视频检测卡顿的原因我就没写手势映射到鼠标的逻辑操作了,如果检测的视频有25fps,那么就可以利用手势来控制鼠标做一些鼠标能做到的事情了。

  • 9
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值