以下文字内容copy于<<数字图像处理
编程入门>>,code为自己实现,是win32控制台程序。
?
旋转(rotation)有一个绕着什么转的问题,通常的做法是以图象的中心为圆心旋转,举个例子,图2.7旋转30度(顺时针方向)后如图2.8所示:
?
?
?
可以看出,旋转后图象变大了。另一种做法是不让图象变大,转出的部分被裁剪掉。如图2.9所示。
我们采用第一种做法,首先给出变换矩阵。在我们熟悉的坐标系中,将一个点顺时针旋转a角后的坐标变换公式,如图2.10所示,r为该点到原点的距离,在旋转过程中,r保持不变;b为r与x轴之间的夹角。
?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
?
旋转前:x0=rcosb;y0=rsinb
?
旋转a角度后:
?
x1=rcos(b-a)=rcosbcosa+rsinbsina= x0cosa+y0sina;
?
y1=rsin(b-a)=rsinbcosa-rcosbsina= -x0sina+y0cosa;
?
以矩阵的形式表示:? ? ? ?
?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(2.5)?
上面的公式中,坐标系xoy是以图象的中心为原点,向右为x轴正方向,向上为y轴正方向。它和以图象左上角点为原点o’,向右为x’轴正方向,向下为y’轴正方向的坐标系x’o’y’之间的转换关系如何呢?如图2.11所示。
?
?
?
?
?
图2.11 ? ?两种坐标系间的转换关系
?
设图象的宽为w,高为h,容易得到:
?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(2.6)?
逆变换为:
?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (2.7)?
有了上面的公式,我们可以把变换分成三步:
?
1.将坐标系o’变成o;
?
2.将该点顺时针旋转a角;
?
3.将坐标系o变回o’,这样,我们就得到了变换矩阵,是上面三个矩阵的级联。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(2.8)?
要注意的是,因为新图变大,所以上面公式中出现了wold,hold,wnew,hnew,它们分别表示原图(old)和新图(new)的宽、高。我们从图2.8中容易看出:wnew=max(|x4-x1|,|x3-x2|);hnew=max(|y4-y1|,|y3-y2|)。
?
(2.8)的逆变换为
?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

(2.9)?
这样,对于新图中的每一点,我们就可以根据公式(2.9)求出对应原图中的点,得到它的灰度。如果超出原图范围,则填成白色。要注意的是,由于有浮点运算,计算出来点的坐标可能不是整数,采用取整处理,即找最接近的点,这样会带来一些误差(图象可能会出现锯齿)。更精确的方法是采用插值,将在图象缩放时介绍。
?
源程序如下:
?
[cpp]?
/**?
* 程序名: Rotation.cpp?
* 功 ?能: 实现灰度图像的旋转,如果超出原图范围,则用白色填充?
* ? ? ? ? 测试位图为test.bmp放到工程目录下?
*/ ?
#include ??
#include ??
#include ??
#include ??
using namespace std; ?
#define PI 3.1415926535 ??
#define RADIAN(angle) (((angle)*PI)/180.0) ??
BITMAPFILEHEADER bmpFileHeader; ? //bmp文件头 ??
BITMAPINFOHEADER bmpInfoHeader; ? //bmp信息头 ??
RGBQUAD *pColorTable; ? ? ? ? ? ?//bmp颜色表 ? ? ?
unsigned char *pBmpData; ? ? ? ?//bmp位图数据 ??
unsigned char *pNewBmpData; ? //旋转后bmp位图数据 ??
int newImgSize; ? ? ? ? //旋转后图像大小 ??
??
/**?
* 函数名: readBmp?
* 参 ?数: fileName--要读取文件的文件名?
* 功 ?能: 读取bmp位图数据,成功返回TRUE,否则返回FALSE?
*/ ?
BOOL readBmp(char *fileName) ?
{ ?
? ? FILE *fp = fopen(fileName,"rb"); ? //以二进制读方式打开 ??
? ? if (NULL == fp) ?
? ? { ?
? ? ? ? cout<<"The file is opened failure!"<
? ? ? ? return FALSE; ?
? ? } ?
? ? //读取信息到相应的变量中 ??
? ? fread(&bmpFileHeader,sizeof(BITMAPFILEHEADER),1,fp); ?
? ? fread(&bmpInfoHeader,sizeof(BITMAPINFOHEADER),1,fp); ?
? ? pColorTable = new RGBQUAD[256]; ?
? ? fread(pColorTable,sizeof(RGBQUAD),256,fp); ?
? ? int imgSize = bmpInfoHeader.biSizeImage; ? ? //文图数据的大小,4的倍数 ??
? ? pBmpData = new ?unsigned char[imgSize]; ?
? ? fread(pBmpData,sizeof(unsigned char),imgSize,fp); ?
? ? fclose(fp); ?
? ? return TRUE; ?
} ?
/**?
* 函数名: rotation?
* 参 ?数: rotAngle--要转换的角度?
* 功 ?能: 实现bmp图像的旋转?
*/ ?
void rotation(int rotAngle) ?
{ ?
? ? double cosa,sina,srcX[4],srcY[4],dstX[4],dstY[4],rad; ?
? ? int oldWidth,oldHeight,newWidth,newHeight; ?
? ? rad = (double)RADIAN(rotAngle); ?
? ? cosa = cos(rad); ?
? ? sina = sin(rad); ?
? ? //原图宽与高 ??
? ? oldWidth = bmpInfoHeader.biWidth; ?
? ? oldHeight = bmpInfoHeader.biHeight; ?
? ? //原图四个角的坐标 ??
? ? srcX[0] = -0.5 * oldWidth; ?
? ? srcY[0] = 0.5 * oldHeight; ?
? ? srcX[1] = 0.5 * oldWidth; ?