opencv实现简单手指位置识别

整体思路:

1.过滤噪声

2.由于RGB颜色的离散性转换为HSV通道

3.对HSV空间进行量化,得到2值图像,亮的部分为手的形状

4.去除杂点造成的伪轮廓,留下手的真实轮廓

5.对凸出点连线

6.最高点到底部中点的连线即为手指方向

//部分代码:
将MFC实现部分给省略了,给出了完整的opencv部分代码,可以参考实现。
int main()
{
    cv::VideoCapture cap(0);
    if (!cap.isOpened())
    {
        return -1;
    }
    //
    cv::Mat frame;
    cv::Mat frameHSV;
    //
    std::vector< std::vector<cv::Point> > OriginalContours;//轮廓
    std::vector< cv::Vec4i > hierarchy; // 轮廓的结构信息
    //
    std::vector< std::vector<cv::Point> > FinalContours;// 筛选后的轮廓
    std::vector< cv::Point > hull;  // 凸包络的点集
    //
    CString Str;
    int i, j;
    int Width = cap.get(CV_CAP_PROP_FRAME_WIDTH), Height = cap.get(CV_CAP_PROP_FRAME_HEIGHT);
    float fHeight = ((float)2 / 3 - (float)1 / 7) * Height;
    //
    while (0 == pDlg->m_bStopFlag)
    {
        cap >> frame;
        if (frame.empty())
        {
            break;
        }
        //左右翻转
        cv::flip(frame, frame, 1);
        //中值滤波,用了这个下面的其他滤波全部异常
        //medianBlur(frame, frame, 10);
        //高斯滤波
        cv::GaussianBlur(frame, frame, cv::Size(7, 7), 1.5, 1.5);
        //通道转换
        cv::cvtColor(frame, frameHSV, CV_BGR2HSV);
        //imshow("frameHSV", frameHSV);
        /*
        S = 符号整型  U = 无符号整型  F = 浮点型
        E.g.:
        CV_8UC1 是指一个8位无符号整型单通道矩阵,
        CV_32FC2是指一个32位浮点型双通道矩阵
        CV_8UC1          CV_8SC1          CV_16U C1       CV_16SC1
        CV_8UC2          CV_8SC2          CV_16UC2        CV_16SC2
        CV_8UC3          CV_8SC3          CV_16UC3        CV_16SC3
        CV_8UC4          CV_8SC4          CV_16UC4        CV_16SC4
        CV_32SC1         CV_32FC1         CV_64FC1
        CV_32SC2         CV_32FC2         CV_64FC2
        CV_32SC3         CV_32FC3         CV_64FC3
        CV_32SC4         CV_32FC4         CV_64FC4
        */
        // 对HSV空间进行量化,得到2值图像,亮的部分为手的形状
        cv::Mat mask(frame.rows, frame.cols, CV_8UC1);
        //inRange(frameHSV, cv::Scalar(0, 30, 30), cv::Scalar(40, 170, 256), mask);
        inRange(frameHSV, cv::Scalar(5, 30, 30), cv::Scalar(40, 170, 256), mask);
        //
        // 腐蚀:去除小亮点 膨胀:连接区块
        cv::erode(mask, mask, cv::Mat(5, 5, CV_8U), cv::Point(-1, -1), 1);
        //cv::dilate(mask, mask, cv::Mat(5, 5, CV_8U), cv::Point(-1, -1), 2);
        //imshow("frameHSV", frameHSV);
        //imshow("mask", mask);
        OriginalContours.clear();
        hierarchy.clear();
        FinalContours.clear();
        // 得到手的轮廓
        cv::findContours(mask, OriginalContours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
        // 去除伪轮廓
        for (i = 0; i < OriginalContours.size(); i++)
        {
            if (fabs(cv::contourArea(cv::Mat(OriginalContours[i]))) > 25000)
            {
                FinalContours.push_back(OriginalContours[i]);
            }
        }
        // 画轮廓
        cv::drawContours(frame, FinalContours, -1, cv::Scalar(0, 0, 255), 3);
        // 得到轮廓的凸包络
        int hullcount;
        int iNumOfContours = FinalContours.size();
        cv::Point top;
        for (j = 0; j < iNumOfContours; j++)
        {
            convexHull(cv::Mat(FinalContours[j]), hull, true);
            hullcount = (int)hull.size();
            //
            for (i = 0; i<hullcount - 1; i++)
            {
                cv::line(frame, hull[i + 1], hull[i], cv::Scalar(255, 0, 0), 2, CV_AA);
            }
            cv::line(frame, hull[hullcount - 1], hull[0], cv::Scalar(255, 0, 0), 2, CV_AA);
            //画点
            GetTopPoint(hull, hullcount, top);
            cv::line(frame, top, top, cv::Scalar(255, 0, 255), 18, CV_AA);
            cv::line(frame, top, cv::Point(Width/2, Height), cv::Scalar(0, 255, 255), 2, CV_AA);
            //
            if (1 == iNumOfContours)
            {
                pDlg->m_FingerPosition.bChanged = 1;
                pDlg->m_FingerPosition.top = ((float)top.y - (float)Height / 7) / fHeight;
                pDlg->m_FingerPosition.left = (float)top.x / (float)Width;
            }
        }
        //
        cv::line(frame, cv::Point(0, Height / 7), cv::Point(Width, Height / 7), cv::Scalar(255, 255, 255), 2, CV_AA);
        cv::line(frame, cv::Point(0, 2 * Height / 3), cv::Point(Width, 2 * Height / 3), cv::Scalar(255, 255, 255), 2, CV_AA);
        imshow("frame", frame);
        cv::waitKey(33);
    }
    return 0;
}

实验效果图
这里写图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值