想起来做手势了,虽然OpenNI里有内置的手势识别算法,但效果似乎不是很好,于是乎就寻思着自己从头开始,包括手的侦测,跟踪,然后识别手势。不过不知道能不能做的比OpenNI内置的方法好。不管怎样先打打基础再说。于是乎拿着OpenCV瞅瞅,花了一个上午时间实验了两个内置的函数,其一为肤色检测,其二为模板匹配。下面是肤色检测代码:
#include<cv.h>
#include<highgui.h>
#include<opencv2/contrib/contrib.hpp>
#include<iostream>
using namespace std;
int main(int argc,char* argv[])
{
IplImage* image = cvLoadImage("test.jpg");
if(image == NULL)
{
cout<<"load image failed!"<<endl;
return -1;
}
IplImage* mask = cvCreateImage(cvGetSize(image),IPL_DEPTH_8U,1);
cvZero(mask);
CvAdaptiveSkinDetector skinDetector(1,CvAdaptiveSkinDetector::MORPHING_METHOD_NONE);
skinDetector.process(image,mask);
cvSet(mask,cvScalar(255),mask);
cvShowImage("image",image);
cvShowImage("mask",mask);
while(cvWaitKey(20) != 27);
cvDestroyAllWindows();
cvReleaseImage(&image);
cvReleaseImage(&mask);
return 0;
}
肤色检测被内置在opencv2/contrib/contrib.hpp里的CvAdaptiveSkinDetector类中。其主要检测函数为:
CvAdaptiveSkinDetector::process(IplImage* image, IplImage* mask);
该函数接受一个图像image,然后将检测结果返回到mask中。mask为一个二值图像,背景像素值为0,前景像素值为1。类CvAdaptiveSkinDetector只有一个构造函数:
CvAdaptiveSkinDetector(int samplingDivider = 1, int morphingMethod = MORPHING_METHOD_NONE);
第一个参数不知道是什么意思,第二个参数为一个枚举值,表示对结果所做的形态学操作,有四种选择。
输入图像: 输出结果:
模板匹配代码:
#include<cv.h>
#include<highgui.h>
#include<iostream>
using namespace std;
int main(void)
{
IplImage* palmTempl = cvLoadImage("template.jpg");
IplImage* result = NULL;
CvRect imageROI = cvRect(0,0,640,480);
for(int i=0;i<1000;i++)
{
char fileName[80];
sprintf(fileName,"image//%d.jpg",i);
IplImage* palmImage = cvLoadImage(fileName);
if(palmImage == NULL) continue;
CvSize size;
size.width = imageROI.width-palmTempl->width+1;
size.height = imageROI.height-palmTempl->height+1;
result = cvCreateImage(size,IPL_DEPTH_32F,1);
cvSetImageROI(palmImage,imageROI);
cvMatchTemplate(palmImage,palmTempl,result,CV_TM_SQDIFF);
cvResetImageROI(palmImage);
double min, max;
CvPoint minLoc;
cvMinMaxLoc(result,&min,&max,&minLoc,NULL);
minLoc.x = minLoc.x+imageROI.x;
minLoc.y = minLoc.y+imageROI.y;
CvPoint point2 = cvPoint(minLoc.x+palmTempl->width,minLoc.y+palmTempl->height);
cvRectangle(palmImage,minLoc,point2,cvScalar(255,255,255));
cvShowImage("image",palmImage);
cvReleaseImage(&palmImage);
if(cvWaitKey(10) == 27) break;
imageROI.x = minLoc.x-palmTempl->width/2>0 ? minLoc.x-palmTempl->width/2 : 0;
imageROI.y = minLoc.y-palmTempl->height/2>0 ? minLoc.y-palmTempl->height/2 : 0;
imageROI.width = 2*palmTempl->width;
imageROI.height = 2*palmTempl->height;
}
cvReleaseImage(&palmTempl);
return 0;
}
OpenCV中的template matching也可以支持imageROI,只是结果矩阵result的大小是严格限制了的,imageROI的改变必然导致result矩阵大小的改变,所以用imageROI还得颇费些周折。在每一步根据imageROI去调整result的大小。
模板图像: 运行结果:
由于只是选取了最优结果,所以只检测到了一只手。并且,由结果可知,模板匹配并不是那么robust.
附注:由于用的图像由kinect产生,故图像大小为640*480.
简单的肤色检测和模板匹配效果不是很好,需要改进。
http://blog.youkuaiyun.com/chenli2010/article/details/7046149