c++ 旋转算法 硬件加速

86 篇文章 0 订阅
48 篇文章 0 订阅

c++旋转算法:

此算法主要优点在于采用先计算矩阵参数速查表来做硬件加速。

首先要有个基础表

其定义与声明如下:

 

	typedef struct tagAreaLookUpRecord
	{
		__int64 nFactQW0;
		__int64 nFactQW1;
		__int64 nFactQW2;
		__int64 nFactQW3;
	}AreaLookUpRecord;
static AreaLookUpRecord m_aAreaLookUpTable[64];//声明

 

 

 

	if(!m_aAreaLookUpTable[0].nFactQW0)//没有初始化矩阵基表
	{
		int x, y;
		int nIndex;
		for (y = 0; y < 8; y++)
		{
			for (x = 0; x < 8; x++)
			{
				nIndex = (y << 3) + x;
				m_aAreaLookUpTable[(y << 3) + x].nFactQW0 = (8 - x) * (8 - y) * 0x1000000000000 + x * (8 - y) * 0x100000000 + (8 - x) * y * 0x10000 + x * y;
				m_aAreaLookUpTable[nIndex].nFactQW0 = (8-x)*(8-y)*0x1000000000000 + (8-x)*(8-y)*0x100000000 + (8-x)*(8-y)*0x10000 + (8-x)*(8-y);
				m_aAreaLookUpTable[nIndex].nFactQW1 = x*(8-y)*0x1000000000000 + x*(8-y)*0x100000000 + x*(8-y)*0x10000 + x*(8-y);
				m_aAreaLookUpTable[nIndex].nFactQW2 = (8-x)*y*0x1000000000000 + (8-x)*y*0x100000000 + (8-x)*y*0x10000 + (8-x)*y;
				m_aAreaLookUpTable[nIndex].nFactQW3 = x*y*0x1000000000000 +  x*y*0x100000000 + x*y*0x10000 + x*y;
			}
		}
	}

 


以下是算法部分:采用汇编语言。(公司元老做的算法加速)

 

 

 

 

//=================================================================
/// 快速旋转图像 (融合2.0 中 CEfxCore::RotationEx函数)
///参数:
///    pSrcBm32:原图像数据首地址
///    dwSrcWidth,dwSrcHeight :原图像宽度及高度
///    pTagBm32:目标图像数据地址
///    fangle:旋转角度(2.0为弧度数,此处为了与3.0一致,改成角度)
HRESULT CTrDib::RotationFast( void *pSrcBm32, DWORD dwSrcWidth, DWORD dwSrcHeight, void *pTagBm32, float fAngle )
{
	fAngle = fAngle/180 * PI;
	TRotPreBuilderValue *pXRotvalue;
	TRotPreBuilderValue *pYRotvalue;
	int x, y, MaxX, MaxY, nLineStep;
	float ox, oy,ox1, oy1;
	DWORD **pLineStartTable;
	float fCosV, fSinV;
	void *pMultptr;
	void *pXRotPtr;
	void *pYRotPtr;
	void *ltPtr;
	DWORD dwEspback;

	//	预先计算旋转矩阵的结果值	nx:= X*CosV - Y*SinV ; ny:= X*SinV + Y*CosV
	ox = dwSrcWidth / 2;
	oy = dwSrcHeight / 2;
	fCosV = cos(fAngle);
	fSinV = sin(fAngle);

	//-------------------------------------------------------------
	//	旋转矩阵参数速查表x部分
	pXRotvalue = new TRotPreBuilderValue[dwSrcWidth];

	for (x = 0; x < dwSrcWidth; x++)
	{
		pXRotvalue[x].nParamX = (int)((x - ox) * fCosV * 8 + 3 + 0.5 + (ox * 8));
		pXRotvalue[x].nParamY = (int)((x - ox) * fSinV * 8 + 3 + 0.5 + (oy * 8));		
	}
	//-------------------------------------------------------------

	//-------------------------------------------------------------
	//	旋转矩阵参数速查表Y部分
	pYRotvalue = new TRotPreBuilderValue[dwSrcHeight];

	for (y = 0; y < dwSrcHeight; y++)
	{
		pYRotvalue[y].nParamX = (-(y - oy) * fSinV * 8 + 0.5);
		pYRotvalue[y].nParamY = ( (y - oy) * fCosV * 8 + 0.5);
	}
	//-------------------------------------------------------------

	//-------------------------------------------------------------
	//	计算行起点速查表(取整前)
	pLineStartTable = new DWORD* [dwSrcHeight << 3];

	for (y = 0; y < (dwSrcHeight << 3); y++)
		pLineStartTable[y] = (DWORD *)pSrcBm32 + (y >> 3) * dwSrcWidth;
	//-------------------------------------------------------------

	MaxX = (dwSrcWidth - 2) << 3;
	MaxY = (dwSrcHeight - 2) << 3;

	pMultptr = &m_aAreaLookUpTable[0];
	pXRotPtr = &pXRotvalue[0];
	pYRotPtr = &pYRotvalue[0];
	ltPtr = &pLineStartTable[0];

	nLineStep = dwSrcWidth << 2;

	__asm
	{
		push  esi
		push  edi
		push  ebx
		mov   dwEspback, esp

		xor   edx, edx
		mov   esp, pTagBm32
		movd  mm5, pXRotPtr
		movd  mm6, pYRotPtr
		movd  mm7, pMultptr

lineloop:
		xor   ecx, ecx

pixloop:
		movd  esi, mm5
		movd  edi, mm6
		mov   eax, [esi+ecx*8]
		add   eax, [edi+edx*8]
		js    nextpixloop
		mov   ebx, [esi+ecx*8+4]
		add   ebx, [edi+edx*8+4]
		js    nextpixloop
		cmp   eax, MaxX
		jg    nextpixloop
		cmp   ebx, MaxY
		jg	  nextpixloop

process:
		mov   edi,ltPtr
		mov   edi,[edi+ebx*4]
		mov   esi, eax
		shr   esi, 3

		and       ebx, 0x7
		shl       ebx, 3
		and       eax, 0x7
		add       eax, ebx
		shl       eax, 5
		movd      ebx, mm7

		punpcklbw MM0, [edi+esi*4]
		punpcklbw MM1, [edi+esi*4+4]
		psrlw     MM0, 8
		psrlw     MM1, 8

		add       edi, nLineStep
		punpcklbw MM2, [edi+esi*4]
		punpcklbw MM3, [edi+esi*4+4]
		psrlw     MM2, 8
		psrlw     MM3, 8


		movq      MM4, [ebx + eax ]
		pmullw    MM0, MM4
		movq      MM4, [ebx + eax+8 ]
		pmullw    MM1, MM4
		movq      MM4, [ebx + eax+16 ]
		pmullw    MM2, MM4
		movq      MM4, [ebx + eax +24]
		pmullw    MM3, MM4

		paddsw    MM0, MM1
		paddsw    MM0, MM2
		paddsw    MM0, MM3
		psrlw     MM0, 6
		PACKUSWB  MM0,  MM0
		MOVD      [esp],MM0

nextpixloop:
		add   esp,4
		inc   ecx
		cmp   ecx, dwSrcWidth
		jne   pixloop

nextline:
		inc   edx
		cmp   edx , dwSrcHeight
		jne   lineloop

exit:
		mov   esp, dwEspback
		pop   ebx
		pop   edi
		pop   esi
		Emms
	}

	delete []pXRotvalue;
	delete []pYRotvalue;
	delete []pLineStartTable;
}
///end

 

 

 

 

 

 

 

 

 

特别说明:此算法要求原图像要与目标图像的矩形宽高一致:故我们在调用之前需要先构造两个边长为原矩形对角线的正方形矩形,并将原图像拷贝到第一个矩形中央,

然后做旋转,结果保存在第二个矩形中,最后得出结果在做最大剪裁。

 

以下为内部程序代码:(没多大实用性,但能看出思路)

 

 

 
template<bool B> struct __MyBoolType{};//用于萃取
HRESULT _RotationTract(ITrDib **lplpiDib , float fAngle, __MyBoolType<false>);//未初始化时使用,用于初始化缓存或矩阵速查表基表
HRESULT _RotationTract(ITrDib **lplpiDib , float fAngle, __MyBoolType<true>);//用于已经初始化(缓存)路线调用
 
HRESULT _RotationTract(ITrDib **lplpiDib , float fAngle, __MyBoolType<false> )
{
	HRESULT hr = S_OK;
	 源图像 DIB 数据
	PTRDIB pDibInfoSrc = GetInfoAddr();
	if (!pDibInfoSrc)
		return TRE_INVALIDDIB;
	//创建最大包容缓存
	m_ptrCachDib = NULL;
	int dSide =sqrt(::pow((double)pDibInfoSrc->nWidth,2) + ::pow((double)pDibInfoSrc->nHeight,2))+0.5;//正方形最大边长

	//创建图像
	if (FAILED(hr = GetCore()->CreateDIB(&m_ptrCachDib,dSide,dSide,GetInfoAddr()->type)))
		return hr;

	POINT pont ={(dSide - pDibInfoSrc->nWidth)/ 2, (dSide - pDibInfoSrc->nHeight)/ 2};
	RECT rect = {0,0,pDibInfoSrc->nWidth,pDibInfoSrc->nHeight};
	 拷贝图像
	if (FAILED(hr = m_ptrCachDib->AlphaBlend(this,&pont,&rect,0xFF,TRBLM_COPY)))
		return hr;

	//m_ptrCachDib.QueryInterface(lplpiDib);
	
	//-------------------------------end

	if(!m_aAreaLookUpTable[0].nFactQW0)//没有初始化矩阵基表
	{
		int x, y;
		int nIndex;
		for (y = 0; y < 8; y++)
		{
			for (x = 0; x < 8; x++)
			{
				nIndex = (y << 3) + x;
				m_aAreaLookUpTable[(y << 3) + x].nFactQW0 = (8 - x) * (8 - y) * 0x1000000000000 + x * (8 - y) * 0x100000000 + (8 - x) * y * 0x10000 + x * y;
				m_aAreaLookUpTable[nIndex].nFactQW0 = (8-x)*(8-y)*0x1000000000000 + (8-x)*(8-y)*0x100000000 + (8-x)*(8-y)*0x10000 + (8-x)*(8-y);
				m_aAreaLookUpTable[nIndex].nFactQW1 = x*(8-y)*0x1000000000000 + x*(8-y)*0x100000000 + x*(8-y)*0x10000 + x*(8-y);
				m_aAreaLookUpTable[nIndex].nFactQW2 = (8-x)*y*0x1000000000000 + (8-x)*y*0x100000000 + (8-x)*y*0x10000 + (8-x)*y;
				m_aAreaLookUpTable[nIndex].nFactQW3 = x*y*0x1000000000000 +  x*y*0x100000000 + x*y*0x10000 + x*y;
			}
		}
	}
	
	return _RotationTract(lplpiDib,fAngle, __MyBoolType<true>());
}

HRESULT _RotationTract(ITrDib **lplpiDib , float fAngle, __MyBoolType<true> )
{
	HRESULT hr = S_OK;

	 源图像 DIB 数据
	PTRDIB pDibInfoSrc = GetInfoAddr();
	if (!pDibInfoSrc)
		return TRE_INVALIDDIB;

	// 旋转中心点
	CPoint pntCenter(pDibInfoSrc->nWidth / 2, pDibInfoSrc->nHeight / 2);

	// 旋转后的四个顶点坐标:TopLeft, TopRight, BottomRight, BottomLeft
	POINT  pntNew[4] = {{0, 0}, {pDibInfoSrc->nWidth, 0}, {pDibInfoSrc->nWidth, pDibInfoSrc->nHeight}, {0, pDibInfoSrc->nHeight}}; 
	for (int n=0;n<4;n++)
		pntNew[n] = TRANSFORM_PARAM::RotationPoint(pntNew[n],pntCenter,fAngle);

	// 旋转后的方框 (4个点最大矩形)
	int nNewLeft	= min4(pntNew[0].x,pntNew[1].x,pntNew[2].x,pntNew[3].x);
	int nNewTop	= min4(pntNew[0].y,pntNew[1].y,pntNew[2].y,pntNew[3].y);
	int nNewRight	= max4(pntNew[0].x,pntNew[1].x,pntNew[2].x,pntNew[3].x);
	int nNewBottom	= max4(pntNew[0].y,pntNew[1].y,pntNew[2].y,pntNew[3].y);

	 新源图像 DIB 数据
	PTRDIB pDibInfoSrc2 = m_ptrCachDib->GetInfoAddr();

	//创建图像
	ITrDibPtr ptrDstDib = NULL;			// 目标图像
	if (FAILED(hr = GetCore()->CreateDIB(&ptrDstDib,pDibInfoSrc2->nWidth,pDibInfoSrc2->nHeight,pDibInfoSrc2->type)))
		return hr;

	TRDIB DibDst;
	ptrDstDib->GetInfo(DibDst);

	RotationFast((RGBA32Color *)pDibInfoSrc2->pvData,pDibInfoSrc2->nWidth,pDibInfoSrc2->nHeight,(RGBA32Color *)DibDst.pvData,fAngle);

	//裁剪
	int cx = nNewRight - nNewLeft,cy = nNewBottom - nNewTop;
	//矫正偏移
	int x = (pDibInfoSrc2->nWidth - cx)/2 + 0.5,y=(pDibInfoSrc2->nHeight - cy)/2 + 0.5;
	RECT rect={x,y,x+cx,y+cy};

	if (FAILED(hr = GetCore()->CreateDIB(lplpiDib,cx,cy,pDibInfoSrc->type)))
		return hr;

	
	(*lplpiDib)->AlphaBlend(ptrDstDib,NULL,&rect,0xFF,TRBLM_COPY);

	//-----------------end

	return S_OK;
}

 

 

 

 

 

友情链接:

http://www.cnblogs.com/ywxgod/archive/2010/08/06/1793609.html

http://blog.csdn.net/tangyongkang/article/details/5484636

获取更多帮主请关注小程序

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值