图像旋转算法
cndg
图像旋转是将新旧坐标值转换以及像素间线性插值处理,由于坐标值转换时使用到乘法运算,本文使用加法运算替换乘法运算解决速度问题。
代码如下:
//函数功能:图象旋转
//参数说明:iSrc,表示原始图像;iDst,表示目标图像;Angle,表示旋转角度;nColorType,表示边界外区域填充颜色
//返回值:无
void ImageRotate2(CxImage* iSrc,CxImage* iDst,double Angle,int nColorType)
{
LONG nWidth,nHeight,nEffectWidth,nBpp,nXDpi,nYDpi,nNewEffectWidth,ImageHeight,ImageWidth;
nWidth = iSrc->GetWidth();
nHeight = iSrc->GetHeight();
nEffectWidth = iSrc->GetEffWidth();
nBpp = iSrc->GetBpp();
nXDpi = iSrc->GetXDPI();
nYDpi = iSrc->GetYDPI();
BYTE *S = NULL,Value;
S = iSrc->GetBits();
double vcos,vsin;
double cx,cy,vx,vy,cntx,cnty;
LONG off,off1,off2,nOffset;
LONG i,j,m,n;
double an,svx,svy;
double dx0,dy0,dx1,dy1,zz;
an = Angle*PI/180.0;
vcos = cos(an); vsin = sin(an);
// 源图四个角的坐标(以图像中心为坐标系原点)
float fSrcX1,fSrcY1,fSrcX2,fSrcY2,fSrcX3,fSrcY3,fSrcX4,fSrcY4;
// 旋转后四个角的坐标(以图像中心为坐标系原点)
float fDstX1,fDstY1,fDstX2,fDstY2,fDstX3,fDstY3,fDstX4,fDstY4;
// 计算原图的四个角的坐标(以图像中心为坐标系原点)
fSrcX1 = (float) (- (nWidth - 1) / 2);
fSrcY1 = (float) ( (nHeight - 1) / 2);
fSrcX2 = (float) ( (nWidth - 1) / 2);
fSrcY2 = (float) ( (nHeight - 1) / 2);
fSrcX3 = (float) (- (nWidth - 1) / 2);
fSrcY3 = (float) (- (nHeight - 1) / 2);
fSrcX4 = (float) ( (nWidth - 1) / 2);
fSrcY4 = (float) (- (nHeight - 1) / 2);
// 计算新图四个角的坐标(以图像中心为坐标系原点)
fDstX1 = vcos * fSrcX1 + vsin * fSrcY1;
fDstY1 = -vsin * fSrcX1 + vcos * fSrcY1;
fDstX2 = vcos * fSrcX2 + vsin * fSrcY2;
fDstY2 = -vsin * fSrcX2 + vcos * fSrcY2;
fDstX3 = vcos * fSrcX3 + vsin * fSrcY3;
fDstY3 = -vsin * fSrcX3 + vcos * fSrcY3;
fDstX4 = vcos * fSrcX4 + vsin * fSrcY4;
fDstY4 = -vsin * fSrcX4 + vcos * fSrcY4;
// 计算旋转后的图像实际宽度
ImageWidth = (LONG) ( max( fabs(fDstX4 - fDstX1), fabs(fDstX3 - fDstX2) ) + 0.5);
// 计算旋转后的图像高度
ImageHeight = (LONG) ( max( fabs(fDstY4 - fDstY1), fabs(fDstY3 - fDstY2) ) + 0.5);
double f1,f2;
f1 = (double) (-0.5 * (ImageWidth - 1) * vcos - 0.5 * (ImageHeight - 1) * vsin + 0.5 * (nWidth - 1));
f2 = (double) ( 0.5 * (ImageWidth - 1) * vsin - 0.5 * (ImageHeight - 1) * vcos + 0.5 * (nHeight - 1));
////////////////////////////////////////////////////////////////////////////////
//分配空间
nNewEffectWidth = (ImageWidth * nBpp + 31)/32 * 4;
BYTE *D = new BYTE[nNewEffectWidth*ImageHeight];
if(nColorType==1)//黑色
{
memset(D,0,sizeof(BYTE)*(nNewEffectWidth*ImageHeight));
}
else
{
memset(D,255,sizeof(BYTE)*(nNewEffectWidth*ImageHeight));
}
/////////////////////////////////////////////////////////////////////////////////
cntx = f1+0.5;
cnty = f2+0.5;
cx = 0; cy = 0;
svx = cx*vcos+cy*vsin+cntx;
svy = -cx*vsin+cy*vcos+cnty;
off = 0,off1 = 0;
LONG i0,j0;
for(i=0;i<ImageHeight;i++)
{
vx = svx;
vy = svy;
off = i * nNewEffectWidth + 0;
for(j=0;j<ImageWidth;j++)
{
// 计算该象素在S中的坐标
// vy = -j * vsin + i * vcos + f2 + 0.5;
// vx = j * vcos + i * vsin + f1 + 0.5;
m = (LONG)vx;
n = (LONG)vy;
if((m<1)||(m>nWidth-2)||(n<1)||(n>nHeight-2))
{
zz = 0;
if(nBpp==24)
{
if(nColorType==1)//黑色
{
zz = 0;
}
else
{
zz = 255;
}
D[off]=(int)zz;
D[off+1]=(int)zz;
D[off+2]=(int)zz;
}
else
{
if(nColorType==1)//黑色
{
zz = 0;
}
else
{
zz = 255;
}
D[off]=(int)zz;
}
}
else
{
if(nBpp==24)
{
dx0 = vx-m; dy0 = vy-n;
dx1 = 1-dx0;dy1 = 1-dy0;
off1 = n*nEffectWidth+3*m;
zz = 0;
zz = S[off1]*dx1*dy1;
off2 = off1+3;
zz += S[off2]*dx0*dy1;
off2 = off1+nEffectWidth;
zz += S[off2]*dx1*dy0;
off2 = off1+nEffectWidth+3;
zz += S[off2]*dx0*dy0;
if(zz>255)
zz= 255;
if(zz<0)
zz = fabs(zz);
D[off]=(int)zz;
off1 = n*nEffectWidth+3*m+1;
zz = 0;
zz = S[off1]*dx1*dy1;
off2 = off1+3;
zz += S[off2]*dx0*dy1;
off2 = off1+nEffectWidth;
zz += S[off2]*dx1*dy0;
off2 = off1+nEffectWidth+3;
zz += S[off2]*dx0*dy0;
if(zz>255)
zz= 255;
if(zz<0)
zz = fabs(zz);
D[off+1]=(int)zz;
off1 = n*nEffectWidth+3*m+2;
zz = 0;
zz = S[off1]*dx1*dy1;
off2 = off1+3;
zz += S[off2]*dx0*dy1;
off2 = off1+nEffectWidth;
zz += S[off2]*dx1*dy0;
off2 = off1+nEffectWidth+3;
zz += S[off2]*dx0*dy0;
if(zz>255)
zz= 255;
if(zz<0)
zz = fabs(zz);
D[off+2]=(int)zz;
}
else
{
dx0 = vx-m; dy0 = vy-n;
dx1 = 1-dx0;dy1 = 1-dy0;
off1 = n*nEffectWidth+m;
zz = 0;
zz = S[off1]*dx1*dy1;
off2 = off1+1;
zz += S[off2]*dx0*dy1;
off2 = off1+nEffectWidth;
zz += S[off2]*dx1*dy0;
off2 = off1+nEffectWidth+1;
zz += S[off2]*dx0*dy0;
if(zz>255)
zz= 255;
if(zz<0)
zz = fabs(zz);
D[off]=(int)zz;
}
}
if(nBpp==24)
{
off +=3;
}
else
{
off++;
}
vx = vx + vcos;
vy = vy - vsin;
}
svx=svx+vsin;
svy=svy+vcos;
}
CxImage tmp;
tmp.Copy(*iSrc);
tmp.Create(ImageWidth,ImageHeight,nBpp,iSrc->GetType());
tmp.SetPalette(iSrc->GetPalette());
// tmp.SetXDPI(nXDpi);
// tmp.SetYDPI(nYDpi);
RGBQUAD color;
for(i=0;i<ImageHeight;i++)
{
for(j=0;j<ImageWidth;j++)
{
nOffset = i * nNewEffectWidth + (nBpp/8) * j;
if(nBpp==24)
{
//color = RGB(D[nOffset],D[nOffset+1],D[nOffset+2]);
color.rgbRed = D[nOffset+2];
color.rgbGreen = D[nOffset+1];
color.rgbBlue = D[nOffset];
color.rgbReserved = 0;
tmp.SetPixelColor(j,i,color);
}
else
{
tmp.SetPixelIndex(j,i,D[nOffset]);
} }
}
if(iDst)
iDst->Copy(tmp);
else
iSrc->Copy(tmp);
if(D)
{
delete []D;
D = NULL;
}
}