如果能用手势来模拟鼠标的动作,就可以用手势进行很多的操作,比如打开文件、关闭文件、播放视频、关闭电脑等等。所以要和sixth sense系统进行友好的人机交互,模拟鼠标的动作是第一步。
如下的代码实现利用手势控制鼠标移动,左键,右键。
首先是main函数,作为一个初级的demo,只进行单一的手势控制鼠标功能,后续需要对代码的整体结构进行重构。
int main(int argc, char** argv){
IplImage *frame = NULL;
IplImage *dst = NULL;
IplImage *dstRed = NULL;
IplImage *dstGreen = NULL;
IplImage *dstBlue = NULL;
int radius_circle_red;
CvPoint center_circle_red;
int radius_circle_green;
CvPoint center_circle_green;
int radius_circle_blue;
CvPoint center_circle_blue;
ofstream f("code.txt");
if(!f)
return -1;
cvNamedWindow("example",CV_WINDOW_AUTOSIZE);
CvCapture *capture=cvCreateCameraCapture(0);
while (1)
{
frame=cvQueryFrame(capture);
if (!frame)
{
break;
}
dst= cvCreateImage(cvGetSize(frame),8,1);
dstRed= cvCreateImage(cvGetSize(frame),8,1);
dstGreen= cvCreateImage(cvGetSize(frame),8,1);
dstBlue= cvCreateImage(cvGetSize(frame),8,1);
cvBinaryzation(frame,dstRed,dstGreen,dstBlue);
cvFindObjectCircle( dstRed, &radius_circle_red, ¢er_circle_red);
cvFindObjectCircle( dstGreen, &radius_circle_green, ¢er_circle_green);
cvFindObjectCircle( dstBlue, &radius_circle_blue, ¢er_circle_blue);
cvControlMouse(center_circle_red,radius_circle_red,
center_circle_green,radius_circle_green,center_circle_blue,radius_circle_blue);
cvShowImage("example", dstRed);
//cvShowImage("example", dstGreen);
//cvShowImage("example", dstBlue);
char c=cvWaitKey(33);
if (27 == c)
{
break;
}
cvReleaseImage(&dst);
cvReleaseImage(&dstRed);
cvReleaseImage(&dstGreen);
cvReleaseImage(&dstBlue);
}
f.close();
cvReleaseCapture(&capture);
cvDestroyWindow("example");
}
在该系统中,需要再手指上带上红色、黄色、绿色的指套,这样只需识别手指上的色块,就可以识别出手势,大大降低了识别的难度。识别色块的函数如下所示:
void cvFindObjectCircle(IplImage *dst,int *radius_circle, CvPoint *center_circle)
{CvMemStorage *storage = NULL;
CvSeq *contours = NULL;
CvSeq *sqMax = NULL;
CvSeq *sq = NULL;
double blCoutourLength = 0;
double bl;
CvContourScanner cs;
CvPoint2D32f center;
float radius;
sqMax = NULL;
blCoutourLength=0;
storage = cvCreateMemStorage(0);
cs = cvStartFindContours(dst,storage,sizeof(CvContour),CV_RETR_TREE,CV_CHAIN_APPROX_SIMPLE);
do
{
sq =cvFindNextContour(cs);
if(sq == NULL)
break;
bl = cvContourPerimeter(sq);
if(bl > blCoutourLength)
{
blCoutourLength = bl;
sqMax = sq;
}
}while(sq != 0);
sq = cvEndFindContours(&cs);
if(sqMax)
{
cvDrawContours(dst,sqMax,cvScalarAll(255),cvScalarAll(255),255);
cvMinEnclosingCircle(sqMax,¢er,&radius);
center_circle->x = center.x;
center_circle->y = center.y;
*radius_circle = radius;
cvCircle(dst, *center_circle,*radius_circle,cvScalarAll(200),5);
}
}
最后,需要根据识别出来的手势来控制鼠标的运动和左右键,下面是最简单的一组代码。
void cvControlMouse(CvPoint center_circle_red,int radius_circle_red,
CvPoint center_circle_green,int radius_circle_green,CvPoint center_circle_blue,int radius_circle_blue){
bool controlMouse=true;
double distanceRed2Green=0;
double distanceRed2Blue=0;
double mouseX;
double mouseY;
distanceRed2Green= sqrt(1.0*(center_circle_red.x-center_circle_green.x)*(center_circle_red.x-center_circle_green.x)
+(center_circle_red.y-center_circle_green.y)*(center_circle_red.y-center_circle_green.y));
distanceRed2Blue= sqrt(1.0*(center_circle_red.x-center_circle_blue.x)*(center_circle_red.x-center_circle_blue.x)
+(center_circle_red.y-center_circle_blue.y)*(center_circle_red.y-center_circle_blue.y));
if(distanceRed2Green < 100)
{
mouse_event(MOUSEEVENTF_LEFTDOWN,0,0,0,0);
Sleep(20);
mouse_event(MOUSEEVENTF_LEFTUP,0,0,0,0);
}
else if(distanceRed2Blue < 100)
{
mouse_event(MOUSEEVENTF_RIGHTDOWN,0,0,0,0);
Sleep(20);
mouse_event(MOUSEEVENTF_RIGHTUP,0,0,0,0);
}
else
{
mouseX = 1.0*center_circle_red.x/IMG_WIDTH*SCREEN_WIDTH;
mouseY = 1.0*center_circle_red.y/IMG_HEIGHT*SCREEN_HEIGHT;
SetCursorPos(mouseX,mouseY);
}
Sleep(500);
}