opencv 获取手势的轮廓

程序是以前在网站上搜到了,使用的opencv的版本为0.9.7.如果用opencv1.0的版本来编译的话有两个需要注意的地方

smooth()函数由于版本的问题参数个数不同,需进行调整,还有一个不能写时拷贝的问题,这个问题产生的原因是opencv的一个函数(具体哪个函数我忘了,编译或运行的时候会有提示)有几个参数,由于输入参数和修改后的参数是同一个造成的,解决方法是自己重新定义一个这种类型的变量,为其分配内存空间,作为该函数的输出参数就可以了。

获得手势识别的方法是根据肤色来进行的,内定了一个肤色的范围,通过肤色的二值化后再平滑处理,边缘接触,计算ROI区域,得到感兴趣区,最后将轮廓找出来。

//VERSION: HAND DETECTION 1.0
//AUTHOR: ANDOL LI@CW3/18, Live:lab
//PROJECT: HAND DETECTION PROTOTYPE
//LAST UPDATED: 03/2009

#include "cv.h"
#include "cxcore.h"
#include "highgui.h"
#include "math.h"
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <conio.h>
#include <sstream>
#include <time.h>
using namespace std;
/*
--------------------------------------------*/
int main()
{
 int c = 0;
 CvSeq* a = 0;
    CvCapture* capture = cvCaptureFromCAM(0);//从对摄像头的初始化捕获
  if(!cvQueryFrame(capture)){ cout<<"Video capture failed, please check the camera."<<endl;}else{cout<<"Video camera capture status: OK"<<endl;};
    CvSize sz = cvGetSize(cvQueryFrame( capture));//得到摄像头图像大小
 IplImage* src = cvCreateImage( sz, 8, 3 );//4通道,每个通道8位
 IplImage* hsv_image = cvCreateImage( sz, 8, 3);//
 IplImage* hsv_mask = cvCreateImage( sz, 8, 1);
 IplImage* hsv_edge = cvCreateImage( sz, 8, 1);
 
 CvScalar  hsv_min = cvScalar(0, 30, 80, 0);//得到BGR,&,每个通道的和
 CvScalar  hsv_max = cvScalar(20, 150, 255, 0);
 //
 CvMemStorage* storage = cvCreateMemStorage(0);//分配大小为0的内存空间
 CvMemStorage* areastorage = cvCreateMemStorage(0);
 CvMemStorage* minStorage = cvCreateMemStorage(0);
 CvMemStorage* dftStorage = cvCreateMemStorage(0);
 CvSeq* contours = NULL;
 //
 cvNamedWindow( "src",1);
 //在屏幕上创建一个窗口,第一个参数为窗口标题,第二个参数为窗口属性,
 //设置为0(默认值),或者CV_WINDOW_AUTOSIZE,设置为0,则窗口不会因图像的大小而改变
 //图像只能在窗口中根据窗口的大小进行拉伸或缩放;设置为CV_WINDOW_AUTOSIZE时,窗口会根据图像
 //的实际大小进行自动拉伸或缩放。
 //cvNamedWindow( "hsv-msk",1);
 //cvNamedWindow( "contour",1);
 //////
 while( c != 27)//27为ASCII键值(ESC),
 {
  IplImage* bg = cvCreateImage( sz, 8, 3);//
  cvRectangle( bg, cvPoint(0,0), cvPoint(bg->width,bg->height), CV_RGB( 255, 255, 255), -1, 8, 0 );//画矩形
   bg->origin = 1;
  for(int b = 0; b< int(bg->width/10); b++)
  {
   cvLine( bg, cvPoint(b*20, 0), cvPoint(b*20, bg->height), CV_RGB( 200, 200, 200), 1, 8, 0 );//画线
   cvLine( bg, cvPoint(0, b*20), cvPoint(bg->width, b*20), CV_RGB( 200, 200, 200), 1, 8, 0 );//画线
  }

  src = cvQueryFrame( capture);//得到一帧图像
  cvCvtColor(src, hsv_image, CV_BGR2HSV);//色彩空间转换,HSV

  cvInRangeS (hsv_image, hsv_min, hsv_max, hsv_mask);//检查数组元素是否在两个数量之间,输出新图像hsv_mask
  //cvSmooth( hsv_mask, hsv_mask, CV_MEDIAN, 27, 0, 0, 0 );

  cvSmooth( hsv_mask, hsv_mask, CV_MEDIAN, 27, 0, 0);//图像平滑,
  //CV_MEDIAN (median blur) - 对图像进行核大小为param1×param1 的中值滤波 (i.e. 邻域是方的).
  cvCanny(hsv_mask, hsv_edge, 1, 3, 5);//采用 Canny 算法做边缘检测

  cvFindContours( hsv_mask, storage, &contours, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0) );
  //对单通道图像检索轮廓,返回第一个轮廓的指针
   CvSeq* contours2 = NULL;
   double result = 0, result2 = 0;
  while(contours)
  {
   result = fabs( cvContourArea( contours, CV_WHOLE_SEQ ) );//计算感兴趣区域
   if ( result > result2) {result2 = result; contours2 = contours;};
   contours  =  contours->h_next;
  }
  if ( contours2 )
  {
   //cout << "contours2: " << contours2->total << endl;
   CvRect rect = cvBoundingRect( contours2, 0 );
   cvRectangle( bg, cvPoint(rect.x, rect.y + rect.height), cvPoint(rect.x + rect.width, rect.y), CV_RGB(200, 0, 200), 1, 8, 0 );
   //cout << "Ratio: " << rect.width << ", " << rect.height << ", " << (float)rect.width / rect.height << endl;
   int checkcxt = cvCheckContourConvexity( contours2 );
    //cout << checkcxt <<endl;
   CvSeq* hull = cvConvexHull2( contours2, 0, CV_CLOCKWISE, 0 );
   CvSeq* defect = cvConvexityDefects( contours2, hull, dftStorage );
   if( defect->total >=40 ) {cout << " Closed Palm " << endl;}
   else if( defect->total >=30 && defect->total <40 ) {cout << " Open Palm " << endl;}
   else{ cout << " Fist " << endl;}
   cout << "defet: " << defect->total << endl;

   CvBox2D box = cvMinAreaRect2( contours2, minStorage );
   //cout << "box angle: " << (int)box.angle << endl;
   cvCircle( bg, cvPoint(box.center.x, box.center.y), 3, CV_RGB(200, 0, 200), 2, 8, 0 );
   cvEllipse( bg, cvPoint(box.center.x, box.center.y), cvSize(box.size.height/2, box.size.width/2), box.angle, 0, 360, CV_RGB(220, 0, 220), 1, 8, 0 );
    //cout << "Ratio: " << (float)box.size.width/box.size.height <<endl;
  }
   //cvShowImage( "hsv-msk", hsv_mask); hsv_mask->origin = 1;
   //IplImage* contour = cvCreateImage( sz, 8, 3 );
 
  cvDrawContours( bg, contours2,  CV_RGB( 0, 200, 0), CV_RGB( 0, 100, 0), 1, 1, 8, cvPoint(0,0));
   cvShowImage( "src", src);
   //contour->origin = 1; cvShowImage( "contour", contour);
   //cvReleaseImage( &contour);

  cvNamedWindow("bg",0);
  cvShowImage("bg",bg);
  cvReleaseImage( &bg);

 


  c = cvWaitKey( 10);
 }
 //////
 cvReleaseCapture( &capture);
 cvDestroyAllWindows();

}

下面的程序是我后来修改过的,上面说的两个错误已修改,添加了注释,但我为了做一些测试改了几个语句,也发上来吧,

--------------------------------------------*/
int main()
{
 int c = 0;
 CvSeq* a = 0;
    CvCapture* capture = cvCaptureFromCAM(0);//从对摄像头的初始化捕获
  if(!cvQueryFrame(capture))  cout<<"Video capture failed, please check the camera."<<endl;
  else cout<<"Video camera capture status: OK"<<endl;
    CvSize sz = cvGetSize(cvQueryFrame( capture));//得到摄像头图像大小
 IplImage* src = cvCreateImage( sz, 8, 3 );//3通道,每个通道8位
 IplImage* hsv_image = cvCreateImage( sz, 8, 3);//
 IplImage* hsv_mask = cvCreateImage( sz, 8, 1);
 IplImage* hsv_mask2 = cvCreateImage( sz, 8, 1);
 IplImage* hsv_edge = cvCreateImage( sz, 8, 1);
 
 CvScalar  hsv_min = cvScalar(0, 30, 80, 0);//最小像素的RGB值
 CvScalar  hsv_max = cvScalar(20, 150, 255, 0);//最大像素的RGB值
 //CvScalar  hsv_min = cvScalar(30, 30, 30, 0);//最小像素的RGB值
 //CvScalar  hsv_max = cvScalar(200, 200, 200, 0);//最大像素的RGB值
 //
 CvMemStorage* storage = cvCreateMemStorage(0);//分配大小为0的内存空间
 CvMemStorage* areastorage = cvCreateMemStorage(0);
 CvMemStorage* minStorage = cvCreateMemStorage(0);
 CvMemStorage* dftStorage = cvCreateMemStorage(0);
 CvSeq* contours = NULL;
 //
 cvNamedWindow( "src",1);
 //在屏幕上创建一个窗口,第一个参数为窗口标题,第二个参数为窗口属性,
 //设置为0(默认值),或者CV_WINDOW_AUTOSIZE,设置为0,则窗口不会因图像的大小而改变
 //图像只能在窗口中根据窗口的大小进行拉伸或缩放;设置为CV_WINDOW_AUTOSIZE时,窗口会根据图像
 //的实际大小进行自动拉伸或缩放。
 //cvNamedWindow( "hsv-msk",1);
 //cvNamedWindow( "contour",1);
 //////
 IplImage * background=cvLoadImage("002.jpg");
 CvRect rect=cvRect(0,0,background->width,background->height);
 cvSetImageROI(background,rect);
 IplImage * src3=cvCreateImage(cvGetSize(background),background->depth,background->nChannels);

 while( c != 27)//27为ASCII键值(ESC),
 {
  IplImage* bg = cvCreateImage( sz, 8, 3);//
  cvRectangle( bg, cvPoint(0,0), cvPoint(bg->width,bg->height), CV_RGB( 255, 255, 255), -1, 8, 0 );//画矩形,参数:Image,两个顶点坐标,线的颜色,线的厚度
   bg->origin = 1;
  for(int b = 0; b< int(bg->width/10); b++)//画网格
  {
   cvLine( bg, cvPoint(b*20, 0), cvPoint(b*20, bg->height), CV_RGB( 200, 200, 200), 1, 8, 0 );//画竖线
   cvLine( bg, cvPoint(0, b*20), cvPoint(bg->width, b*20), CV_RGB( 200, 200, 200), 1, 8, 0 );//画横线
  }

  src = cvQueryFrame( capture);//得到一帧图像
  
  cvCvtColor(src, hsv_image, CV_BGR2HSV);//色彩空间转换,HSV

  cvInRangeS (hsv_image, hsv_min, hsv_max, hsv_mask);//检查数组元素是否在两个数量之间,输出新图像hsv_mask,从3通道到1通道
  //hsv_mask的数据要么为0,要么为1,在min和max范围内为1,得到ROI区域,找到在像素RGB范围内的数据
  //cvSmooth( hsv_mask, hsv_mask, CV_MEDIAN, 27, 0, 0, 0 );

  cvSmooth( hsv_mask, hsv_mask2, CV_MEDIAN, 27, 0, 0);//图像平滑,
  //CV_MEDIAN (median blur) - 对图像进行核大小为param1×param1 的中值滤波 (i.e. 邻域是方的).
  cvCanny(hsv_mask2, hsv_edge, 1, 3, 5);
  //cvCanny(hsv_mask, hsv_edge, 1, 3, 5);//采用 Canny 算法做边缘检测

  cvFindContours( hsv_mask, storage, &contours, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0) );
  //对单通道图像检索轮廓,返回第一个轮廓的指针
   CvSeq* contours2 = NULL;
   double result = 0, result2 = 0;
  while(contours)//得到最大的两个感兴趣区
  {
   result = fabs( cvContourArea( contours, CV_WHOLE_SEQ ) );//计算感兴趣区域的像素点数
   if ( result > result2) {result2 = result; contours2 = contours;};
   contours  =  contours->h_next;
  }
  if ( contours2 )//最大的感兴趣区,ROI
  {
   //cout << "contours2: " << contours2->total << endl;
   CvRect rect = cvBoundingRect( contours2, 0 );//返回一个2d矩形的点集合
   cvRectangle( bg, cvPoint(rect.x, rect.y + rect.height), cvPoint(rect.x + rect.width, rect.y), CV_RGB(200, 0, 200), 1, 8, 0 );
   //在bg的矩形区域中画rect的图形
   //cout << "Ratio: " << rect.width << ", " << rect.height << ", " << (float)rect.width / rect.height << endl;
   int checkcxt = cvCheckContourConvexity( contours2 );//检测输入的轮廓是否是凸的
    //cout << checkcxt <<endl;
   CvSeq* hull = cvConvexHull2( contours2, 0, CV_CLOCKWISE, 0 );//二维凸包
   CvSeq* defect = cvConvexityDefects( contours2, hull, dftStorage );//凸包中的缺陷
   if( defect->total >=40 ) {cout << " Closed Palm " << endl;}
   else if( defect->total >=30 && defect->total <40 ) {cout << " Open Palm " << endl;}
   else{ cout << " Fist " << endl;}
   cout << "defet: " << defect->total << endl;

   CvBox2D box = cvMinAreaRect2( contours2, minStorage );//包围所有点的轮廓的最小矩形
   //cout << "box angle: " << (int)box.angle << endl;
   cvCircle( bg, cvPoint(box.center.x, box.center.y), 3, CV_RGB(200, 0, 200), 2, 8, 0 );//画圆
   cvEllipse( bg, cvPoint(box.center.x, box.center.y), cvSize(box.size.height/2, box.size.width/2), box.angle, 0, 360, CV_RGB(220, 0, 220), 1, 8, 0 );//椭圆
    //cout << "Ratio: " << (float)box.size.width/box.size.height <<endl;
  }
   //cvShowImage( "hsv-msk", hsv_mask); hsv_mask->origin = 1;
   //IplImage* contour = cvCreateImage( sz, 8, 3 );
 
   cvDrawContours( bg, contours2,  CV_RGB( 0, 200, 0), CV_RGB( 0, 100, 0), 1, 1, 8, cvPoint(0,0));//绘制轮廓的图像到bg图像中
 
   cvShowImage( "src", src);
   //cvShowImage("src",src3);
   //contour->origin = 1; cvShowImage( "contour", contour);
   //cvReleaseImage( &contour);

  cvNamedWindow("bg",0);
  cvShowImage("bg",bg);
  cvNamedWindow( "ROI",0);
  cvShowImage("ROI",hsv_mask2);
  //cvShowImage("ROI",hsv_mask2);
  cvReleaseImage( &bg);

  c = cvWaitKey( 10);
 }
 //////
 cvReleaseCapture( &capture);
 cvDestroyAllWindows();

}

 

 

你可能感兴趣的:(算法,image,video,float,Palm,math.h)