模式识别开发之项目---基于opencv的手势识别
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
模式识别开发之项⽬---基于opencv的⼿势识别
我使⽤OpenCV2.4.4的windows版本+Qt4.8.3+VS2010的编译器做了⼀个⼿势识别的⼩程序。
本程序主要使到了Opencv的特征训练库和最基本的图像处理的知识,包括肤⾊检测等等。
废话不多,先看⼀下基本的界⾯设计,以及主要功能:
相信对于Qt有⼀些了解的⼈都不会对这个界⾯的设计感到陌⽣吧!(该死,该死!)我们向下⾛:
紧接着是Qt导⼊OPenCV2.4.4的库⽂件:(先看⼀下Qt的⼯程⽂件吧)
[cpp]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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=(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]
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]
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. }
注意该特征⽂件包含了⼿掌半握式的⼿势效果较好:
多谢⼤家,这么长时间的阅读和浏览,⼩弟做的很粗糙还有⼀些地⽅⾃已也没有弄明⽩,希望各位⼤神批评指教!
我已把源代码上传到对应的资源中去,以便⼤家学习修改!。