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\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

你可能感兴趣的:(opencv)