• OpenCV学习(31) 基于defects的简单手势


          前几年在做毕业设计时候曾用opencv1.0中defects做过简单的手势识别,这几天看OpenCV2.46中的轮廓函数,发现和以前差别挺大,函数调用完全不一样,重新实现了简单手势的代码。

    1.首先用简单的肤色检测算法,得到手的区域。

        Mat img = cv::imread("../hand2.jpg");
        namedWindow("image");
        imshow("image", img);

        Mat hsvimg;

          首先把图像转化到HSV颜色空间,利用肤色色度、饱和度和亮度的特殊范围,得到手的区域。最后对得到的二值手的区域进行开闭操作,去掉一些小的干扰点。
        //得到HSV颜色空间的图像
        cvtColor( img, hsvimg, CV_BGR2HSV );
        //初始化手的图像和原始图像一样大小
        Mat handimg1(img.rows,img.cols, CV_8UC1, Scalar(0));

        //简单的肤色检测算法,基于HSV颜色空间和域值
        uchar* p;
        uchar* p1;
        uchar h, s, v;
        int i, j;
        for( i = 0; i < hsvimg.rows; ++i)
            {
            p = hsvimg.ptr<uchar>(i);
            p1= handimg1.ptr<uchar>(i);
            for ( j = 0; j < hsvimg.cols; ++j)
                {
                //printf (" %d %d %d",p[j*3], p[j*3+1],p[j*3+2]);
                h = p[j*3];
                s = p[j*3+1];
                v = p[j*3+2];
                if(h <= 19 && s >= 48 && v > 40)
                    {
                    p1[j] = 255;
                    }
                else p1[j] = 0;
                }
            }
        //对得到手区域二值图做简单的开闭操作
        cv::Mat element = cv::getStructuringElement( cv::MORPH_RECT,
            cv::Size( 5,5 ),
            cv::Point( 2, 2 ) );
        morphologyEx( handimg1, handimg1, MORPH_OPEN, element );
        morphologyEx( handimg1, handimg1, MORPH_CLOSE, element );

    简单肤色算法后的效果:

    imageimage

         接着对得到的手区域二值图,查找轮廓,找出面积最大的轮廓区域,这个区域一般为手的区域,对该区域求凸包以及defect数目,根据defect的数目,可以判断伸出几个手指头。注意:在判断defect数目时候,我们根据defect点到凸包的距离长度,过滤了一些小的defect。

    过滤的代码为:

    if ( defectVector.val[3] <= 10000 ) { continue; }

    下面是过滤前后的defect点(黄色点),可以看到过滤后,只有4个defect点,我们可以得出此时伸出了5个手指头。

    imageimage

    而下面的图,只有1个defect点,则表示伸出2个手指头。

    imageimageimage

    检测defect的代码如下:

    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;

    //查找轮廓
    findContours( handimg1, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
    printf("轮廓数目:%d ", contours.size());
    vector<vector<Point> >hull( contours.size() );
    for( int i = 0; i < contours.size(); i++ )
    { convexHull( Mat(contours[i]), hull[i], false ); }

    Mat drawing = Mat::zeros( handimg1.size(), CV_8UC3 );
    int area = 0; //轮廓索引
    int k = 0;
    for(i = 0; i< contours.size(); i++ )
    {
    Scalar color1 = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
    drawContours( drawing, contours, i, color1, 1, 8, vector<Vec4i>(), 0, Point() );
    Scalar color2 = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
    drawContours( drawing, hull, i, color2, 1, 8, vector<Vec4i>(), 0, Point() );
    int tt = contourArea(contours[i]);
    printf("轮廓面积%d = %d ", i, tt);
    if( tt > area)
    {
    area = contourArea(contours[i]);
    k = i;
    }

    }

    if (!isContourConvex(contours[k]) &&contours[k].size() > 3)
    {
    vector<int> convexHull_IntIdx;
    vector<Vec4i> defects;
    convexHull(contours[k], convexHull_IntIdx, true);
    convexityDefects(contours[k], convexHull_IntIdx, defects);

    int defectcount = 0;
    for(i=0;i < defects.size();++i)
    {
    Matx<int,4,1> defectVector = defects[i];
    vector<Point> contours1 =contours[k];
    Point point1 = contours1[defectVector.val[0]];//开始点
    Point point2 = contours1[defectVector.val[1]];//结束点
    Point point3 = contours1[defectVector.val[2]];//深度点
    float dist = defectVector.val[3];
    printf("dist: %f ", dist);
    if ( defectVector.val[3] <= 10000 ) { continue; } // skip defects that are shorter than 100 pixel
    circle(drawing, point1, 3, Scalar(255,255,0), 2, CV_AA);
    circle(drawing, point2, 8, Scalar(0,255,0), 2, CV_AA);
    circle(drawing, point3, 3, Scalar(0,255,255), 2, CV_AA);
    defectcount++;
    }
    printf("指缝数目:%d ", defectcount);

    }

    程序源码:工程FirstOpenCV26

  • 相关阅读:
    2
    spring jdbcTemplate 基本使用
    Day38-数据库入门学习
    DAY37-Python入门学习-进程池与线程池、协程、gevent模块
    Python入门学习-DAY36-GIL全局解释器锁、死锁现象与递归锁、信号量、Event事件、线程queue
    Python入门学习-DAY35-线程
    Python入门学习-DAY34-开启进程的两种方法、join方法、进程之间内存空间互相隔离、进程对象其他相关的属性或方法、僵尸进程与孤儿进程、守护进程、互斥锁
    Python入门学习-DAY33-基于UDP的套接字、socketserver模块、进程简单介绍
    Python入门学习-DAY32-链接循环与通信循环,粘包问题,远程控制,文件上传与下载
    Python入门学习-DAY31-三次握手原理与四次挥手,socket
  • 原文地址:https://www.cnblogs.com/mikewolf2002/p/3427012.html
Copyright © 2020-2023  润新知