最近看到有人用flash和摄像头做了一个互动游戏觉得很好玩,就 利用OpenCV的库函数和VC仿照也做了个类似的呵呵。效果不是很好,拿出来献丑了。下面介绍一下,电脑上连接一个摄像头,启动程序后在视频窗口中就会有两个跳动的黄色小球作为你攻击的目标(小球本来是要做成漂浮的泡泡的,没找到动力学方程,就随便设计了一个),还有一个白色的十字圈作为你的准星。拥有一个红的物体在摄像头前晃动来操纵你的准星,当准星击中黄色小球的时候小球就会消失。(这个游戏需要OpenCV beta5 的动态连接库的支持。还要在当前目录下放置一副320×240的命名为gun.bmp的图,我用的就是图中的这张卡,通过它来决定你能用什么颜色的物体操纵你的准星,是不是很烦啊呵呵,没办法放假回家之前的产物啊:)
好了贴上源码看看吧
// auto.cpp : Defines the entry point for the console application.//
#include "stdafx.h"#include "cv.h"#include "highgui.h"#include "stdio.h"#include "ctype.h"#include "math.h"
IplImage *image = 0, *hsv = 0, *hue = 0, *mask = 0, *backproject = 0, *histimg = 0;CvHistogram *hist = 0;
int backproject_mode = 0;int select_object = 0;int track_object = 0;int show_hist = 1;
int Xn=0;int Yn=0;int Xn2=0;int Yn2=0;
CvPoint origin;CvPoint trackPoint;CvRect selection;CvRect track_window;CvBox2D track_box;CvConnectedComp track_comp;int hdims = 16;float hranges_arr[] = {0,180};float* hranges = hranges_arr;int vmin = 90, vmax = 256, smin = 90;
CvScalar hsv2rgb( float hue );
//加载预定图像void loadTemplateImage(){ IplImage *tempimage = cvLoadImage("gun.bmp",1); cvCvtColor( tempimage, hsv, CV_BGR2HSV ); int _vmin = vmin, _vmax = vmax;
cvInRangeS( hsv, cvScalar(0,smin,MIN(_vmin,_vmax),0), cvScalar(180,256,MAX(_vmin,_vmax),0), mask ); cvSplit( hsv, hue, 0, 0, 0 ); selection.x = 1; selection.y = 1; selection.width = 320-1; selection.height= 240-1;
cvSetImageROI( hue, selection ); cvSetImageROI( mask, selection ); cvCalcHist( &hue, hist, 0, mask );
float max_val = 0.f; cvGetMinMaxHistValue( hist, 0, &max_val, 0, 0 ); cvConvertScale( hist->bins, hist->bins, max_val ? 255. / max_val : 0., 0 ); cvResetImageROI( hue ); cvResetImageROI( mask ); track_window = selection; track_object = 1;
cvZero( histimg ); int bin_w = histimg->width / hdims; for(int i = 0; i < hdims; i++ ) { int val = cvRound( cvGetReal1D(hist->bins,i)*histimg->height/255 ); CvScalar color = hsv2rgb(i*180.f/hdims); cvRectangle( histimg, cvPoint(i*bin_w,histimg->height), cvPoint((i+1)*bin_w,histimg->height - val), color, -1, 8, 0 ); }
cvReleaseImage(&tempimage);
}
//鼠标事件回调函数void on_mouse( int event, int x, int y, int flags, void* param ){ if( !image ) return;
if( image->origin ) y = image->height - y;
if( select_object ) { selection.x = MIN(x,origin.x); selection.y = MIN(y,origin.y); selection.width = selection.x + CV_IABS(x - origin.x); selection.height = selection.y + CV_IABS(y - origin.y); selection.x = MAX( selection.x, 0 ); selection.y = MAX( selection.y, 0 ); selection.width = MIN( selection.width, image->width ); selection.height = MIN( selection.height, image->height ); selection.width -= selection.x; selection.height -= selection.y; }
switch( event ) { case CV_EVENT_LBUTTONDOWN: origin = cvPoint(x,y); selection = cvRect(x,y,0,0); select_object = 1; break; case CV_EVENT_LBUTTONUP: select_object = 0; if( selection.width > 0 && selection.height > 0 ) track_object = -1; break; }}
//颜色空间CvScalar hsv2rgb( float hue ){ int rgb[3], p, sector; static const int sector_data[][3]= {{0,2,1}, {1,2,0}, {1,0,2}, {2,0,1}, {2,1,0}, {0,1,2}}; hue *= 0.033333333333333333333333333333333f; sector = cvFloor(hue); p = cvRound(255*(hue - sector)); p ^= sector & 1 ? 255 : 0;
rgb[sector_data[sector][0]] = 255; rgb[sector_data[sector][1]] = 0; rgb[sector_data[sector][2]] = p;
return cvScalar(rgb[2], rgb[1], rgb[0],0);}
//划popovoid drawCorssMark(IplImage *dst, CvPoint pt){
const int cross_len = 10; CvPoint pt1,pt2,pt3,pt4; pt1.x = pt.x; pt1.y = pt.y - cross_len; pt2.x = pt.x; pt2.y = pt.y + cross_len; pt3.x = pt.x - cross_len; pt3.y = pt.y; pt4.x = pt.x + cross_len; pt4.y = pt.y;
cvCircle( dst, pt, 10, CV_RGB(255,255,255), 2,CV_AA,0);
cvLine(dst,pt1,pt2,CV_RGB(255,255,255),2,CV_AA, 0 ); cvLine(dst,pt3,pt4,CV_RGB(255,255,255),2,CV_AA, 0 );
}
//点的移动void MovePOPO(IplImage *dst,int & Xn,int & Yn){
int Xn1= Xn+1; int i=-1; int Yn1=(int)( (Xn)+(20*sin(Xn)) ); if (Xn1 >= (dst->width)) { Xn1=0; Yn1=0; } /* image width in pixels */ if (Yn1 >=(dst->height)) { Xn1=0; Yn1=0; }
CvPoint pt=cvPoint(Xn1, Yn1); cvCircle(dst, pt, 4, CV_RGB(230,255,0), 2,CV_AA,0); Xn=Xn1; Yn=Yn1;}
void MovePOPO1(IplImage *dst,int & Xn,int & Yn){
int Xn1= Xn+2; int Yn1=(int)( (Xn)+(10*sin(Xn)) ); if (Xn1 >= (dst->width)) { Xn1=0; Yn1=0; } /* image width in pixels */ if (Yn1 >=(dst->height)) { Xn1=0; Yn1=0; } CvPoint pt=cvPoint(Xn1, Yn1); cvCircle(dst, pt, 4, CV_RGB(230,255,0), 2,CV_AA,0); Xn=Xn1; Yn=Yn1;}
int main( int argc, char** argv ){ CvCapture* capture = 0; if( argc == 1 || (argc == 2 && strlen(argv[1]) == 1 && isdigit(argv[1][0]))) capture = cvCaptureFromCAM( argc == 2 ? argv[1][0] - '0' : 0 ); else if( argc == 2 ) capture = cvCaptureFromAVI( argv[1] );
if( !capture ) { fprintf(stderr,"Could not initialize capturing.../n"); return -1; }
printf( "Hot keys: /n" "/tESC - quit the program/n" "/tc - stop the tracking/n" "/tb - switch to/from backprojection view/n" "/th - show/hide object histogram/n" "To initialize tracking, select the object with mouse/n" );
// cvNamedWindow( "Histogram", 0 ); cvNamedWindow( "InteractiveCAMGame", 0 ); cvSetMouseCallback( "InteractiveCAMGame", on_mouse, 0 ); // cvCreateTrackbar( "Vmin", "CamShiftDemo", &vmin, 256, 0 ); // cvCreateTrackbar( "Vmax", "CamShiftDemo", &vmax, 256, 0 ); // cvCreateTrackbar( "Smin", "CamShiftDemo", &smin, 256, 0 );
for(;;) { IplImage* frame = 0; //int i, bin_w, c; int c;
frame = cvQueryFrame( capture ); if( !frame ) break;
if( !image ) { /* allocate all the buffers */ image = cvCreateImage( cvGetSize(frame), 8, 3 ); image->origin = frame->origin; hsv = cvCreateImage( cvGetSize(frame), 8, 3 ); hue = cvCreateImage( cvGetSize(frame), 8, 1 ); mask = cvCreateImage( cvGetSize(frame), 8, 1 ); backproject = cvCreateImage( cvGetSize(frame), 8, 1 ); hist = cvCreateHist( 1, &hdims, CV_HIST_ARRAY, &hranges, 1 ); histimg = cvCreateImage( cvSize(320,200), 8, 3 ); cvZero( histimg ); // cvSaveImage("a.bmp",image); loadTemplateImage(); }
cvCopy( frame, image, 0 ); cvSaveImage("a.bmp",image); cvCvtColor( image, hsv, CV_BGR2HSV );
if( track_object ) { int _vmin = vmin, _vmax = vmax;
cvInRangeS( hsv, cvScalar(0,smin,MIN(_vmin,_vmax),0), cvScalar(180,256,MAX(_vmin,_vmax),0), mask ); cvSplit( hsv, hue, 0, 0, 0 );
cvCalcBackProject( &hue, backproject, hist ); cvAnd( backproject, mask, backproject, 0 ); cvCamShift( backproject, track_window, cvTermCriteria( CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1 ), &track_comp, &track_box ); track_window = track_comp.rect; if( backproject_mode ) cvCvtColor( backproject, image, CV_GRAY2BGR ); if( image->origin ) track_box.angle = -track_box.angle; // cvEllipseBox( image, track_box, CV_RGB(255,0,0), 3, CV_AA, 0 ); drawCorssMark(image, cvPointFrom32f(track_box.center)); MovePOPO(image,Xn,Yn); MovePOPO1(image, Xn2, Yn2); //MovePOPO(image,image->width,image->height); trackPoint= cvPointFrom32f(track_box.center); if ( sqrt( ((trackPoint.x-Xn)*(trackPoint.x-Xn)) + ((trackPoint.y-Yn)*(trackPoint.y-Yn)) )<10 ) { Xn=0; Yn=0; MovePOPO(image,Xn,Yn);
}
} if( select_object && selection.width > 0 && selection.height > 0 ) { cvSetImageROI( image, selection ); cvXorS( image, cvScalarAll(255), image, 0 ); cvResetImageROI( image ); }
cvShowImage( "InteractiveCAMGame", image ); // cvShowImage( "Histogram", histimg );
c = cvWaitKey(10); if( c == 27 ) break; switch( c ) { case 'b': backproject_mode ^= 1; break; case 'c': track_object = 0; cvZero( histimg ); break; case 'h': show_hist ^= 1; if( !show_hist ) cvDestroyWindow( "Histogram" ); else cvNamedWindow( "Histogram", 1 ); break; default: ; } }
cvReleaseCapture( &capture ); cvDestroyWindow("InteractiveCAMGame");
return 0;}
#ifdef _EiCmain(1,"camshiftdemo.c");#endif
是不是很眼熟啊,没错就是用了OpenCV那个例子
在这里还要感谢大侠hardvb 这个小游戏用了你的成果并且从你的Blog学到很多 谢谢
http://blog.csdn.net/hardvb/