首页 > 代码库 > 模式识别开发之项目---基于opencv的手势识别

模式识别开发之项目---基于opencv的手势识别

我使用OpenCV2.4.4的windows版本+Qt4.8.3+VS2010的编译器做了一个手势识别的小程序。

本程序主要使到了Opencv的特征训练库和最基本的图像处理的知识,包括肤色检测等等。

废话不多,先看一下基本的界面设计,以及主要功能:

相信对于Qt有一些了解的人都不会对这个界面的设计感到陌生吧!(该死,该死!)我们向下走:

紧接着是Qt导入OPenCV2.4.4的库文件:(先看一下Qt的工程文件吧)

 

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
 
  1. #-------------------------------------------------  
  2. #  
  3. # Project created by QtCreator 2013-05-25T11:16:11  
  4. #  
  5. #-------------------------------------------------  
  6.   
  7. QT       += core gui  
  8.   
  9. CONFIG += warn_off  
  10.   
  11. greaterThan(QT_MAJOR_VERSION, 4): QT += widgets  
  12.   
  13. TARGET = HandGesture  
  14. TEMPLATE = app  
  15.   
  16. INCLUDEPATH += E:/MyQtCreator/MyOpenCV/opencv/build/include  
  17.   
  18. SOURCES += main.cpp\  
  19.         handgesturedialog.cpp \  
  20.     SRC/GestrueInfo.cpp \  
  21.     SRC/AIGesture.cpp  
  22.   
  23. HEADERS  += handgesturedialog.h \  
  24.     SRC/GestureStruct.h \  
  25.     SRC/GestrueInfo.h \  
  26.     SRC/AIGesture.h  
  27.   
  28. FORMS    += handgesturedialog.ui  
  29.   
  30. #Load OpenCV runtime libs  
  31. win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10/lib/ -lopencv_core244  
  32. else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10/lib/ -lopencv_core244d  
  33.   
  34. INCLUDEPATH += $$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10  
  35. DEPENDPATH += $$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10  
  36.   
  37. win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10/lib/ -lopencv_features2d244  
  38. else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10/lib/ -lopencv_features2d244d  
  39.   
  40. INCLUDEPATH += $$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10  
  41. DEPENDPATH += $$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10  
  42.   
  43. win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10/lib/ -lopencv_haartraining_engine  
  44. else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10/lib/ -lopencv_haartraining_engined  
  45.   
  46. INCLUDEPATH += $$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10  
  47. DEPENDPATH += $$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10  
  48.   
  49. win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10/lib/ -lopencv_highgui244  
  50. else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10/lib/ -lopencv_highgui244d  
  51.   
  52. INCLUDEPATH += $$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10  
  53. DEPENDPATH += $$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10  
  54.   
  55. win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10/lib/ -lopencv_objdetect244  
  56. else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10/lib/ -lopencv_objdetect244d  
  57.   
  58. INCLUDEPATH += $$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10  
  59. DEPENDPATH += $$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10  
  60.   
  61. win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10/lib/ -lopencv_video244  
  62. else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10/lib/ -lopencv_video244d  
  63.   
  64. INCLUDEPATH += $$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10  
  65. DEPENDPATH += $$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10  
  66.   
  67. win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10/lib/ -lopencv_calib3d244  
  68. else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10/lib/ -lopencv_calib3d244d  
  69.   
  70. INCLUDEPATH += $$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10  
  71. DEPENDPATH += $$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10  
  72.   
  73. win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10/lib/ -lopencv_contrib244  
  74. else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10/lib/ -lopencv_contrib244d  
  75.   
  76. INCLUDEPATH += $$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10  
  77. DEPENDPATH += $$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10  
  78.   
  79. win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10/lib/ -lopencv_imgproc244  
  80. else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10/lib/ -lopencv_imgproc244d  
  81.   
  82. INCLUDEPATH += $$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10  
  83. DEPENDPATH += $$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10  
  84.   
  85.   
  86. win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10/lib/ -lopencv_legacy244  
  87. else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10/lib/ -lopencv_legacy244d  
  88.   
  89. INCLUDEPATH += $$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10  
  90. DEPENDPATH += $$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10  
  91.   
  92. win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10/lib/ -lopencv_ml244  
  93. else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10/lib/ -lopencv_ml244d  
  94.   
  95. INCLUDEPATH += $$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10  
  96. DEPENDPATH += $$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10  
  97.   
  98. win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10/lib/ -lopencv_photo244  
  99. else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10/lib/ -lopencv_photo244d  
  100.   
  101. INCLUDEPATH += $$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10  
  102. DEPENDPATH += $$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10  
  103.   
  104. win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10/lib/ -lopencv_nonfree244  
  105. else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10/lib/ -lopencv_nonfree244d  
  106.   
  107. INCLUDEPATH += $$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10  
  108. DEPENDPATH += $$PWD/../../../MyQtCreator/MyOpenCV/opencv/build/x86/vc10  


当做好以上的基本配置之后,我们进行手势识别的开发:

 

 

第一:要采集到原始的图片

采集好原始图片后进行修正,包括尺寸大小,那时我还使用到了matlab这个强大的工具,

紧接着进行图像的样本特征提取,到网上把,CSDN中有大量的关于对图像特征训练库的识别与训练,按照他们一步一步的操作模式不会有问题的饿

下面是要通过摄像头进行图像的采集,直接贴代码:

 

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
 
  1. void HandGestureDialog::on_pushButton_OpenCamera_clicked()  
  2. {  
  3.     cam = cvCreateCameraCapture(0);  
  4.     timer->start(time_intervals);  
  5.     frame = cvQueryFrame(cam);  
  6.   
  7.     ui->pushButton_OpenCamera->setDisabled (true);  
  8.     ui->pushButton_CloseCamera->setEnabled (true);  
  9.     ui->pushButton_ShowPause->setEnabled (true);  
  10.     ui->pushButton_SnapImage->setEnabled (true);  
  11.     afterSkin = cvCreateImage (cvSize(frame->width,frame->height),IPL_DEPTH_8U,1);  
  12. }  

 

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
 
  1. void HandGestureDialog::readFarme()  
  2. {  
  3.     frame = cvQueryFrame(cam);  
  4.     QImage image((const uchar*)frame->imageData,  
  5.                  frame->width,  
  6.                  frame->height,  
  7.                  QImage::Format_RGB888);  
  8.     image = image.rgbSwapped();  
  9.     image = image.scaled(320,240);  
  10.     ui->label_CameraShow->setPixmap(QPixmap::fromImage(image));  
  11.     gesture.SkinDetect (frame,afterSkin);  
  12.   
  13.     /*next to opencv*/  
  14.   
  15.     if(status_switch == Recongnise)  
  16.     {  
  17.         // Flips the frame into mirror image  
  18.         cvFlip(frame,frame,1);  
  19.   
  20.         // Call the function to detect and draw the hand positions  
  21.         StartRecongizeHand(frame);  
  22.     }  
  23. }  


查看一下样例图片:

 

 

 

开始训练的核心代码:

 

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
 
  1. void HandGestureDialog::on_pushButton_StartTrain_clicked()  
  2. {  
  3.     QProgressDialog* process = new QProgressDialog(this);  
  4.     process->setWindowTitle ("Traning Model");  
  5.     process->setLabelText("Processing...");  
  6.     process->setModal(true);  
  7.     process->show ();  
  8.     gesture.setMainUIPointer (this);  
  9.     gesture.Train(process);  
  10.     QMessageBox::about (this,tr("完成"),tr("手势训练模型完成"));  
  11. }  

 

 

 

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
 
  1. void CAIGesture::Train(QProgressDialog *pBar)//对指定训练文件夹里面的所有手势进行训练  
  2. {  
  3.     QString curStr = QDir::currentPath ();  
  4.     QString fp1 = "InfoDoc/gestureFeatureFile.yml";  
  5.     fp1 = curStr + "/" + fp1;  
  6.     CvFileStorage *GestureFeature=cvOpenFileStorage(fp1.toStdString ().c_str (),0,CV_STORAGE_WRITE);  
  7.     FILE* fp;  
  8.     QString fp2 = "InfoDoc/gestureFile.txt";  
  9.     fp2 = curStr + "/" + fp2;  
  10.     fp=fopen(fp2.toStdString ().c_str (),"w");  
  11.     int FolderCount=0;  
  12.   
  13.     /*获取当前的目录,然后得到当前的子目录*/  
  14.     QString trainStr = curStr;  
  15.     trainStr += "/TraningSample/";  
  16.     QDir trainDir(trainStr);  
  17.     GestureStruct gesture;  
  18.     QFileInfoList list = trainDir.entryInfoList();  
  19.   
  20.     pBar->setRange(0,list.size ()-2);  
  21.   
  22.   
  23.     for(int i=2;i<list.size ();i++)  
  24.     {  
  25.         pBar->setValue(i-1);  
  26.   
  27.         QFileInfo fileInfo = list.at (i);  
  28.         if(fileInfo.isDir () == true)  
  29.         {  
  30.             FolderCount++;  
  31.   
  32.             QString tempStr = fileInfo.fileName ();  
  33.             fprintf(fp,"%s\n",tempStr.toStdString ().c_str ());  
  34.             gesture.angleName = tempStr.toStdString ()+"angleName";  
  35.             gesture.anglechaName = tempStr.toStdString ()+"anglechaName";  
  36.             gesture.countName = tempStr.toStdString ()+"anglecountName";  
  37.   
  38.             tempStr = trainStr + tempStr + "/";  
  39.             QDir subDir(tempStr);  
  40.             OneGestureTrain(subDir,GestureFeature,gesture);  
  41.         }  
  42.     }  
  43.     pBar->autoClose ();  
  44.     delete pBar;  
  45.     pBar = NULL;  
  46.     fprintf(fp,"%s%d","Hand Gesture Number: ",FolderCount);  
  47.     fclose(fp);  
  48.     cvReleaseFileStorage(&GestureFeature);  
  49. }  

 

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
 
  1. void CAIGesture::OneGestureTrain(QDir GestureDir,CvFileStorage *fs,GestureStruct gesture)//对单张图片进行训练  
  2. {     
  3.     IplImage* TrainImage=0;  
  4.     IplImage* dst=0;  
  5.     CvSeq* contour=NULL;  
  6.     CvMemStorage* storage;  
  7.     storage = cvCreateMemStorage(0);  
  8.     CvPoint center=cvPoint(0,0);  
  9.     float radius=0.0;  
  10.     float angle[FeatureNum][10]={0},anglecha[FeatureNum][10]={0},anglesum[FeatureNum][10]={0},anglechasum[FeatureNum][10]={0};  
  11.     float count[FeatureNum]={0},countsum[FeatureNum]={0};  
  12.   
  13.     int FileCount=0;  
  14.     /*读取该目录下的所有jpg文件*/  
  15.     QFileInfoList list = GestureDir.entryInfoList();  
  16.     QString currentDirPath = GestureDir.absolutePath ();  
  17.     currentDirPath += "/";  
  18.     for(int k=2;k<list.size ();k++)  
  19.     {  
  20.         QFileInfo tempInfo = list.at (k);  
  21.         if(tempInfo.isFile () == true)  
  22.         {  
  23.             QString fileNamePath = currentDirPath + tempInfo.fileName ();  
  24.             TrainImage=cvLoadImage(fileNamePath.toStdString ().c_str(),1);  
  25.             if(TrainImage==NULL)  
  26.             {  
  27.                 cout << "can‘t load image" << endl;  
  28.                 cvReleaseMemStorage(&storage);  
  29.                 cvReleaseImage(&dst);  
  30.                 cvReleaseImage(&TrainImage);  
  31.                 return;  
  32.             }  
  33.             if(dst==NULL&&TrainImage!=NULL)  
  34.                 dst=cvCreateImage(cvGetSize(TrainImage),8,1);  
  35.             SkinDetect(TrainImage,dst);  
  36.             FindBigContour(dst,contour,storage);  
  37.             cvZero(dst);  
  38.             cvDrawContours( dst, contour, CV_RGB(255,255,255),CV_RGB(255,255,255), -1, -1, 8 );  
  39.             ComputeCenter(contour,center,radius);  
  40.   
  41.             GetFeature(dst,center,radius,angle,anglecha,count);  
  42.             for(int j=0;j<FeatureNum;j++)  
  43.             {  
  44.                 countsum[j]+=count[j];  
  45.                 for(int k=0;k<10;k++)  
  46.                 {  
  47.                     anglesum[j][k]+=angle[j][k];  
  48.                     anglechasum[j][k]+=anglecha[j][k];  
  49.                 }  
  50.             }  
  51.             FileCount++;  
  52.             cvReleaseImage(&TrainImage);  
  53.         }  
  54.     }  
  55.     for(int i=0;i<FeatureNum;i++)  
  56.     {  
  57.         gesture.count[i]=countsum[i]/FileCount;  
  58.         for(int j=0;j<10;j++)  
  59.         {  
  60.             gesture.angle[i][j]=anglesum[i][j]/FileCount;  
  61.             gesture.anglecha[i][j]=anglechasum[i][j]/FileCount;  
  62.         }  
  63.     }  
  64.     cvStartWriteStruct(fs,gesture.angleName.c_str (),CV_NODE_SEQ,NULL);//开始写入yml文件  
  65.   
  66.     int i=0;  
  67.     for(i=0;i<FeatureNum;i++)  
  68.         cvWriteRawData(fs,&gesture.angle[i][0],10,"f");//写入肤色角度的值  
  69.   
  70.     cvEndWriteStruct(fs);  
  71.     cvStartWriteStruct(fs,gesture.anglechaName.c_str (),CV_NODE_SEQ,NULL);  
  72.   
  73.     for(i=0;i<FeatureNum;i++)  
  74.         cvWriteRawData(fs,&gesture.anglecha[i][0],10,"f");//写入非肤色角度的值  
  75.   
  76.     cvEndWriteStruct(fs);  
  77.     cvStartWriteStruct(fs,gesture.countName.c_str (),CV_NODE_SEQ,NULL);  
  78.     cvWriteRawData(fs,&gesture.count[0],FeatureNum,"f");//写入肤色角度的个数  
  79.     cvEndWriteStruct(fs);  
  80.   
  81.     cvReleaseMemStorage(&storage);  
  82.     cvReleaseImage(&dst);  
  83. }  

 

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
 
  1. void CAIGesture::SkinDetect(IplImage* src,IplImage* dst)  
  2. {  
  3.     IplImage* hsv = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 3);//use to split to HSV  
  4.     IplImage* tmpH1 = cvCreateImage( cvGetSize(src), IPL_DEPTH_8U, 1);//Use To Skin Detect  
  5.     IplImage* tmpS1 = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);  
  6.     IplImage* tmpH2 = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);  
  7.     IplImage* tmpS3 = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);  
  8.     IplImage* tmpH3 = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);  
  9.     IplImage* tmpS2 = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);  
  10.     IplImage* H = cvCreateImage( cvGetSize(src), IPL_DEPTH_8U, 1);  
  11.     IplImage* S = cvCreateImage( cvGetSize(src), IPL_DEPTH_8U, 1);  
  12.     IplImage* V = cvCreateImage( cvGetSize(src), IPL_DEPTH_8U, 1);  
  13.     IplImage* src_tmp1=cvCreateImage(cvGetSize(src),8,3);  
  14.   
  15.     cvSmooth(src,src_tmp1,CV_GAUSSIAN,3,3); //Gaussian Blur  
  16.     cvCvtColor(src_tmp1, hsv, CV_BGR2HSV );//Color Space to Convert  
  17.     cvCvtPixToPlane(hsv,H,S,V,0);//To Split 3 channel  
  18.   
  19.     /*********************Skin Detect**************/  
  20.     cvInRangeS(H,cvScalar(0.0,0.0,0,0),cvScalar(20.0,0.0,0,0),tmpH1);  
  21.     cvInRangeS(S,cvScalar(75.0,0.0,0,0),cvScalar(200.0,0.0,0,0),tmpS1);  
  22.     cvAnd(tmpH1,tmpS1,tmpH1,0);  
  23.   
  24.     // Red Hue with Low Saturation  
  25.     // Hue 0 to 26 degree and Sat 20 to 90  
  26.     cvInRangeS(H,cvScalar(0.0,0.0,0,0),cvScalar(13.0,0.0,0,0),tmpH2);  
  27.     cvInRangeS(S,cvScalar(20.0,0.0,0,0),cvScalar(90.0,0.0,0,0),tmpS2);  
  28.     cvAnd(tmpH2,tmpS2,tmpH2,0);  
  29.   
  30.     // Red Hue to Pink with Low Saturation  
  31.     // Hue 340 to 360 degree and Sat 15 to 90  
  32.     cvInRangeS(H,cvScalar(170.0,0.0,0,0),cvScalar(180.0,0.0,0,0),tmpH3);  
  33.     cvInRangeS(S,cvScalar(15.0,0.0,0,0),cvScalar(90.,0.0,0,0),tmpS3);  
  34.     cvAnd(tmpH3,tmpS3,tmpH3,0);  
  35.   
  36.     // Combine the Hue and Sat detections  
  37.     cvOr(tmpH3,tmpH2,tmpH2,0);  
  38.     cvOr(tmpH1,tmpH2,tmpH1,0);  
  39.   
  40.     cvCopy(tmpH1,dst);  
  41.   
  42.     cvReleaseImage(&hsv);  
  43.     cvReleaseImage(&tmpH1);  
  44.     cvReleaseImage(&tmpS1);  
  45.     cvReleaseImage(&tmpH2);  
  46.     cvReleaseImage(&tmpS2);  
  47.     cvReleaseImage(&tmpH3);  
  48.     cvReleaseImage(&tmpS3);  
  49.     cvReleaseImage(&H);  
  50.     cvReleaseImage(&S);  
  51.     cvReleaseImage(&V);  
  52.     cvReleaseImage(&src_tmp1);  
  53. }  

 

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
 
  1. //To Find The biggest Countour  
  2. void CAIGesture::FindBigContour(IplImage* src,CvSeq* (&contour),CvMemStorage* storage)  
  3. {  
  4.     CvSeq* contour_tmp,*contourPos;  
  5.     int contourcount=cvFindContours(src, storage, &contour_tmp, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_NONE );  
  6.     if(contourcount==0)  
  7.         return;  
  8.     CvRect bndRect = cvRect(0,0,0,0);  
  9.     double contourArea,maxcontArea=0;  
  10.     for( ; contour_tmp != 0; contour_tmp = contour_tmp->h_next )  
  11.     {  
  12.         bndRect = cvBoundingRect( contour_tmp, 0 );  
  13.         contourArea=bndRect.width*bndRect.height;  
  14.         if(contourArea>=maxcontArea)//find Biggest Countour  
  15.         {  
  16.             maxcontArea=contourArea;  
  17.             contourPos=contour_tmp;  
  18.         }  
  19.     }  
  20.     contour=contourPos;  
  21. }  

 

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
 
  1. //Calculate The Center  
  2. void CAIGesture::ComputeCenter(CvSeq* (&contour),CvPoint& center,float& radius)  
  3. {  
  4.     CvMoments m;  
  5.     double M00,X,Y;  
  6.     cvMoments(contour,&m,0);  
  7.     M00=cvGetSpatialMoment(&m,0,0);  
  8.     X=cvGetSpatialMoment(&m,1,0)/M00;  
  9.     Y=cvGetSpatialMoment(&m,0,1)/M00;  
  10.   
  11.     center.x=(int)X;  
  12.     center.y=(int)Y;  
  13.   
  14.     /*******************tO find radius**********************/  
  15.     int hullcount;  
  16.     CvSeq* hull;  
  17.     CvPoint pt;  
  18.     double tmpr1,r=0;  
  19.     hull=cvConvexHull2(contour,0,CV_COUNTER_CLOCKWISE,0);  
  20.     hullcount=hull->total;  
  21.     for(int i=1;i<hullcount;i++)  
  22.     {  
  23.         pt=**CV_GET_SEQ_ELEM(CvPoint*,hull,i);//get each point  
  24.         tmpr1=sqrt((double)((center.x-pt.x)*(center.x-pt.x))+(double)((center.y-pt.y)*(center.y-pt.y)));//计算与中心点的大小  
  25.         if(tmpr1>r)//as the max radius  
  26.             r=tmpr1;  
  27.     }  
  28.     radius=r;  
  29. }  

 

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
 
  1. void CAIGesture::GetFeature(IplImage* src,CvPoint& center,float radius,  
  2.                             float angle[FeatureNum][10],  
  3. float anglecha[FeatureNum][10],  
  4. float count[FeatureNum])  
  5. {  
  6.     int width=src->width;  
  7.     int height=src->height;  
  8.     int step=src->widthStep/sizeof(uchar);  
  9.     uchar* data=http://www.mamicode.com/(uchar*)src->imageData;
  10.   
  11.     float R=0.0;  
  12.     int a1,b1,x1,y1,a2,b2,x2,y2;//the distance of the center to other point  
  13.     float angle1_tmp[200]={0},angle2_tmp[200]={0},angle1[50]={0},angle2[50]={0};//temp instance to calculate angule  
  14.     int angle1_tmp_count=0,angle2_tmp_count=0,angle1count=0,angle2count=0,anglecount=0;  
  15.   
  16.     for(int i=0;i<FeatureNum;i++)//分FeatureNum层进行特征提取(也就是5层)分析  
  17.     {  
  18.         R=(i+4)*radius/9;  
  19.         for(int j=0;j<=3600;j++)  
  20.         {  
  21.             if(j<=900)  
  22.             {  
  23.                 a1=(int)(R*sin(j*3.14/1800));//这个要自己实际画一张图就明白了  
  24.                 b1=(int)(R*cos(j*3.14/1800));  
  25.                 x1=center.x-b1;  
  26.                 y1=center.y-a1;  
  27.                 a2=(int)(R*sin((j+1)*3.14/1800));  
  28.                 b2=(int)(R*cos((j+1)*3.14/1800));  
  29.                 x2=center.x-b2;  
  30.                 y2=center.y-a2;  
  31.             }  
  32.             else  
  33.             {  
  34.                 if(j>900&&j<=1800)  
  35.                 {  
  36.                     a1=(int)(R*sin((j-900)*3.14/1800));  
  37.                     b1=(int)(R*cos((j-900)*3.14/1800));  
  38.                     x1=center.x+a1;  
  39.                     y1=center.y-b1;  
  40.                     a2=(int)(R*sin((j+1-900)*3.14/1800));  
  41.                     b2=(int)(R*cos((j+1-900)*3.14/1800));  
  42.                     x2=center.x+a2;  
  43.                     y2=center.y-b2;  
  44.                 }  
  45.                 else  
  46.                 {  
  47.                     if(j>1800&&j<2700)  
  48.                     {  
  49.                         a1=(int)(R*sin((j-1800)*3.14/1800));  
  50.                         b1=(int)(R*cos((j-1800)*3.14/1800));  
  51.                         x1=center.x+b1;  
  52.                         y1=center.y+a1;  
  53.                         a2=(int)(R*sin((j+1-1800)*3.14/1800));  
  54.                         b2=(int)(R*cos((j+1-1800)*3.14/1800));  
  55.                         x2=center.x+b2;  
  56.                         y2=center.y+a2;  
  57.                     }  
  58.                     else  
  59.                     {  
  60.                         a1=(int)(R*sin((j-2700)*3.14/1800));  
  61.                         b1=(int)(R*cos((j-2700)*3.14/1800));  
  62.                         x1=center.x-a1;  
  63.                         y1=center.y+b1;  
  64.                         a2=(int)(R*sin((j+1-2700)*3.14/1800));  
  65.                         b2=(int)(R*cos((j+1-2700)*3.14/1800));  
  66.                         x2=center.x-a2;  
  67.                         y2=center.y+b2;  
  68.                     }  
  69.                 }  
  70.             }  
  71.   
  72.             if(x1>0&&x1<width&&x2>0&&x2<width&&y1>0&&y1<height&&y2>0&&y2<height)  
  73.             {  
  74.                 if((int)data[y1*step+x1]==255&&(int)data[y2*step+x2]==0)  
  75.                 {  
  76.                     angle1_tmp[angle1_tmp_count]=(float)(j*0.1);//从肤色到非肤色的角度  
  77.                     angle1_tmp_count++;  
  78.                 }  
  79.                 else if((int)data[y1*step+x1]==0&&(int)data[y2*step+x2]==255)  
  80.                 {  
  81.                     angle2_tmp[angle2_tmp_count]=(float)(j*0.1);//从非肤色到肤色的角度  
  82.                     angle2_tmp_count++;  
  83.                 }  
  84.             }  
  85.         }  
  86.         int j=0;  
  87.         for(j=0;j<angle1_tmp_count;j++)  
  88.         {  
  89.             if(angle1_tmp[j]-angle1_tmp[j-1]<0.2)//忽略太小的角度  
  90.                 continue;  
  91.             angle1[angle1count]=angle1_tmp[j];  
  92.             angle1count++;  
  93.         }  
  94.   
  95.         for(j=0;j<angle2_tmp_count;j++)  
  96.         {  
  97.             if(angle2_tmp[j]-angle2_tmp[j-1]<0.2)  
  98.                 continue;  
  99.             angle2[angle2count]=angle2_tmp[j];  
  100.             angle2count++;  
  101.         }  
  102.   
  103.         for(j=0;j<max(angle1count,angle2count);j++)  
  104.         {  
  105.             if(angle1[0]>angle2[0])  
  106.             {  
  107.                 if(angle1[j]-angle2[j]<7)//忽略小于7度的角度,因为人的手指一般都大于这个值  
  108.                     continue;  
  109.                 angle[i][anglecount]=(float)((angle1[j]-angle2[j])*0.01);//肤色的角度  
  110.                 anglecha[i][anglecount]=(float)((angle2[j+1]-angle1[j])*0.01);//非肤色的角度,例如手指间的角度  
  111.                 anglecount++;  
  112.             }  
  113.             else  
  114.             {  
  115.                 if(angle1[j+1]-angle2[j]<7)  
  116.                     continue;  
  117.                 anglecount++;  
  118.                 angle[i][anglecount]=(float)((angle1[j+1]-angle2[j])*0.01);  
  119.                 anglecha[i][anglecount]=(float)((angle2[j]-angle1[j])*0.01);  
  120.             }  
  121.         }  
  122.   
  123.         if(angle1[0]<angle2[0])  
  124.             angle[i][0]=(float)((angle1[0]+360-angle2[angle2count-1])*0.01);  
  125.         else  
  126.             anglecha[i][0]=(float)((angle2[0]+360-angle1[angle1count-1])*0.01);  
  127.   
  128.         count[i]=(float)anglecount;  
  129.         angle1_tmp_count=0,angle2_tmp_count=0,angle1count=0,angle2count=0,anglecount=0;  
  130.         for(j=0;j<200;j++)  
  131.         {  
  132.             angle1_tmp[j]=0;  
  133.             angle2_tmp[j]=0;  
  134.         }  
  135.         for(j=0;j<50;j++)  
  136.         {  
  137.             angle1[j]=0;  
  138.             angle2[j]=0;  
  139.         }  
  140.     }  
  141. }  




 

基本上对于自己使用代码创建的训练库的特征提取函数和基本的肤色检测和连通域的检测的函数的核心代码都已经贴到上面去了。

然后再看一下对于特定的手势识别的文件:

 

 

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
 
  1. void HandGestureDialog::on_pushButton_StartRecongnise_clicked()  
  2. {  
  3.     if(cam==NULL)  
  4.     {  
  5.         QMessageBox::warning (this,tr("Warning"),tr("Please Check Camera !"));  
  6.         return;  
  7.     }  
  8.   
  9.     status_switch = Nothing;  
  10.   
  11.     status_switch = Recongnise;  
  12. }  

 

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
 
  1. void HandGestureDialog::StartRecongizeHand (IplImage *img)  
  2. {  
  3.     // Create a string that contains the exact cascade name  
  4.     // Contains the trained classifer for detecting hand  
  5.     const char *cascade_name="hand.xml";  
  6.     // Create memory for calculations  
  7.     static CvMemStorage* storage = 0;  
  8.     // Create a new Haar classifier  
  9.     static CvHaarClassifierCascade* cascade = 0;  
  10.     // Sets the scale with which the rectangle is drawn with  
  11.     int scale = 1;  
  12.     // Create two points to represent the hand locations  
  13.     CvPoint pt1, pt2;  
  14.     // Looping variable  
  15.     int i;  
  16.     // Load the HaarClassifierCascade  
  17.     cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name, 0, 0, 0 );  
  18.     // Check whether the cascade has loaded successfully. Else report and error and quit  
  19.     if( !cascade )  
  20.     {  
  21.         fprintf( stderr, "ERROR: Could not load classifier cascade\n" );  
  22.         return;  
  23.     }  
  24.   
  25.     // Allocate the memory storage  
  26.     storage = cvCreateMemStorage(0);  
  27.   
  28.     // Create a new named window with title: result  
  29.     cvNamedWindow( "result", 1 );  
  30.   
  31.     // Clear the memory storage which was used before  
  32.     cvClearMemStorage( storage );  
  33.   
  34.     // Find whether the cascade is loaded, to find the hands. If yes, then:  
  35.     if( cascade )  
  36.     {  
  37.         // There can be more than one hand in an image. So create a growable sequence of hands.  
  38.         // Detect the objects and store them in the sequence  
  39.         CvSeq* hands = cvHaarDetectObjects( img, cascade, storage,  
  40.                                             1.1, 2, CV_HAAR_DO_CANNY_PRUNING,  
  41.                                             cvSize(40, 40) );  
  42.   
  43.         // Loop the number of hands found.  
  44.         for( i = 0; i < (hands ? hands->total : 0); i++ )  
  45.         {  
  46.             // Create a new rectangle for drawing the hand  
  47.             CvRect* r = (CvRect*)cvGetSeqElem( hands, i );  
  48.   
  49.             // Find the dimensions of the hand,and scale it if necessary  
  50.             pt1.x = r->x*scale;  
  51.             pt2.x = (r->x+r->width)*scale;  
  52.             pt1.y = r->y*scale;  
  53.             pt2.y = (r->y+r->height)*scale;  
  54.   
  55.             // Draw the rectangle in the input image  
  56.             cvRectangle( img, pt1, pt2, CV_RGB(230,20,232), 3, 8, 0 );  
  57.         }  
  58.     }  
  59.   
  60.     // Show the image in the window named "result"  
  61.     cvShowImage( "result", img );  
  62.     cvWaitKey (30);  
  63. }  


注意该特征文件包含了手掌半握式的手势效果较好:

 

 

 

多谢大家,这么长时间的阅读和浏览,小弟做的很粗糙还有一些地方自已也没有弄明白,希望各位大神批评指教!

 

我已把源代码上传到对应的资源中去,以便大家学习修改!

http://download.csdn.net/detail/liuguiyangnwpu/7467891

http://blog.csdn.net/berguiliu/article/details/9307495

模式识别开发之项目---基于opencv的手势识别