www.pudn.com > expressionsb.rar > EGraph.cpp


// EGraph.cpp: implementation of the CEGraph class. 
// 
////////////////////////////////////////////////////////////////////// 
 
#include "stdafx.h" 
#include "test1.h" 
#include "EGraph.h" 
#include  
 
#ifdef _DEBUG 
#undef THIS_FILE 
static char THIS_FILE[]=__FILE__; 
#define new DEBUG_NEW 
#endif 
 
////////////////////////////////////////////////////////////////////// 
// Construction/Destruction 
////////////////////////////////////////////////////////////////////// 
 
CEGraph::CEGraph() 
{ 
	m_dimension=0; 
	m_pNext=NULL; 
	int i; 
	for(i=0;iGetDIBSize(); 
	if((sizeDIB.cx!=90)||(sizeDIB.cy!=100)) 
	{ 
		MessageBox(NULL,"请先将图像归一为90×100","Information",MB_OK); 
		return FALSE; 
	} 
	int widthBytes=WIDTHBYTES(8*sizeDIB.cx); 
 
	LPSTR lpbi; 
	int i,j; 
	BYTE *image; 
	HDIB tmp_hDIB; 
	tmp_hDIB=pDIB->GetHDIB(); 
	lpbi=(LPSTR)::GlobalLock((HGLOBAL)tmp_hDIB); 
	image=(BYTE*)pDIB->FindDIBBits(lpbi); 
	for(i=0;i<20;i++)//行 
		for(j=0;j<18;j++)//列 
		{//m_pvGraph的第0单元存储向量 
			m_pvGraph[i*18+j]=pExpStr->GetGaborVector_5(image,j*5,100-i*5-5,widthBytes); 
		} 
		m_dimension=360; 
///////////////////// 
	::GlobalUnlock((HGLOBAL)tmp_hDIB); 
////计算每个向量的模,并保存入m_module数组中 
	for(i=0;i<360;i++) 
	{ 
		m_module[i]=CalModule(m_pvGraph[i]); 
	} 
//////////////增加的语句:用于检测关键点,只要模板需要,而被测表情图像不需要 
//	DetectKeyPoints(); 
	return TRUE; 
///该函数用于创建标准模板表情图像(pDIB,大小90×100)的弹性图 
 ///向量分布于眼角、眉毛、额角、嘴巴等共15处 
/* 
	if(m_dimension!=0) 
		return FALSE; 
	CSize sizeDIB=pDIB->GetDIBSize(); 
	if((sizeDIB.cx!=90)||(sizeDIB.cy!=100)) 
	{ 
		MessageBox(NULL,"请先将图像归一为90×100","Information",MB_OK); 
		return FALSE; 
	} 
	int widthBytes=WIDTHBYTES(8*sizeDIB.cx); 
	LPSTR lpbi; 
	int i; 
	//保存模板各个关键点的坐标,0单元不用 
	//注意图像返过来保存 
	int pos_x[16]={0,5,22,26,40,53,58,76,  22,40,53,22,40,53,17,58}; 
	int pos_y[16]={0,23,8,25,10,25,8,23,  70,70,70,85,85,85,78,78}; 
	for(i=1;i<16;i++) 
		pos_y[i]=95-pos_y[i]; 
//	LPBITMAPINFO lpbmi; 
	BYTE *image; 
	HDIB tmp_hDIB; 
	tmp_hDIB=pDIB->GetHDIB(); 
	lpbi=(LPSTR)::GlobalLock((HGLOBAL)tmp_hDIB); 
	image=(BYTE*)pDIB->FindDIBBits(lpbi); 
 
	for(i=1;i<=15;i++) 
		m_pvGraph[i]=pExpStr->GetGaborVector_5(image,pos_x[i],pos_y[i],widthBytes); 
	::GlobalUnlock((HGLOBAL)tmp_hDIB); 
	m_dimension=15; 
	return TRUE; 
	*/ 
} 
 
 
BOOL CEGraph::init_testExpr(CDIB *pDIB, CExpStrategy *pExpStr) 
{///创建归一化后的被测表情图像(pDIB,90×100)的弹性图 
 ///分别提取眼睛(图像的上半部分,90×30)和嘴巴(下半部分,40×30)的特征向量 
	if(m_dimension!=0) 
		return FALSE; 
	CSize sizeDIB=pDIB->GetDIBSize(); 
	if((sizeDIB.cx!=90)||(sizeDIB.cy!=100)) 
	{ 
		MessageBox(NULL,"请先将图像归一为90×100","Information",MB_OK); 
		return FALSE; 
	} 
	int widthBytes=WIDTHBYTES(8*sizeDIB.cx); 
	LPSTR lpbi; 
	int i,j; 
	BYTE *image; 
	HDIB tmp_hDIB; 
	tmp_hDIB=pDIB->GetHDIB(); 
	lpbi=(LPSTR)::GlobalLock((HGLOBAL)tmp_hDIB); 
	image=(BYTE*)pDIB->FindDIBBits(lpbi); 
/////////////10*10: 
/*	for(i=0;i<3;i++)//行 
		for(j=0;j<9;j++)//列 
		{//m_pvGraph的第0单元不存储向量 
			m_pvGraph[i*9+j+1]=pExpStr->GetGaborVector(image,j*10,100-i*10-10,widthBytes); 
		} 
	for(i=0;i<3;i++) 
		for(j=0;j<5;j++) 
		{ 
			m_pvGraph[27+i*5+j+1]=pExpStr->GetGaborVector(image,20+j*10,35-i*10-10,widthBytes); 
		} 
	m_dimension=42;*/ 
///////////////5*5: 
	for(i=0;i<20;i++)//行 
		for(j=0;j<18;j++)//列 
		{//m_pvGraph的第0单元存储向量 
			m_pvGraph[i*18+j]=pExpStr->GetGaborVector_5(image,j*5,100-i*5-5,widthBytes); 
		} 
		m_dimension=360; 
///////////////////// 
	::GlobalUnlock((HGLOBAL)tmp_hDIB); 
/////计算每个向量的模,并保存入m_module数组中 
	for(i=0;i<360;i++) 
	{ 
		m_module[i]=CalModule(m_pvGraph[i]); 
	} 
/*	for(i=0;i<20;i++)//行 
		for(j=0;j<18;j++)//列 
			m_module[i*18+j]=j;*/ 
	return TRUE; 
} 
 
/** 
采用弹性匹配算法计算本弹性图(待测表情)与模板弹性图的最小能量 
* 该算法是整体程序的主体之一 
*/ 
FLOAT CEGraph::CalEnergy(CEGraph *tempEG) 
{ 
////////*********************************算法0************************ 
//采用欧氏距离衡量两个图间的相似性 
	if((tempEG==NULL)||(tempEG->m_dimension!=360)) 
	{ 
		MessageBox(NULL,"能量的参数必须是模板弹性图",NULL,MB_OK); 
		return -1.0f; 
	} 
	int  i,j,m,n; 
	FLOAT f_result, f_tmp; 
	f_result=65000.0f; 
	//模板可以在被测图上进行微小的整体偏移,取所有偏移中最小的值为最终结果 
	for(i=-1;i<=1;i++) 
		for(j=-1;j<=1;j++) 
		{//****************************************** 
			f_tmp=0.0f;//累加 
			///眼睛区域(14×5),权值为1.2 
			for(n=2;n<7;n++) 
				for(m=2;m<16;m++)///眼睛区域(14×5) 
				{ 
					f_tmp+=1.2*sub_CalEnergy(tempEG->m_pvGraph[18*n+m],m_pvGraph[18*(n+i)+m+j]); 
				}		 
			///嘴巴区域(8×6),权值为1.5 
				for(n=12;n<18;n++) 
					for(m=5;m<13;m++) 
					{ 
						f_tmp+=1.5*sub_CalEnergy(tempEG->m_pvGraph[18*n+m],m_pvGraph[18*(n+i)+m+j]); 
					} 
			///脸颊(4点),权值为0.9 
			n=10; m=7; 
				f_tmp+=0.9*sub_CalEnergy(tempEG->m_pvGraph[18*n+m],m_pvGraph[18*(n+i)+m+j]); 
			n=11; m=7; 
				f_tmp+=0.9*sub_CalEnergy(tempEG->m_pvGraph[18*n+m],m_pvGraph[18*(n+i)+m+j]); 
			n=10; m=11; 
				f_tmp+=0.9*sub_CalEnergy(tempEG->m_pvGraph[18*n+m],m_pvGraph[18*(n+i)+m+j]); 
			n=11; m=11; 
				f_tmp+=0.9*sub_CalEnergy(tempEG->m_pvGraph[18*n+m],m_pvGraph[18*(n+i)+m+j]); 
		//	if(f_tmp>0) f_tmp*=-1.0f; 
			f_tmp/=112.0f;//共112个点,故,取其均值 
			if(f_result>f_tmp) f_result=f_tmp; 
		}//********************************************* 
		return f_result; 
////****************************************************** 
/***********************************************算法1******************* 
//新算法:眼睛区域、嘴巴区域的严格匹配 
	if((tempEG==NULL)||(tempEG->m_dimension!=360)) 
	{ 
		MessageBox(NULL,"能量的参数必须是模板弹性图",NULL,MB_OK); 
		return -1.0f; 
	} 
	int  i,j,m,n; 
	FLOAT f_result, f_tmp; 
	f_result=65000.0f; 
	//模板可以在被测图上进行微小的整体偏移,取所有偏移中最小的值为最终结果 
	for(i=-1;i<=1;i++) 
		for(j=-1;j<=1;j++) 
		{//****************************************** 
			f_tmp=0.0f;//累加 
			///眼睛区域(14×5),权值为1.2 
			for(n=2;n<7;n++) 
				for(m=2;m<16;m++)///眼睛区域(14×5) 
				{ 
					f_tmp+=1.2*Cal_neiji(tempEG->m_pvGraph[18*n+m],m_pvGraph[18*(n+i)+m+j]) 
						/((tempEG->m_module[18*n+m])*(m_module[18*(n+i)+m+j])); 
				}		 
			///嘴巴区域(8×6),权值为1.5 
				for(n=12;n<18;n++) 
					for(m=5;m<13;m++) 
					{ 
						f_tmp+=1.5*Cal_neiji(tempEG->m_pvGraph[18*n+m],m_pvGraph[18*(n+i)+m+j]) 
							/((tempEG->m_module[18*n+m])*(m_module[18*(n+i)+m+j]));					 
					} 
			///脸颊(4点),权值为0.9 
			n=10; m=7; 
				f_tmp+=0.9*Cal_neiji(tempEG->m_pvGraph[18*n+m],m_pvGraph[18*(n+i)+m+j]) 
					/((tempEG->m_module[18*n+m])*(m_module[18*(n+i)+m+j])); 
			n=11; m=7; 
				f_tmp+=0.9*Cal_neiji(tempEG->m_pvGraph[18*n+m],m_pvGraph[18*(n+i)+m+j]) 
					/((tempEG->m_module[18*n+m])*(m_module[18*(n+i)+m+j])); 
			n=10; m=11; 
				f_tmp+=0.9*Cal_neiji(tempEG->m_pvGraph[18*n+m],m_pvGraph[18*(n+i)+m+j]) 
					/((tempEG->m_module[18*n+m])*(m_module[18*(n+i)+m+j])); 
			n=11; m=11; 
				f_tmp+=0.9*Cal_neiji(tempEG->m_pvGraph[18*n+m],m_pvGraph[18*(n+i)+m+j]) 
					/((tempEG->m_module[18*n+m])*(m_module[18*(n+i)+m+j]));	 
			if(f_tmp>0) f_tmp*=-1.0f; 
			if(f_result>f_tmp) f_result=f_tmp; 
		}//********************************************* 
		return f_result; 
**************************************************************/ 
/**************************算法2************************************** 
//老算法 
//假设两个弹性图都是18×20个向量,则用本部分代码代替下面注释的部分 
//首先在模板的m_keyPoints[]定义的关键点处进行匹配,然后移动关键点,再进行弹性匹配 
/*	if((tempEG==NULL)||(tempEG->m_dimension!=360)) 
	{ 
		MessageBox(NULL,"能量的参数必须是模板弹性图",NULL,MB_OK); 
		return -1.0f; 
	} 
	int  i; 
	FLOAT f_result, f_tmp; 
	f_result=0.0f; 
 
	CPoint tmpPoint; 
	//不同关键点的权值 
	FLOAT afai[13]={1.5f,1.5f,1.5f,1.5f,1.5f,1.5f,0.8f,1.2f,1.2f,1.2f,1.2f,0.9f,0.9f}; 
	//位置变化的权值 
	FLOAT lamta=0.1f; 
	int m,n;//记录在被测表情中的搜索位置,搜索深度为3,即在7*7的空间中完全搜索 
	int c_x,c_y;//记录搜索的次数,分别是x和y方向 
	for(i=0;im_keyPoints[i].x; 
		tmpPoint.y=tempEG->m_keyPoints[i].y; 
		m=(tmpPoint.x-3<0)?0:tmpPoint.x-3; 
		n=(tmpPoint.y-3<0)?0:tmpPoint.y-3; 
		//计算该点处弹性变形时的最小能量 
		FLOAT f_minEng=10.0f; 
		//f_tmp=0; 
		for(c_y=0;(c_y<7)&&(n<20);c_y++,n++) 
			for(c_x=0;(c_x<7)&&(m<18);c_x++,m++) 
			{ 
				f_tmp=Cal_neiji(m_pvGraph[18*tmpPoint.y+tmpPoint.x],tempEG->m_pvGraph[18*tmpPoint.y+tmpPoint.x]) 
					/(m_module[18*tmpPoint.y+tmpPoint.x]*tempEG->m_module[18*tmpPoint.y+tmpPoint.x]); 
				if(f_tmp>0) f_tmp*=-1; 
				f_tmp=afai[i]*f_tmp+lamta*sqrt((3-c_x)*(3-c_x)+(3-c_y)*(3-c_y)); 
			} 
		if(f_minEng>f_tmp) f_minEng=f_tmp; 
		f_result+=f_minEng; 
	} 
	 
	return f_result; 
***********************************************************/ 
} 
 
FLOAT CEGraph::sub_CalEnergy(FLOAT testVect[], FLOAT tempVect[]) 
{ 
/* 
///采用论文中提出的计算向量相似度的公式代替下面注释的部分 
	FLOAT result=0.0f; 
	FLOAT neiji=0.0f;//内积 
*/ 
//欧氏距离 
	FLOAT result=0.0f; 
	FLOAT ftmp1; 
	int i; 
	for(i=0;i<18;i++) 
	{ 
		ftmp1=testVect[i]-tempVect[i]; 
		result+=ftmp1*ftmp1; 
	} 
	result=(FLOAT)sqrt(result); 
	return result; 
} 
 
FLOAT CEGraph::CalModule(FLOAT * vector) 
{ 
////计算向量模,要求输入的向量必须是18维 
	FLOAT result; 
	result=0.0f; 
	int i; 
	for(i=0;i<18;i++) 
	{ 
		result+=vector[i]*vector[i]; 
	} 
	result=sqrt(result); 
	return result; 
} 
 
FLOAT CEGraph::Cal_neiji(FLOAT vec1[], FLOAT vec2[]) 
{//计算两个向量的内积,要求这两个向量必须为18维 
	FLOAT result=0.0f; 
	int i; 
	for(i=0;i<18;i++) 
	{ 
		result+=vec1[i]*vec2[1]; 
	} 
	return result; 
} 
 
void CEGraph::DetectKeyPoints() 
{ 
	if(m_dimension==0) 
	{ 
		MessageBox(NULL,"请在检测关键点之前先进行Gabor变换!","INFO",MB_OK); 
		return; 
	} 
	/*GetKeys(CRect(2,4,9,10),0,2); 
	GetKeys(CRect(10,4,18,10),3,5); 
	GetKeys(CRect(6,2,12,6),6,6); 
	GetKeys(CRect(5,12,13,19),7,10); 
	GetKeys(CRect(6,10,9,15),11,11); 
	GetKeys(CRect(12,10,16,15),12,12);*/ 
	GetKeys(CRect(2,3,8,8),0,2); 
	GetKeys(CRect(11,3,17,8),3,5); 
	GetKeys(CRect(8,1,11,4),6,6); 
	GetKeys(CRect(5,12,13,18),7,10); 
	GetKeys(CRect(6,8,9,12),11,11); 
	GetKeys(CRect(10,9,13,12),12,12); 
} 
 
//由DetectKeyPoints()调用,在某个子区域里获得模最大的几个点 
//并将这几个点存入m_keyPoints[]数组中,从_from 到_to 
void CEGraph::GetKeys(CRect _subRect, int _from, int _to) 
{ 
	int num=_to-_from+1; 
	if(num>4) 
	{ 
		MessageBox(NULL,"在子区域中最多只能检测到4个最大模的点!","INFO",MB_OK); 
		return; 
	} 
	FLOAT key_val[4]={0.0f,0.0f,0.0f,0.0f};//从大到小排序,且关键点间至少要相隔两个像素的距离 
	CPoint key_point[4]; 
	key_point[0].x=_subRect.left; 
	key_point[0].y=_subRect.top; 
	int curx,cury;	 
	curx=_subRect.left-3; 
	cury=_subRect.top; 
	int i,j,m,k=0;//k表示当前已经找到的关键点数目, 
	for(i=_subRect.top;i<_subRect.bottom;i++) 
		for(j=_subRect.left;j<_subRect.right;j++) 
		{ 
			if((m_module[i*18+j]>key_val[k])&&((j>curx+2)||(i>cury))) 
			{///////////////////////////////////// 
				if(k < num-1) 
				{ 
					key_val[k+1]=key_val[k]; 
					key_point[k+1]=key_point[k]; 
				} 
				m=k-1; 
				while((m>=0)&&(m_module[i*18+j]>key_val[m])) 
				{ 
					key_val[m+1]=key_val[m]; 
					key_point[m+1]=key_point[m]; 
					m--; 
				} 
				key_val[m+1]=m_module[i*18+j]; 
				key_point[m+1].x=j; 
				key_point[m+1].y=i; 
				if(k < num-1) 
					k++; 
				//if(i>cury) 
				//	curx=_subRect.left; 
			//	else 
					curx=j; 
			//	cury=i; 
			}/////////////////////////////////// 
			if(i>cury) {cury=i; curx=_subRect.left-1;} 
		} 
	for(i=0;im_dimension!=360)) 
	{ 
		MessageBox(NULL,"未构造弹性图",NULL,MB_OK); 
		return -1.0f; 
	} 
	FLOAT f_result=65000.0f; 
	FLOAT x,y; 
	int i,j,m,n; 
	for(i=-2;i<=2;i++) 
		for(j=-2;j<=2;j++) 
		{ 
			FLOAT f_tmp=0.0f; 
			for(m=0;m<20;m++) 
				for(n=0;n<18;n++) 
				{ 
					if((m+i>=0)&&(m+i<20)&&(n+j>=0)&&(n+j<18)) 
					{ 
						x=m_module[(m+i)*18+(n+j)]; 
						y=tmpEGraph->m_module[m*18+n]; 
						f_tmp+=(x-y)*(x-y); 
					} 
				} 
			f_tmp=sqrt(f_tmp)/(360-2*(abs(i)*18+abs(j)*20-abs(i*j))); 
			if(f_result>f_tmp) 
				f_result=f_tmp; 
		} 
	return f_result; 
}