至於爲什麼要做這個小玩意,是因爲之前有個學長做過,他也是學這個的,所以就想自己也做一下看能不能做出來,最後雖然,效果出來了,但不是很理想,原理很簡單,就是利用遠近不同,手在圖像上的像素面積的大小也會改變,近則大,遠則小,這也是學長給我的想法。具體的步驟如下
一:首先進行閾值分割,找到手所在的輪廓,其實可以用膚色檢測出手的輪廓,在這裏我沒有用,如果用的話,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