Demo1:视频人体检测






/*
#include
using namespace cv;
int main()
{
	Mat img = imread("1.jpg");
	imshow("测试图片",img);
	waitKey(50);
	return 0;

}*/





/*



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%                                                            %%%%%%
%%%%%%       欢迎到www.opencvchina.com下载源代码和资料              %%%%%%
%%%%%%                                                            %%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%




*/
/*
 * Code written by Lya (GeckoGeek.fr)
 */
//#include "stdafx.h"
#include "opencv/highgui.h"
#include "opencv/cv.h"
 
#include 
#include 
#include 
 
// Maths methods
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))  
#define abs(x) ((x) > 0 ? (x) : -(x))
#define sign(x) ((x) > 0 ? 1 : -1)

// Step mooving for object min & max
#define STEP_MIN 5 
#define STEP_MAX 100 
//轮廓区域最小面积

int detectarea=100;
IplImage *image;
IplImage *im; 
// Position of the object we overlay
CvPoint objectPos = cvPoint(-1, -1); //目标当前位置
// Color tracked and our tolerance towards it
int h = 0, s = 0, v = 0, tolerance = 10;
CvPoint temp ;
int T_HSV[3]={111,111,23};
//	int HSV[3]={177,185,120};
	int HSV[3]={179,79,81};
	int HSV_f[3]={177,185,120};
//int count=0;
int countd=0; //在drawbody函数用到
CvPoint HEAD;//上次的头部坐标
CvPoint HAND[5];//用于存储上次的手部坐标
CvPoint FOOT[5];//用于存储上次的脚坐标
CvPoint point[10];//存储目标位置
CvScalar color=CV_RGB(255,158,97);
	// Next position of the object we overlay
	CvPoint objectNextPos;

//此函数用于画出image图片中是HSV[]色彩的所有轮廓,HSV[]是感兴趣的三通道色彩
CvPoint ditalcontours(IplImage* image, int *nbPixels,int HSV[],int detectarea) {
 
	void drawcontours(IplImage* mask,IplImage* image);
	int x, y;
	//CvScalar pixel;
	IplImage *hsv, *mask;
	IplConvKernel *kernel;
	int sommeX = 0, sommeY = 0;
	*nbPixels = 0;
 
	// Create the mask &initialize it to white (no color detected)
	mask = cvCreateImage(cvGetSize(image), image->depth, 1);
 
	// Create the hsv image
	hsv = cvCloneImage(image);
	cvCvtColor(image, hsv, CV_BGR2HSV);
 
	// We create the mask
	cvInRangeS(hsv, cvScalar(HSV[0] - tolerance -1, HSV[1] - tolerance,0), cvScalar(HSV[0] + tolerance -1, HSV[1] + tolerance,  255), mask);
  //cvInRangeS(1,2,3,4)此函数就是从hsv图像中选出在范围在2到3之间的像素点,选出来符合的置为1,否则置为0。
  //最后把二值化图像存在mask中
	//cvShowImage("mask第一步", mask);//展示mask效果

	// Create kernels for the morphological operation
	kernel = cvCreateStructuringElementEx(5, 5, 2, 2, CV_SHAPE_CROSS);
    //生成膨胀和溶解结构 kernel
	// Morphological opening (inverse because we have white pixels on black background)
	cvDilate(mask, mask, kernel, 1); //膨胀
	cvErode(mask, mask, kernel, 1);  //溶解	

	// We go through the mask to look for the tracked object and get its gravity center
  for(x = 0; x < mask->width; x++) {
		for(y = 0; y < mask->height; y++) { 
 
			// If its a tracked pixel, count it to the center of gravity's calcul
			if(((uchar *)(mask->imageData + y*mask->widthStep))[x] == 255) {
				sommeX += x;    //目标像素点x坐标总和	
				sommeY += y;	//目标像素点y坐标总和	
				(*nbPixels)++; //目标像素点个数
			}
		}
	}

	// Show the result of the mask image
//	cvShowImage("Mask第二部", mask);
	drawcontours(mask,image);
	// We release the memory of kernels
	cvReleaseStructuringElement(&kernel);
 
	// We release the memory of the mask
	cvReleaseImage(&mask);
	// We release the memory of the hsv image
    	cvReleaseImage(&hsv);
 
	// If there is no pixel, we return a center outside the image, else we return the center of gravity
	if(*nbPixels > 0)
		return cvPoint((int)(sommeX / (*nbPixels)), (int)(sommeY / (*nbPixels))); //目标像素点的质心
	else
		return cvPoint(-1, -1);
}
 
//此函数用于勾画黑白图mask的轮廓
void drawcontours(IplImage* mask,IplImage* image)
{



IplConvKernel *kernel = cvCreateStructuringElementEx(5, 5, 2, 2, CV_SHAPE_ELLIPSE);
IplImage* pyr = cvCreateImage( cvSize((mask->width )/2, (mask->height)/2), 8, 1 );
	CvMemStorage *stor; 
	CvSeq *cont; 
	// 中值滤波,消除小的噪声 
cvSmooth( mask, mask, CV_MEDIAN, 3, 0, 0, 0 ); 

cvPyrDown( mask, pyr, CV_GAUSSIAN_5x5 );// 向下采样,去掉噪声,图像是原图像的四分之一 ,mask是pyr面积的四倍,要不然会内存溢出
cvDilate( pyr, pyr, 0, 1 ); // 做膨胀操作,消除目标的不连续空洞 

cvPyrUp( pyr,mask, CV_GAUSSIAN_5x5 );// 向上采样,恢复图像,图像是原图像的四倍 
cvErode(mask, mask, kernel, 1);  //溶解
cvShowImage("Mask第三部", mask);

// 下面的程序段用来找到轮廓 
// Create dynamic structure and sequence. 
stor = cvCreateMemStorage(0); 
cont = cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvSeq), sizeof(CvPoint) , stor); 
// 找到所有轮廓 
//cvFindContors( dst, stor, &cont, sizeof(CvContour), 
//CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0)); 
cvFindContours( mask, stor, &cont, sizeof(CvContour), 
CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0)); 

// 直接使用CONTOUR中的矩形来画轮廓 
/*
	  double area=0;
  CvSeq *contemp=cont;
for(;contemp;contemp = contemp->h_next) 
{  CvRect    temp = ((CvContour*)cont)->rect;
  if(temp.height * temp.width>area)
   area=temp.height * temp.width;
} 
*/	 




for(int num=0;cont;cont = cont->h_next) 
{ 
CvRect  r = ((CvContour*)cont)->rect;
if(r.height * r.width > detectarea) // 面积小的方形抛弃掉 
{ 
	point[num%10].x=(2*r.x + r.width)/2; 
    point[num%10].y= (2*r.y + r.height)/2; 

//cvRectangle( image, cvPoint(r.x,r.y), cvPoint(r.x + r.width, r.y + r.height), CV_RGB(255,0,0), 1, CV_AA,0); //给指定区域画轮廓
		cvCircle(im,point[num%10],10,color,CV_FILLED,CV_AA,0);
printf( "轮廓的开始位置 %d.%d ,中心x,y = %d.%d ,个数是%d\n",r.x,r.y ,point[num%10].x,point[num%10].y ,num);
	num++; 
} 
} 

	cvReleaseStructuringElement(&kernel);
	// free memory 
cvReleaseMemStorage(&stor); 
	// We release the memory of the hsv image
    	cvReleaseImage(&pyr);

} 



int SMINY(CvPoint P[])
{  int i=0;
	int MAX=1000,c=0;
	while(P[i].x&&P[i].y)
		{  if(P[i].y0&&P[i].x>0)
	  {
		MAX=P[i].y;
		c=i;
	  }
		
		i++;
	}
	return c;
}

int SMINX(CvPoint P[])
{
		 int i=0;
	int MAX=1000,c=0;
		while(P[i].x&&P[i].y)
	{  if(P[i].x0&&P[i].y>0)
	  {
		MAX=P[i].x;
		c=i;
	  }
		
		i++;
	}
	return c;	
}

int SMAXX(CvPoint P[])
{
		 int i=0;
	int MAX=0,c=0;
while(P[i].x&&P[i].y)
	{  if(P[i].x>MAX&&P[i].y>0)
	  {
		MAX=P[i].x;
		c=i;
	  }
		
		i++;
	}
return c;
}


void drawupbody(CvPoint P[],CvPoint center,CvPoint P1[])
{	int i=0;
	int c=0;

	CvPoint pt1_Rect;
	CvPoint pt2_Rect;
	CvPoint head;
	CvPoint body;
	CvPoint hand[2];
	CvPoint foot[2];	
	char key='e';
	int radius=0;
	//char str[15];	//CvFont font;

	c=SMINY(P);
		head.x=P[c].x;
		head.y=P[c].y;
	c=SMINX(P);
		hand[0].x=P[c].x;
		hand[0].y=P[c].y;
	c=SMAXX(P);
		hand[1].x=P[c].x;
		hand[1].y=P[c].y;
	body.x=center.x;
	body.y=center.y;

		c=SMINX(P1);
		foot[0].x=P1[c].x;
		foot[0].y=P1[c].y;
		c=SMAXX(P1);
		foot[1].x=P1[c].x;
		foot[1].y=P1[c].y;

	 //对头部,手臂点 空间位置跳跃控制。减少乱跳现象
	if(countd++<4)
	{HEAD.x=head.x;
	 HEAD.y=head.y;

	for(int i=0;i<2;i++)
	{ HAND[i].x=hand[i].x;
	 HAND[i].y=hand[i].y;
	 FOOT[i].x=foot[i].x;
	 FOOT[i].y=foot[i].y;
	}
	}
	// printf( "轮廓的中心x,y = %d.%d \n", abs(HEAD.x-head.x),abs(HEAD.y-head.y));
	 if( abs(HEAD.x-head.x)>40||abs(HEAD.y-head.y)>40) 
		{head.x=HEAD.x;
		 head.y=HEAD.y;
		}
	 HEAD.x=head.x;
	 HEAD.y=head.y;

	 for(int i=0;i<2;i++)
	 {
	 if( abs(HAND[i].x-hand[i].x)>60||abs(HAND[i].y-hand[i].y)>60)
		{
		 hand[i].x=HAND[i].x;
		 hand[i].y=HAND[i].y;
		}
	  if( abs(FOOT[i].x-foot[i].x)>100||abs(FOOT[i].y-foot[i].y)>100)
		{
		 foot[i].x=FOOT[i].x;
		 foot[i].y=FOOT[i].y;
		}
	 HAND[i].x=hand[i].x;
	 HAND[i].y=hand[i].y;
	 FOOT[i].x=foot[i].x;
	 FOOT[i].y=foot[i].y;
	 } //对头部,手臂点 空间位置跳跃控制。减少乱跳现象
//	 printf("右手坐标是%d,%d",hand[1].x,hand[1].y);
	
	IplImage *img=cvCreateImage(cvGetSize(image),IPL_DEPTH_8U,3);
	cvNamedWindow("image",CV_WINDOW_AUTOSIZE);


	pt1_Rect.x=0;
	pt1_Rect.y=0;
	pt2_Rect.x=600;
	pt2_Rect.y=600;
	color=CV_RGB(97,158,225);
	cvRectangle(img,pt1_Rect,pt2_Rect,color,CV_FILLED,CV_AA,0);
	color=CV_RGB(255,158,97);
	radius=35;


	cvCircle(img,head,radius,color,CV_FILLED,CV_AA,0);//头部

	pt1_Rect.x=body.x-30;
	pt1_Rect.y=body.y-20;
	pt2_Rect.x=body.x+30;
	pt2_Rect.y=body.y+80;
	cvRectangle(img,pt1_Rect,pt2_Rect,color,CV_FILLED,CV_AA,0);//身体

	cvLine(img,head,body,color,10,CV_AA,0);//颈部

	color=CV_RGB(255,255,0);
	pt1_Rect.x=body.x-30;
	pt1_Rect.y=body.y-20;
	cvLine(img,pt1_Rect,hand[0],color,30,CV_AA,0);//手臂1
	pt1_Rect.x=body.x+30;
	pt1_Rect.y=body.y-20;
	cvLine(img,pt1_Rect,hand[1],color,30,CV_AA,0);//手臂2


	color=CV_RGB(255,255,0);
	pt1_Rect.x=body.x-30;
	pt1_Rect.y=body.y+70;
	cvLine(img,pt1_Rect,foot[0],color,30,CV_AA,0);//腿1
	pt1_Rect.x=body.x+30;
	pt1_Rect.y=body.y+70;
	cvLine(img,pt1_Rect,foot[1],color,30,CV_AA,0);//腿1
	cvShowImage("image",img);
		cvReleaseImage(&img);

}



//此函数截取人物部分,再来跟踪颜色质心对于人物跟踪更加精准

void ditaldeal(IplImage* image, CvPoint t,int *nbPixels,int HSV[])
{  
int tem=*nbPixels;	

CvPoint h[5],f[5];

im=cvCreateImage(cvGetSize(image),image->depth,image->nChannels);
cvCopy(image,im,NULL);
//cvSetImageROI(im,cvRect(t.x-70,t.y-150,140,400));
detectarea=100;//最小区域面积的设定
temp =ditalcontours(im,nbPixels,HSV,detectarea);
for(int i=0;i<5;i++)
{h[i].x=point[i].x; h[i].y=point[i].y;  }//找上身的点

for(int i=0;i<5;i++)
{point[i].x=NULL; point[i].y=NULL;  }//清空point

//cvCopy(image,im,NULL);
detectarea=50;
temp =ditalcontours(im,nbPixels,HSV_f,detectarea);
for(int i=0;i<5;i++)
{f[i].x=point[i].x; f[i].y=point[i].y; 
//printf("下半身的第%d点是x=%d,y=%d",i,f[i].x,f[i].y);
}//找下身的点

for(int i=0;i<5;i++)
{point[i].x=NULL; point[i].y=NULL;  }//注意清空point[],以免下一帧有影响

drawupbody(h,objectNextPos,f);

 
}



//此函数用于跟踪HSV[]三通道色彩像素点的质心

CvPoint binarisation(IplImage* image, int *nbPixels,int HSV[]) {
 
	int x, y;
	//CvScalar pixel;
	IplImage *hsv, *mask;
	IplConvKernel *kernel;
	int sommeX = 0, sommeY = 0;
	*nbPixels = 0;
 
	// Create the mask &initialize it to white (no color detected)
	mask = cvCreateImage(cvGetSize(image), image->depth, 1);
 
	// Create the hsv image
	hsv = cvCloneImage(image);
	cvCvtColor(image, hsv, CV_BGR2HSV);
 
	// We create the mask
	cvInRangeS(hsv, cvScalar(HSV[0] - tolerance -1, HSV[1]- tolerance, 0), cvScalar(HSV[0] + tolerance -1, HSV[1] + tolerance, 255), mask);
  //cvInRangeS(1,2,3,4)此函数就是从hsv图像中选出在范围在2到3之间的像素点,选出来符合的置为1,否则置为0。
  //最后把二值化图像存在mask中
	//cvShowImage("mask第一步", mask);//展示mask效果

	// Create kernels for the morphological operation
	kernel = cvCreateStructuringElementEx(5, 5, 2, 2, CV_SHAPE_ELLIPSE);
    //生成膨胀和溶解结构 kernel
	// Morphological opening (inverse because we have white pixels on black background)
	cvDilate(mask, mask, kernel, 1); //膨胀
	cvErode(mask, mask, kernel, 1);  //溶解
 
	// We go through the mask to look for the tracked object and get its gravity center
	for(x = 0; x < mask->width; x++) {
		for(y = 0; y < mask->height; y++) { 
 
			// If its a tracked pixel, count it to the center of gravity's calcul
			if(((uchar *)(mask->imageData + y*mask->widthStep))[x] == 255) {
				sommeX += x;    //目标像素点x坐标总和	
				sommeY += y;	//目标像素点y坐标总和	
				(*nbPixels)++;  //目标像素点个数
			}
		}
	}
 
	// Show the result of the mask image
	//cvShowImage("Mask第二部", mask);
 
	// We release the memory of kernels
	cvReleaseStructuringElement(&kernel);
 
	// We release the memory of the mask
	cvReleaseImage(&mask);
	// We release the memory of the hsv image
    	cvReleaseImage(&hsv);
 
	// If there is no pixel, we return a center outside the image, else we return the center of gravity
	if(*nbPixels > 0)
		return cvPoint((int)(sommeX / (*nbPixels)), (int)(sommeY / (*nbPixels))); //目标像素点的质心
	else
		return cvPoint(-1, -1);
}




//此函数用于给指定点的质心打点
void addObjectToVideo(IplImage* image, CvPoint objectNextPos, int nbPixels) {
 
	int objectNextStepX, objectNextStepY;
     
	 CvPoint t;
	t.x=objectNextPos.x;
	 t.y=objectNextPos.y;
	// Draw an object (circle) centered on the calculated center of gravity
	if (nbPixels > 10)
		cvDrawCircle(image, objectNextPos, 10, CV_RGB(255, 0, 0), -1);
 cvRectangle( image, cvPoint(t.x-50,t.y-120), 
cvPoint(t.x + 50, t.y + 90), 
CV_RGB(255,0,0), 1, CV_AA,0); 
	// We show the image on the window
			
}
 
//得到鼠标点击处的HSV[]三通道色彩
void getObjectColor(int event, int x, int y, int flags, void *param = NULL) {
 
	// Vars
	CvScalar pixel;
	IplImage *hsv;
 
	if(event == CV_EVENT_LBUTTONUP)	{
	
		// Get the hsv image
		hsv = cvCloneImage(image);
		cvCvtColor(image, hsv, CV_BGR2HSV);
 
		// Get the selected pixel
		pixel = cvGet2D(hsv, y, x);
 
		// Change the value of the tracked color with the color of the selected pixel
		h = (int)pixel.val[0];  //修改全局变量 h通道值
		s = (int)pixel.val[1]; //修改全局变量 s通道值
		v = (int)pixel.val[2]; //修改全局变量 v通道值
	

	// {	HSV[0]=h;  HSV[1]=s;  HSV[2]=v;}

	   {   T_HSV[0]=h;   T_HSV[1]=s;   T_HSV[2]=v;}
		// Release the memory of the hsv image
    		cvReleaseImage(&hsv);
 
	}
 
}



/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%                                                            %%%%%%
%%%%%%       欢迎到www.opencvchina.com下载源代码和资料              %%%%%%
%%%%%%                                                            %%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


*/

 
int main() {
	double t;
	// Image & hsvImage
	IplImage *hsv;
	// Video Capture
	CvCapture *capture;
	// Key for keyboard event
	char key='e';

	// Number of tracked pixels
	int nbPixels;

 
	// Initialize the video Capture (200 => CV_CAP_V4L2)
 //	capture = cvCreateCameraCapture(0);
 
capture = cvCaptureFromAVI("face.mp4" );
	// Check if the capture is ok
    	if (!capture) {
		printf("Can't initialize the video capture.\n");
        	return -1;
 	}
 
	// Create the windows
 	cvNamedWindow("GeckoGeek Color Tracking", CV_WINDOW_AUTOSIZE);
  
	cvMoveWindow("GeckoGeek Color Tracking", 0, 100);

 
	// Mouse event to select the tracked color on the original image
	cvSetMouseCallback("GeckoGeek Color Tracking", getObjectColor); //设置鼠标监听,修改目标颜色的h,s,v三个通道值
			image = cvQueryFrame(capture);

	// While we don't want to quit
 	while(key != 'Q' && key != 'q') {
		
		// We get the current image
		image = cvQueryFrame(capture);
 
		// If there is no image, we exit the loop
		if(!image)
			continue;
	
		objectNextPos = binarisation(image, &nbPixels,T_HSV);   //返回 质心坐标,nbPixels是目标像素的个数
	
	//	addObjectToVideo(image, objectNextPos, nbPixels);  //质心移动处理函数

			 t = (double)cvGetTickCount();//用来计算算法执行时间
	   ditaldeal(image,objectNextPos,&nbPixels,HSV);//人物颜色质心跟踪更加精准
			 t = (double)cvGetTickCount() - t;//相减为算法执行的时间
			 printf( "detection time = %g ms\n", t/((double)cvGetTickFrequency()*1000.) );

			 cvShowImage("GeckoGeek Color Tracking", image);//完整框,显示框不能重名
			  cvShowImage("GeckoGeek Color Track", im);//人物框

		// We wait 10 ms
		key = cvWaitKey(10);
 
	}
 
	// Destroy the windows we have created
	cvDestroyWindow("GeckoGeek Color Tracking");
	cvDestroyWindow("GeckoGeek Mask");
 
	// Destroy the capture
	cvReleaseCapture(&capture);
	cvReleaseImage(&hsv);
	return 0;
 
}


 

你可能感兴趣的:(C++,图像识别)