11月份有一个项目需要用到手势识别功能,google之,大爱OpenCv,记录下自己的学习历程,让我们为互联网的开源精神Cheers.
项目采用Qt + Opencv + win7环境下实现
一、
首先我们要 win7下配置OpenCV的Qt开发环境,具体参考如下
http://blog.csdn.net/qiurisuixiang/article/details/8665278
当你的test code 成功实现一张图片显示的时候,congratulate you,你的环境已经搭建成功了。
二、
做完初步的环境搭建,让我们来做一些好玩的事情,实现对一个物体的背景轮廓分离。这里我采用了大津算法,初步实现了背景和背景的分离。
贴Code
#include"cv.h" #include"cxcore.h" #include"highgui.h" void cvThresholdOtsu(IplImage* src, IplImage* dst) { int height=src->height; int width=src->width; //histogram float histogram[256]={0}; for(int i=0;i<height;i++) { unsigned char* p=(unsigned char*)src->imageData+src->widthStep*i; for(int j=0;j<width;j++) { histogram[*p++]++; } } //normalize histogram int size=height*width; for(int i=0;i<256;i++) { histogram[i]=histogram[i]/size; } //average pixel value float avgValue=0; for(int i=0;i<256;i++) { avgValue+=i*histogram[i]; } int threshold; float maxVariance=0; float w=0,u=0; //自适应阈值 for(int i=0;i<256;i++) { w+=histogram[i]; u+=i*histogram[i]; float t=avgValue*w-u; float variance=t*t/(w*(1-w)); if(variance>maxVariance) { maxVariance=variance; threshold=i; } } cvThreshold(src,dst,threshold,255,CV_THRESH_BINARY);//设置阈值 } void cvSkinOtsu(IplImage* src, IplImage* dst) { assert(dst->nChannels==1&& src->nChannels==3); IplImage* ycrcb=cvCreateImage(cvGetSize(src),8,3); IplImage* cr=cvCreateImage(cvGetSize(src),8,1); cvCvtColor(src,ycrcb,CV_BGR2YCrCb); cvSplit(ycrcb,0,cr,0,0); cvThresholdOtsu(cr,cr); cvCopyImage(cr,dst); cvReleaseImage(&cr); cvReleaseImage(&ycrcb); } int main(int argc,char *argv[]) { IplImage *src=cvLoadImage("E:/hand.jpg",1); IplImage *binary_img=cvCreateImage(cvGetSize(src),8,1); cvSkinOtsu(src, binary_img); CvMemStorage *pcvMStorage = cvCreateMemStorage(); CvSeq *pcvSeq = NULL; cvFindContours(binary_img, pcvMStorage, &pcvSeq, sizeof(CvContour),\ CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0, 0)); IplImage *pOutlineImage = cvCreateImage(cvGetSize(binary_img), IPL_DEPTH_8U, 3); cvDrawContours(pOutlineImage, pcvSeq, CV_RGB(255,0,0), CV_RGB(0,255,0), 5, 2); cvNamedWindow("Image",1); cvNamedWindow("binary",1); cvNamedWindow("end",1); cvShowImage("Image",src); cvShowImage("binary",binary_img); cvShowImage("end", pOutlineImage); cvWaitKey(0); cvDestroyWindow("Image"); cvReleaseImage(&src); cvDestroyWindow("binary"); cvReleaseImage(&binary_img); cvDestroyWindow("end"); cvReleaseImage(&pOutlineImage); return 0; }
通过以上代码我们可以实现初步的轮廓提取,贴上一张图
具体的实现算法google之,简要概括就是通过类间方差识别出手掌和背景的分离指标,用这个算出手掌和背景的分离阈值,从而对图像二值化,最后使用cvFindContours对二值化图像寻找轮廓显示。未完待续。