i-mode图像描绘的仿射变换的C++实现

曾经做项目的时候,用到了i-mode仿射变换的函数,对其算法寻找花费了不少时间,都没有找到最相像的。后来花费了一个周末,根据api提供的公式,重新复习下矩阵的计算,终于写了一个基本上完全一样效果的。看来,还是老老实实一些比较好写。

       #define EPSILON_E5 (int)(((int64)(1E-5))* (1< M[row][col] = ma->M[row][col] + mb->M[row][col];
		} // end for col

	} // end for row

} // end Mat_Add_3X3

////////////////////////////////////////////////////////////////////

void Mat_Mul_VECTOR3D_3X3(VECTOR3D_PTR  va, 
						  MATRIX3X3_PTR mb,
						  VECTOR3D_PTR  vprod)
{
	// this function multiplies a VECTOR3D against a 
	// 3x3 matrix - ma*mb and stores the result in mprod

	for (int col=0; col < 3; col++)
	{
		// compute dot product from row of ma 
		// and column of mb
		int sum = 0; // used to hold result

		for (int row=0; row<3; row++)
		{
			// add in next product pair
			sum+=(va->M[row]*mb->M[col][row]/*>>FIX_POINT*/);
		} // end for index

		// insert resulting col element
		vprod->M[col] = sum;

	} // end for col

} // end Mat_Mul_VECTOR3D_3X3

////////////////////////////////////////////////////////////////////

void Mat_Init_3X3(MATRIX3X3_PTR ma, 
				  int m00, int m01, int m02,
				  int m10, int m11, int m12,
				  int m20, int m21, int m22)
{
	// this function fills a 3x3 matrix with the sent data in row major form

	ma->M[0][0] = m00; ma->M[0][1] = m01; ma->M[0][2] = m02;
	ma->M[1][0] = m10; ma->M[1][1] = m11; ma->M[1][2] = m12;
	ma->M[2][0] = m20; ma->M[2][1] = m21; ma->M[2][2] = m22;

} // end Mat_Init_3X3

/////////////////////////////////////////////////////////////////

int Mat_Inverse_3X3(MATRIX3X3_PTR m, MATRIX3X3_PTR mi)
{
	// this function computes the inverse of a 3x3

	// first compute the determinate to see if there is 
	// an inverse
	int det = ((int64)m->M[0][0]*(((int64)m->M[1][1]*m->M[2][2]>>FIX_POINT) - ((int64)m->M[2][1]*m->M[1][2]>>FIX_POINT))>>FIX_POINT) - 
		((int64)m->M[0][1]*(((int64)m->M[1][0]*m->M[2][2]>>FIX_POINT) - ((int64)m->M[2][0]*m->M[1][2]>>FIX_POINT))>>FIX_POINT) + 
		((int64)m->M[0][2]*(((int64)m->M[1][0]*m->M[2][1]>>FIX_POINT) - ((int64)m->M[2][0]*m->M[1][1]>>FIX_POINT))>>FIX_POINT);

	if (fabs(det) < = EPSILON_E5)
		return(0);

	// compute inverse to save divides
	int det_inv = ((1<M[0][0] =  ((int64)det_inv*(((int64)m->M[1][1]*m->M[2][2]>>FIX_POINT) - ((int64)m->M[2][1]*m->M[1][2]>>FIX_POINT)))>>FIX_POINT;
	mi->M[1][0] = -((int64)det_inv*(((int64)m->M[1][0]*m->M[2][2]>>FIX_POINT) - ((int64)m->M[2][0]*m->M[1][2]>>FIX_POINT)))>>FIX_POINT;
	mi->M[2][0] =  (int64)det_inv*(((int64)m->M[1][0]*m->M[2][1]>>FIX_POINT) - ((int64)m->M[2][0]*m->M[1][1]>>FIX_POINT))>>FIX_POINT;

	mi->M[0][1] = -((int64)det_inv*(((int64)m->M[0][1]*m->M[2][2]>>FIX_POINT) - ((int64)m->M[2][1]*m->M[0][2]>>FIX_POINT)))>>FIX_POINT;
	mi->M[1][1] =  (int64)det_inv*(((int64)m->M[0][0]*m->M[2][2]>>FIX_POINT) - ((int64)m->M[2][0]*m->M[0][2]>>FIX_POINT))>>FIX_POINT;
	mi->M[2][1] = -((int64)det_inv*(((int64)m->M[0][0]*m->M[2][1]>>FIX_POINT) - ((int64)m->M[2][0]*m->M[0][1]>>FIX_POINT)))>>FIX_POINT;

	mi->M[0][2] =  (int64)det_inv*(((int64)m->M[0][1]*m->M[1][2]>>FIX_POINT) - ((int64)m->M[1][1]*m->M[0][2]>>FIX_POINT))>>FIX_POINT;
	mi->M[1][2] = -((int64)det_inv*(((int64)m->M[0][0]*m->M[1][2]>>FIX_POINT) - ((int64)m->M[1][0]*m->M[0][2]>>FIX_POINT)))>>FIX_POINT;
	mi->M[2][2] =  (int64)det_inv*(((int64)m->M[0][0]*m->M[1][1]>>FIX_POINT) - ((int64)m->M[1][0]*m->M[0][1]>>FIX_POINT))>>FIX_POINT;

	// return success
	return(1);

} // end Mat_Inverse_3X3

/////////////////////////////////////////////////////////////////



/////////////////////////////////////////////////////////////////

int Mat_Det_3X3(MATRIX3X3_PTR m)
{
	// computes the determinate of a 3x3 matrix using co-factor
	// expansion

	return((m->M[0][0]*((m->M[1][1]*m->M[2][2]>>FIX_POINT) - (m->M[2][1]*m->M[1][2]>>FIX_POINT))>>FIX_POINT) - 
		(m->M[0][1]*((m->M[1][0]*m->M[2][2]>>FIX_POINT) - (m->M[2][0]*m->M[1][2]>>FIX_POINT))>>FIX_POINT) + 
		(m->M[0][2]*((m->M[1][0]*m->M[2][1]>>FIX_POINT) - (m->M[2][0]*m->M[1][1]>>FIX_POINT))>>FIX_POINT) );

} // end Mat_Det_3X3

上面其实是要用到的算法,我记得是从《游戏编程大师》中摘抄的吧,中间为了计算正确,有一个最小值的判断,不然,可能会发生除0错误(1/det)。

        void drawImage(Image *img, int *buf, int ax, int ay, int aw, int ah)
{
	if( img == 0 )
		return;

	MATRIX3X3 Morg;
	MATRIX3X3 Mdes;
	Mat_Init_3X3( &Morg, buf[0], buf[1], buf[2] + (transX< >FIX_POINT);
	int miny = ((int)(min(min(des_left_top.M[1], des_right_top.M[1]), min(des_left_bottom.M[1], des_right_bottom.M[1])))>>FIX_POINT);
	int maxx = ((int)(max(max(des_left_top.M[0], des_right_top.M[0]), max(des_left_bottom.M[0], des_right_bottom.M[0])))>>FIX_POINT);
	int maxy = ((int)(max(max(des_left_top.M[1], des_right_top.M[1]), max(des_left_bottom.M[1], des_right_bottom.M[1])))>>FIX_POINT);
	
	if(minx >=  clip[0] + clip[2] || miny >= clip[1] + clip[3] || maxx < = clip[0] || maxy <= clip[1] )
		return;
	if( minx < clip[0] )
		minx = clip[0];
	if( maxx > clip[0] + clip[2] )
		maxx = clip[0] + clip[2];
	if( miny < clip[1] )
		miny = clip[1];
	if(maxy > clip[1] + clip[3] )
		maxy = clip[1] + clip[3];
	IBitmap *pback = IDISPLAY_GetDestination(m_pDisplay);
	IDIB* pDib = NULL;
	IBITMAP_QueryInterface( pback, AEECLSID_DIB, (void**)&pDib);
	IBITMAP_Release(pback);
	int* tablex_x = (int*)static_tablex_x;
	int* tablex_y = (int*)static_tablex_y;
	int* tabley_x = (int*)static_tabley_x;
	int* tabley_y = (int*)static_tabley_y;
for( int j = minx; j < maxx; j++)
{
	tablex_x[j-minx] = (j*Mdes.M[0][0]+Mdes.M[0][2])>>FIX_POINT;
}
for( int j = minx; j < maxx; j++)
{
	tablex_y[j-minx] = (j*Mdes.M[1][0]+Mdes.M[1][2])>>FIX_POINT;
}
for( int j = miny ; j < maxy; j++)
{
	tabley_x[j-miny] = (j*Mdes.M[0][1])>>FIX_POINT;
}
for( int j = miny; j < maxy; j++)
{
	tabley_y[j-miny] = (j*Mdes.M[1][1])>>FIX_POINT;
}
switch (img->m_pIDIB->nDepth) {
		case 16:
			{
				unsigned short *pdes = (unsigned short*)((unsigned char*)(pDib->pBmp) + pDib->nPitch * miny + (minx < < 1));
				unsigned short *psrc = (unsigned short*)((unsigned char*)(img->m_pIDIB->pBmp) + img->m_pIDIB->nPitch *(ay)+ ((ax) < < 1));
				int desstep = (pDib->nPitch >> 1) - (maxx - minx);
				int stepsrc = (img->m_pIDIB->nPitch>>1);
				int *ptablex_x = tablex_x;
				int *ptabley_x = tabley_x;
				int *ptablex_y = tablex_y;
				int *ptabley_y = tabley_y;
				for( int i = miny; i < maxy; i++, pdes += desstep, ptabley_x++, ptabley_y++, ptablex_x = tablex_x, ptablex_y = tablex_y )
					for( int j = minx; j < maxx; j++, pdes++, ptablex_x++, ptablex_y++ )
					{
						int x = (*ptablex_x+*ptabley_x);
						int y = (*ptablex_y+*ptabley_y);;
						if( x < 0 || y < 0 || x >= aw || y >= ah )
							continue;
						unsigned short *ptsrc = psrc + y * stepsrc + x;
						if( *ptsrc != img->m_pIDIB->ncTransparent )
							*pdes = *ptsrc;

					}
			}

			break;
	}
	IDIB_Release( pDib );
return;
}
        

基本上已经完全优化了,值得注意的是,我是根据公式反过来计算的,即扫描要填充的区域,计算在原图中的位置,如果在原图上,则填充,如果不在原图上,则跳过。这样做的好处就是防止由于误差引起的漏点。旋转也可以采用类似的方法,改天有时间的话,把代码找到放出来。上述函数的使用办法,请参考相关的i-mode的代码。

发布者

rix

如果连自己都不爱自己,哪还有谁来爱你