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
获取更多帮主请关注小程序