基于opencv的手势识别


本次实验的目的是,利用opencv来进行手势识别。基本流程就是:

 

肤色检测-速度建模

 

通过检测肤色块连续八帧的坐标最大值最小值之差与肤色块的宽高的大小之比来确定手势的运动方向。大概的思想过程如下图所示。

 

 

下面直接上代码。

// color_detection_video.cpp : 定义控制台应用程序的入口点。
//

//----------------------------------------本程序用于从视频中进行肤色检测-------------------------------------------//
#include "stdafx.h"
#include <cv.h>
#include <cvaux.h>
#include <highgui.h>  
#include <ml.h>
#include <cxcore.h>
#include <stdlib.h>
#include <iostream>

void skin_detection_draw_video()
{
	CvCapture *pCapture=NULL;

	IplImage *pImage=NULL;
	IplImage *pMask=NULL;
	IplImage *dst=NULL;
	IplImage *mask=NULL;	


	int num=0;
	int step = 0;
	int channels =0;
	int l;
	int num_count=0;

	double x_pos=0;
	double y_pos=0;

	double x_pos_min=0;
	double y_pos_min=0;
	double x_pos_max=0;
	double y_pos_max=0;
	int width=0;
	int height=0;
	int t=0;

	CvMat* M_x=cvCreateMat(1,8,CV_64FC1);
	CvMat* M_y=cvCreateMat(1,8,CV_64FC1);

	static int B=0;
	static int G=0;
	static int R=0;

	cvNamedWindow("video",1);

	CvMemStorage* storage = cvCreateMemStorage(0);
	CvSeq* contour = 0;
	CvSeq *contmax = 0;
	CvRect rect=cvRect(0,0,0,0);
	CvRect rect_backup=cvRect(0,0,0,0);

	CvFont font;
	cvInitFont(&font,CV_FONT_HERSHEY_SIMPLEX,1,1,0,2,8);


	if (!(pCapture=cvCaptureFromCAM(-1)))
	{
		fprintf(stderr,"Could not open the video\n");
	}
	while (pImage=cvQueryFrame(pCapture))
	{		
		num++;
		if(num==1)
		{
			step = pImage->widthStep;
			channels = pImage->nChannels;
			pMask=cvCreateImage(cvSize(pImage->width,pImage->height),IPL_DEPTH_8U,3);
			dst=cvCreateImage(cvSize(pImage->width,pImage->height),IPL_DEPTH_8U,3);
			cvZero(dst);
			mask=cvCreateImage(cvSize(pImage->width,pImage->height),IPL_DEPTH_8U,1);

		}
		else
		{
				l=(num-2)%8;
				cvCopyImage(pImage,pMask);
				for (int i = 0; i < pMask->height; i++)
				{
					for (int j = 0; j < pMask->width; j++)
					{
						uchar *data_src = (uchar *)pMask->imageData+i*step+j*channels;
						uchar *data_dst = (uchar *)dst->imageData+i*step+j*channels;
						B=*(data_src+0);
						G=*(data_src+1);
						R=*(data_src+2);
						if (R>95 && G>40 && B>20 && MAX(MAX(R,G),B) - MIN(MIN(R,G),B) && abs(R-G)>15 && R>G && R>B) //满足肤色的条件
						{
							memcpy(data_dst,data_src,channels);
						}
						else
						{
							continue;
						}
					}
				}
				//mark
				cvCvtColor(dst,mask,CV_RGB2GRAY);
				cvZero(dst);
				cvThreshold(mask, mask, 1, 255, CV_THRESH_BINARY );//二值化
				cvFindContours(mask, storage, &contour, sizeof(CvContour), 
					CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); //提取出最外面的轮廓
				double area,maxArea =100;
				for( ; contour != 0; contour = contour->h_next )
				{
					area =fabs(cvContourArea( contour, CV_WHOLE_SEQ ));
					if (area>maxArea)
					{
						contmax=contour;//找出最大连通区域
						maxArea=area;
						rect=cvBoundingRect(contmax,0);		//得到最佳连通域的外接矩形			
						x_pos=rect.x;
						y_pos=rect.y;
						width=rect.width;
						height=rect.height;
					}
				}
				cvmSet(M_x,0,l,x_pos);
				cvmSet(M_y,0,l,y_pos);
				num_count++;
				if (num_count==8)
				{					
					cvMinMaxLoc(M_x,&x_pos_min,&x_pos_max);
					cvMinMaxLoc(M_y,&y_pos_min,&y_pos_max);
					printf("xmin=%f,xmax=%f,ymin=%f,ymax=%f\n",x_pos_min,x_pos_max,y_pos_min,y_pos_max);
					num_count=0;
					if(abs(x_pos_max-x_pos_min)>width)
					{
						if(x_pos>((x_pos_max+x_pos_min)*0.5))
							cvPutText(pMask,"R",cvPoint(x_pos+width,y_pos+height),&font,cvScalar(0,0,255));
						else
							cvPutText(pMask,"L",cvPoint(x_pos+width,y_pos+height),&font,cvScalar(0,0,255));
					}
					if (abs(y_pos_max-y_pos_min)>height)
					{
						if(y_pos>((y_pos_max+y_pos_min)*0.5))
							cvPutText(pMask,"D",cvPoint(x_pos+width,y_pos+height),&font,cvScalar(0,0,255));
						else
							cvPutText(pMask,"U",cvPoint(x_pos+width,y_pos+height),&font,cvScalar(0,0,255));
					}
					num_count=7;
				}
		}
	
		cvRectangle(pMask,cvPoint(rect.x,rect.y),
			cvPoint(rect.x+rect.width,rect.y+rect.height),
			cvScalar(0,0,255),2,8,0);
		cvShowImage("video",pMask);
		rect=cvRect(0,0,0,0);
		if(cvWaitKey(33)>=0)
			break;
	}

	cvDestroyWindow("video");

	cvReleaseImage(&dst);
	cvReleaseImage(&pMask);
	cvReleaseImage(&mask);

	cvReleaseMat(&M_x);
	cvReleaseMat(&M_y);

	cvReleaseCapture(&pCapture);
}
int _tmain(int argc, _TCHAR* argv[])
{
	skin_detection_draw_video();
	return 0;
}

运行结果不大好截屏,我就懒得截了,大家可以把代码复制下来直接试试运行结果。

 

雁过留声,人过留名。

 

 

评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值