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 );

简单肤色算法后的效果:

 

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

过滤的代码为:

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

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

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

 

检测defect的代码如下:

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

//查找轮廓findContours( handimg1, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );printf("轮廓数目:%d\n", 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\n", 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 \n", 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\n", defectcount);

}

 

程序源码:工程FirstOpenCV26

时间: 2024-09-30 11:08:22

OpenCV学习(31) 基于defects的简单手势的相关文章

OpenCV学习(30) 轮廓defects

     上一篇教程中,我们学习了如何计算轮廓的凸包,其实对一个轮廓而言,可能它的凸包和它本身是重合的,也有可能不是重合的.比如下面左边图像的轮廓本身就是凸包,而右边图像的轮廓则不是.我们可以通过函数bool isContourConvex(InputArray contour),来判定一个轮廓是否是凸包,是的话返回true,否则false[注意测试的轮廓必须是简单轮廓,没有自交叉之类的].       对一个非凸包的轮廓而言,它包括一系列的凹陷区域,这些区域称作defect,比如下面手轮廓中,

基于PHP实现简单的随机抽奖小程序_php实例

一个抽奖小程序,概论可控,也可某个奖品在前端显示,而程序中根本不可能获得!把所有的概率x10后相加起来,新数组中每项的值等于它前几个的和加上它本身. 然后随即生成一个0到最大数之间的一个数,通过循环查看它属于那个区间,返回该区间的key. 代码如下 $prize = array( 1 => 3.5, //3.5%机率 2 => 2.5, 3 => 6, 4 => 2, 5 => 42, //42%机率 6 => 36, 7 => 2, 8 => 4, 9 =

搜索不再是基于浏览器的简单查询

摘要: 微软搜索业务总裁陆奇(Qi Lu)近日表示,在搜索框中输入关键字不是未来搜索模式.将来,用户将可以使用语音发起对话,可以用手势来表达自我.当前,微软正将必应整合到所有微软产 微软搜索业务总裁陆奇(Qi Lu)近日表示,在搜索框中输入关键字不是未来搜索模式.将来,用户将可以使用语音发起对话,可以用手势来表达自我.当前,微软正将必应整合到所有微软产品中,这些新模式将赋予微软新的契机赶超谷歌. 微软必应搜索业务主管陆奇上周在微软TechForum论坛上表示:"作为一款产品,搜索正在以深远的方式

基于ajax的简单搜索实现方法

本文实例讲述了基于ajax的简单搜索实现方法.分享给大家供大家参考,具体如下: 这里使用两个.aspx文件,一个叫Default.aspx,一个叫AjaxOperations.aspx,第一个用来输入搜索数据,后一个用来对搜索关键字进行处理.js文件夹下面还有一个testJs.js的文件,它就是ajax操作的核心部分.不错,code is cheap.看代码: testJs.js // 此函数等价于document.getElementById /document.all function $(

OpenCV学习(18) 细化算法(6)

本章我们在学习一下基于索引表的细化算法. 假设要处理的图像为二值图,前景值为1,背景值为0. 索引表细化算法使用下面的8邻域表示法: 一个像素的8邻域,我们可以用8位二进制表示,比如下面的8邻域,表示为00111000=0x38=56 我们可以枚举出各种情况下,当前像素能否删除的表,该表大小为256.它的索引即为8邻域表示的值,表中存的值为0或1,0表示当前像素不能删除,1表示可以删除.deletemark[256] 比如下图第一个表示,索引值为0,它表示孤立点,不能删除,所以deletemar

OpenCV学习(38) 人脸识别(3)

            前面我们学习了基于特征脸的人脸识别,现在我们学习一下基于Fisher脸的人脸识别,Fisher人脸识别基于LDA(线性判别算法)算法,算法的详细介绍可以参考下面两篇教程内容: http://docs.opencv.org/modules/contrib/doc/facerec/facerec_tutorial.html LDA算法细节参考: http://www.cnblogs.com/mikewolf2002/p/3435750.html   程序代码: #includ

指针-opencv学习灰度图锐化的两个函数的差别不理解

问题描述 opencv学习灰度图锐化的两个函数的差别不理解 下面是一个灰度图锐化的函数,我有两种方式实现,方式1,和方式2,居然得到的结果不一样,图片数据也不一样,请高手看一下,可能是C语言的知识掌握的不好. void my_sharpen(const cv::Mat &image, cv::Mat &result) { result.create (image.size(), image.type ()); for(int j=1; j<image.rows-1; j++) { u

[WEB开发] 基于XMLHTTP的简单实例

web|xml 樊欢 java爱好者.Email :heydaymail@hotmail.comBlog :http://heyday.blogone.net2005-8-23 引言 大家都知道可以通过post或者get获得form表单的数据,那么我们如何实现不刷新的提交直接获得页面上的数据呢?这就要借助xmlhttp协议了.xmlhttp是xmldom技术的一部分.  下面的代码就是一个很简单的例子,我们利用xmlhttp技术实现简单的用户登陆.   开始  1.简单的登录页面 login.j

Python基于twisted实现简单的web服务器_python

本文实例讲述了Python基于twisted实现简单的web服务器,分享给大家供大家参考.具体方法如下: 1. 新建htm文件夹,在这个文件夹中放入显示的网页文件 2. 在htm文件夹的同级目录下,建立web.py,web.py的内容为: from twisted.web.resource import Resource from twisted.web import server from twisted.web import static from twisted.internet impo