⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 skelecton.cpp

📁 基于Opencv的人体运动检测系统
💻 CPP
📖 第 1 页 / 共 2 页
字号:
	ppbone = get_bone_by_name(pname); 
	pbone = get_bone_by_name(ppName); 
	if(pbone!=NULL && pbone->is_marked)
	{
		cx0= ppbone->x - coordinator_X ;
		cy0= ppbone->y - coordinator_Y ;

		ppbone ->r_x = cx0;
		ppbone ->r_y = cy0;
		double A,B,C,det,sqdet,x1,x2=0;

		int cx,cy=0; //校正后的坐标
		
		cx= pbone->x - coordinator_X ;
		cy= pbone->y - coordinator_Y ;

		//'求解二元一次方程
		A = 1;
		B = - 2*ppbone->r_z;
		C = pow(cx-cx0,2) + pow(cy-cy0,2) + pow(ppbone->r_z,2) - pow(pbone->LengthRatio*StardardLength,2);
			//'B^2-4ACy
			det = pow(B,2) - 4*A*C;
			//'det>0 两个解
			if (det>MaxMinZero)
			{
				//需要舍弃一个无意义的解
				sqdet = sqrt(det);
				x1=(-B+sqdet)/(2*A);
				x2=(-B-sqdet)/(2*A);
				x1=get_porper_Z(x1,x2,pbone);
			}
			//'det==0 单解
			else if (det<MaxMinZero && det>0)
			{
				x1=x2=(-B)/(2*A);
			} 
			//'det<0 无解
			else if (det<0)
			{
				//需要再次探索
				x1=x2=0;
			}	
		pbone->r_z =x1;
		pbone ->r_x = cx ;
		pbone ->r_y = cy ;


		/*
		printf( "A: %f \n",A);
		printf( "B: %f \n",B);
		printf( "C: %f \n",C);	
		
		*/
	}
	return 0;

}

void skelecton::CorrectPosition(int ID,CvPoint2D32f &pt,kalman &bone_kalman,const CvArr* grey)
{
		/*
			一些假设:1。neck为支点不动,
					  2。支点坐标轴不偏斜,始终y向上,x向左,z向外,即人体运动垂直与摄像位置,
					  没有明显的侧身运动等。躯干运动不受限制。
					  head: L*-sinx2 < r_x < L*sinx1 ,   x^2 + y^2 <= L^2 ; 
					  shoulder: shoulder.x  <= neck.x + L ;
					  eblow: x^2 + y^2 <= L^2 ;
					  rWrist: x^2 + y^2 <= L^2 ; 
					  waist: waist.y = neck.y + L
					  keen:  x^2 + y^2 <= L^2 ; x<0;
					  ankle: x^2 + y^2 <= L^2 ;

		*/
		//检查坐标,将经过跟踪后的2D坐标,代入表达式
		//如果位于人体运动范围内
			//
		//如果超出人体运动范围内(如丢掉特征点,自遮挡),开始利用kalman滤波,
			//如果kalman滤波位于人体运动范围内,以kalman预测的点周围寻找新的特征点
			//如果kalman滤波超出人体运动范围内,按照线性插值给一个特征点

		bone *pbone;
		bone *ppbone;
		bool is_inarea=true;
		CvPoint2D32f predict_point;		
		double bone_length = 0; //对应骨架的长度	
		
		pbone = get_bone_by_ID (ID);		
		pbone->is_marked =1;
		double x,y,x0,y0;
		x=pt.x;
		y=pt.y;
		if(0!=pbone->PID)
		{
			bone_length = (pbone->LengthRatio * (1+StardardLengthNoiseRatio)) * StardardLength;
			ppbone = get_bone_by_ID(pbone->PID); 
			x0=ppbone->x;
			y0=ppbone->y;
			if(pow(x-x0,2) + pow(y-y0,2) > pow(bone_length,2)) 
			is_inarea = false;	
		}

		//printf("before  : %f %f \n",x,y); 

		predict_point = bone_kalman.get_predict(x,y);

		//printf("predict : %f %f \n",predict_point.x,predict_point.y); 

		if(is_inarea) 
		{

			//左肩右肩,脖子,腰部,加刚性三角形约束
		}
		else
		{
			if(pow(predict_point.x-x0,2) + pow(predict_point.y-y0,2) > pow(bone_length,2)) 
			{
				//预测点也不在刚体约束内,则宣布特征点丢失
				//特征点丢失,利用运动连续性,根据上五帧的情况,按照匀速线性插值,预测一个点
				//to do list
				if (pre_ske!=NULL)
				{	
					bone* pre_pbone =NULL;
					//pre_pbone = pre_ske->get_bone_by_ID (pbone->ID);	
					//pt.x = pre_pbone->r_x;
					//pt.y = pre_pbone->r_y;

				}

			}
			else
			{		
				//预测点在刚体约束内,添加在指定范围寻找特征点
				//to do list
				pt.x = predict_point.x;
				pt.y = predict_point.y;
			}
/*
			cvFindCornerSubPix( grey, &pt, 1,
						        cvSize(10,10), cvSize(-1,-1),
							    cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,20,0.03));
*/

		}
		pbone->x = (int)pt.x;
		pbone->y = (int)pt.y;

}

void skelecton::CalcLengthRatio(int ID,CvPoint2D32f pt)
{
		bone *pbone;
		bone *ppbone;
		double bone_length;
		double x,y,x0,y0;

		pbone = get_bone_by_ID(ID); 
		if(pbone!=NULL) 
		{
			if(0!=pbone->PID)
			{
				x=pt.x;
				y=pt.y;
				
				ppbone = get_bone_by_ID(pbone->PID); 
				x0=ppbone->x;
				y0=ppbone->y;
				bone_length = sqrt(pow(x-x0,2) + pow(y-y0,2));
				pbone->LengthRatio = bone_length/StardardLength ;

			}
			else
				pbone->LengthRatio = 0;

			pbone->x = (int)pt.x;
			pbone->y = (int)pt.y;
		}


}

//根据人体模型来消除z坐标的二义性
int skelecton::get_porper_Z(int x1, int x2, bone *pbone)
{
	
	//return x2;
	//利用上一状态估计当前状态,取离上一状态最近的点
	bone *pre_pbone=NULL;
	int result = 0;
	int pre_z = 0 ;

	if (pre_ske!=NULL)
	{
		pre_pbone = pre_ske->get_bone_by_ID (pbone->ID);	
		pre_z = pre_pbone->r_z ;
		if(abs(pre_z-x1)>abs(pre_z-x2)) 	
			result= x2;
		else
			result= x1;
	}
		result= x1;
	//肢体本身的二义性
	if(pre_pbone!=NULL)
	{
		switch(pbone->ID)
		{
			case 5:	//rElbow 胳膊肘不能向外拐				
				result = check_porper_Z(x1,x2,pre_pbone,false);
				break;
			case 6: //lElbow 胳膊肘不能向外拐
				result = check_porper_Z(x1,x2,pre_pbone,true);
				break;
			case 10: //rKnee 膝盖不能内弯
				result = check_porper_Z(x1,x2,pre_pbone,false);
				break;
			case 11: //lKnee 膝盖不能内弯
				result = check_porper_Z(x1,x2,pre_pbone,true);
				break;
		}
	}
	return result;
}

void skelecton::CalcBonePosition()
{
	CalcBoneRealWorldPosition_parallel("neck","head");
	CalcBoneRealWorldPosition_parallel("neck","rShoulder");
	CalcBoneRealWorldPosition_parallel("neck","lShoulder");
	CalcBoneRealWorldPosition_parallel("rShoulder","rElbow");
	CalcBoneRealWorldPosition_parallel("lShoulder","lElbow");
	CalcBoneRealWorldPosition_parallel("rElbow","rWrist");
	CalcBoneRealWorldPosition_parallel("lElbow","lWrist");
	CalcBoneRealWorldPosition_parallel("neck","Waist");
	CalcBoneRealWorldPosition_parallel("Waist","rKnee");
	CalcBoneRealWorldPosition_parallel("Waist","lKnee");
	CalcBoneRealWorldPosition_parallel("rKnee","rAnkle");
	CalcBoneRealWorldPosition_parallel("lKnee","lAnkle");

}


void skelecton::set_previous_skelecton(skelecton *pre_skelecton)
{
	pre_ske = pre_skelecton;
}

//将坐标旋转到肩膀与手腕的向量上,求得到点的值是否在向量上方
int skelecton::check_porper_Z(int x1, int x2, bone *pbone,bool IsLeft)
{
	int xx0,zz0,xx1,xx2,zz1,zz2,result=0;
	float sinx,cosx,radiolen;
	float zz,zzz;
	bone *ppbone,*cpbone;
	ppbone = pre_ske->get_bone_by_ID (pbone->PID);
	cpbone = pre_ske->get_bone_by_ID (pbone->CID);
	if (ppbone!=NULL && cpbone!=NULL)
	{
		xx1 = ppbone->r_x;
		zz1 = ppbone->r_z;
		xx2 = cpbone->r_x;
		zz2 = cpbone->r_z;
		xx0=xx2-xx1;
		zz0=zz2-zz1;
		radiolen = sqrt(xx0*xx0 + zz0*zz0);
		sinx=xx0/radiolen;
		cosx=zz0/radiolen;
		zz=(x1-zz1)*sinx+(x1-zz1)*cosx;  
		zzz=(x2-zz1)*sinx+(x2-zz1)*cosx;
		if(IsLeft)
		{
			if(zz<0) 
				result = x1;
			if(zzz<0)
				result = x2;
		}
		else
		{
			if(zz>0) 
				result = x1;
			if(zzz>0)
				result = x2;
		}

	}
	return result;
	
}

int skelecton::drawOpenGL3D(CvArr *motion_track_img)
{

	bone_vector::iterator theIterator;
	bone *pbone = 0;
	bone *ppbone = 0;	
	Vector3f  vt1,vt2;
	
	ppbone = get_bone_by_name("neck"); 
	ppbone->r_z =0;  //初始化head的坐标为0

	
	CvSize ImageSize; 
	ImageSize = cvGetSize(motion_track_img);	
	coordinator_X = (int)ImageSize.width/2;
	coordinator_Y = (int)ImageSize.height/2;

	CalcBonePosition();

	assert(pgl!=NULL);
	if(pgl!=NULL) 	pgl->clear();


    for (theIterator = bonevec.begin(); theIterator != bonevec.end();
         theIterator++)
    {
		  pbone = theIterator;	

			if(pbone->is_marked==0)  continue; //未标记则不画
			  if ( 0 != pbone->PID )  
			  {
				  ppbone = get_bone_by_ID(pbone->PID); 				  
				  vt1.x = pbone->r_x;
				  vt1.y = pbone->r_y;
				  vt1.z = pbone->r_z;
				  vt2.x = ppbone->r_x;
				  vt2.y = ppbone->r_y;
				  vt2.z = ppbone->r_z;
				  if(pgl!=NULL)  pgl->draw2point(vt1,vt2);				  
			  }

	} 
	


	if(pgl!=NULL) 
	{
		//pgl->Correct_3D_Layout(vt1,vt2);
		pgl->display();
	}
    return 0;
}

void skelecton::view_up()
{
	if(pgl!=NULL) 
	 pgl->x_arc = (pgl ->x_arc + 5) % 360;
}

void skelecton::view_down()
{
	if(pgl!=NULL) 
	pgl->x_arc = (pgl ->x_arc - 5) % 360;
}

void skelecton::view_left()
{
	if(pgl!=NULL) 
	pgl->y_arc = (pgl ->y_arc + 5) % 360;
}

void skelecton::view_right()
{
	if(pgl!=NULL) 
	pgl->y_arc = (pgl ->y_arc - 5) % 360;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -