至于为什么要做这个小玩意,是因为之前有个学长做过,他也是学这个的,所以就想自己也做一下看能不能做出来,最后虽然,效果出来了,但不是很理想,原理很简单,就是利用远近不同,手在图像上的像素面积的大小也会改变,近则大,远则小,这也是学长给我的想法。具体的步骤如下
一:首先进行阈值分割,找到手所在的轮廓,其实可以用肤色检测出手的轮廓,在这里我没有用,如果用的话,HSV图像的话取H通道比较好,如果用YCrCb图像的话,用Cb通道则要好些
二:通过第一步找到手的轮廓后,一般手的部分是二值图像轮廓面积最大的,可以求出每帧图像中手轮廓面积的大小和前一帧的相比较,大则使指定图片放大,反之图片缩小
其实也没多少的技术含量,就是想大家指点一下,以及希望能对一些初学的同学有所帮助
程序实现:
#include "stdafx.h"
#include "cv.h"
#include "highgui.h"
#include "cxcore.h"
#include "stdio.h"
double GetContourMaxArea(int x)
{
double max = 0;
IplImage *img = 0;
CvCapture *capture = 0;
IplImage *img_gray = 0;
IplImage *erode = 0;
IplImage *img_back = 0;
IplImage *dst_gray = 0;
capture = cvCaptureFromCAM(0);
img = cvQueryFrame(capture);
/*******************************************************
对图像进行人工阈值分割
*****************************************************************/
int width = img->width;
int height = img->height;
const int R = 0;
const int G = 1;
const int B = 2;
for(int i = 0; i<height ; i++)
{
unsigned char * pgrb = (unsigned char *)(img->imageData + i*img->widthStep );
unsigned char * pdst = (unsigned char *)(img->imageData + i*img->widthStep );
for(int j = 0; j< width ; j++)
{
if(55 <pgrb[R] && 110<pgrb[G] && 105<pgrb[B] && pgrb[G])
{
pgrb[R] = 255;
pgrb[G] = 255;
pgrb[B] = 255;
}
else
{
pgrb[R] =0;
pgrb[G] = 0;
pgrb[B] =0;
}
pgrb += 3;
}
}
img_gray = cvCreateImage(cvGetSize(img) , 8 , 1);
cvCvtColor(img , img_gray , CV_BGR2GRAY);
IplImage *dst_bw = cvCreateImage(cvGetSize(img) , 8 ,1);
CvMemStorage * stor = cvCreateMemStorage(0);
CvSeq * cont = 0;
cvThreshold(img_gray , dst_bw ,0 ,20 , CV_THRESH_BINARY);
cvFindContours(dst_bw , stor , &cont , sizeof(CvContour) , CV_RETR_TREE , CV_CHAIN_APPROX_SIMPLE , cvPoint(0,0));
/**********************************************************************88
取最大的轮廓面积来比较前后两幅图像离摄像头的远近
**********************************************************************************/
for(; cont!=0 ; cont = cont->h_next)
{
if(cvContourArea(cont , CV_WHOLE_SEQ) >= max)
max = cvContourArea(cont , CV_WHOLE_SEQ);
}
cvDrawContours(img_gray , cont ,CV_RGB(255 , 0 , 0) , CV_RGB(0 , 0 , 255) , -1 , CV_FILLED , 8);
cvShowImage("haiyingyang" , img_gray);
cvReleaseImage(&img);
cvReleaseImage(&img_gray);
cvReleaseImage(&erode);
cvReleaseImage(&img_back);
cvReleaseImage(&dst_gray);
cvReleaseImage(&dst_bw);
return max;
}
int _tmain(int argc, _TCHAR* argv[])
{
/*******************************************8
定以数据类型和窗口
*************************************************/
IplImage *src = cvLoadImage("2.jpg" , 1);
int dsp_width = 320;
int dsp_height = 240;
double max1 = 0 ;
double max2 = 0 ;
int vmin = 10 ;
cvNamedWindow("haiyingyang" , 1);
cvCreateTrackbar("Threshold" , "haiyingyang" , &vmin , 256 , NULL);
cvNamedWindow("woaini" , 1);
for( ; ;)
{
max1 = GetContourMaxArea(vmin);
max2 = GetContourMaxArea(vmin);
/*****************************************************************88
差值滤波
***************************************************************************/
if((max2-max1) >= 300)
{
dsp_width += 10;
dsp_height += 10;
IplImage *change_src = 0;
change_src = cvCreateImage(cvSize(dsp_width , dsp_height) , 8 , 3);
cvResize(src , change_src);
cvShowImage("woaini" , change_src);
}
if((max1-max2) >= 300)
{
dsp_width -= 10;
dsp_height -= 10;
IplImage *change_src = 0;
change_src = cvCreateImage(cvSize(dsp_width , dsp_height) , 8 , 3);
cvResize(src , change_src);
cvShowImage("woaini" , change_src);
}
if(cvWaitKey(2) >= 0)
{
cvDestroyAllWindows();
cvReleaseImage(&src);
break;
}
}
return 0;
}
项目源代码下载:http://qinjianganying.download.csdn.net/
视频演示:http://v.youku.com/v_show/id_XMjgxNDUyMzYw.html
类似项目手模拟赛车的项目:http://download.csdn.net/source/3412836