zl程序教程

您现在的位置是:首页 >  工具

当前栏目

图像编程学习笔记3——图像旋转

笔记学习编程 图像 旋转
2023-09-27 14:29:33 时间

 

旋转(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)求出对应原图中的点,得到它的灰度。如果超出原图范围,则填成白色。要注意的是,由于有浮点运算,计算出来点的坐标可能不是整数,采用取整处理,即找最接近的点,这样会带来一些误差(图象可能会出现锯齿)。更精确的方法是采用插值,将在图象缩放时介绍。

源程序如下:


* 功  能: 实现灰度图像的旋转,如果超出原图范围,则用白色填充  *         测试位图为test.bmp放到工程目录下  #include  iostream    #include  fstream    #include  cstring    #include  cmath    #include  windows.h    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!" endl;           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;       srcY[1] = 0.5 * oldHeight;       srcX[2] = 0.5 * oldWidth;       srcY[2] = -0.5 * oldHeight;       srcX[3] = -0.5 * oldWidth;       srcY[3] = -0.5 * oldHeight;       //新图四个角坐标       for(int i = 0; i   i++ )       {           dstX[i] = cosa * srcX[i] + sina * srcY[i];           dstY[i] = -sina * srcX[i] + cosa * srcY[i];   //      cout dstY[i] endl;       }       //新图的宽与高,向上取整       bmpInfoHeader.biWidth = newWidth = (int)(max(fabs(dstX[0] - dstX[2]),fabs(dstX[1] - dstX[3])) + 0.5);       bmpInfoHeader.biHeight = newHeight = (int)(max(fabs(dstY[0] - dstY[2]),fabs(dstY[1] - dstY[3])) + 0.5);   //  cout newWidth newHeight endl;       //新图位图数据大小       bmpInfoHeader.biSizeImage = newImgSize = newHeight * ((newWidth * bmpInfoHeader.biBitCount + 31) / 32 * 4);       pNewBmpData = new unsigned char[newImgSize];       double temp1,temp2;   //计算矩阵(2.9)中的两个常数,这样不用以后每次都计算了       temp1 = -0.5 * newWidth * cosa - 0.5 * newHeight * sina + 0.5 * oldWidth;       temp2 = 0.5 * newWidth * sina - 0.5 * newHeight * cosa + 0.5 * oldHeight;       memset(pNewBmpData,(BYTE)255,newImgSize);   //先全部填充成白色       int x0,y0,x1,y1;       unsigned char *pOldTemp,*pNewTemp;       int oldLineByte,newLineByte;       oldLineByte = (oldWidth * bmpInfoHeader.biBitCount + 31) / 32 * 4;       newLineByte = (newWidth * bmpInfoHeader.biBitCount + 31) / 32 * 4;       //把旋转后的图像数据对应存储到pNewBmpData相应位置       for(y1 = 0; y1   newHeight; y1++)       {           for(x1 = 0; x1   newWidth; x1++ )           {               x0 = (int)(x1 * cosa + y1 * sina + temp1);               y0 = (int)(-x1 * sina + y1 * cosa + temp2);               if((x0  = 0   x0   oldWidth)   (y0  = 0   y0   oldHeight))    //这里不能为 =oldWidth或oldHeight               {                   pOldTemp = pBmpData + (oldHeight - 1 - y0) * oldLineByte + x0;                   pNewTemp = pNewBmpData + (newHeight - 1 - y1) * newLineByte + x1;                   *pNewTemp = *pOldTemp;               }           }       }   * 函数名: writeBmp  * 参  数: bmpName -- 旋转后的bmp文件名  * 功  能: 新建一个bmp文件,把旋转后的图像信息存入其中  void writeBmp(char *bmpName)       FILE *fp = fopen(bmpName,"wb");  //以二进制写方式打开       if(NULL == fp)           cout "The file is opened failure" endl;       //写入选装后图像信息       fwrite( bmpFileHeader,sizeof(BITMAPFILEHEADER),1,fp);       fwrite( bmpInfoHeader,sizeof(BITMAPINFOHEADER),1,fp);       fwrite(pColorTable,sizeof(RGBQUAD),256,fp);       fwrite(pNewBmpData,sizeof(unsigned char),newImgSize,fp);       fclose(fp);           delete []pColorTable;           delete []pNewBmpData;           delete []pBmpData;   * 函数名: work  * 参  数: 无  * 功  能: 实现处理工作  void work()       char readBmpName[] = "test.bmp";       if ( !readBmp(readBmpName))           cout "The file " readBmpName "is read failure" endl;       cout "please input the angle to rotate(Clockwise):";       int rotAngle;       cin rotAngle;       rotation(rotAngle);       char writeBmpName[] = "test_new.bmp";       writeBmp(writeBmpName);   int main()       work();       return 0;  
【动手学计算机视觉】第二讲:图像预处理之图像增强 计算机视觉主要有两部分组成: 其中第一条特征提取在计算机视觉中占据着至关重要的位置,尤其是在传统的计算机视觉算法中,更为明显,例如比较著名的HOG、DPM等目标识别模型,主要的研究经历都是在图像特征提取方面。图像增强能够有效的增强图像中有价值的信息,改善图像质量,能够满足一些特征分析的需求,因此,可以用于计算机视觉数据预处理中,能够有效的改善图像的质量,进而提升目标识别的精度。
【动手学计算机视觉】第四讲:图像预处理之图像增广(上) 近几年深度学习的大规模成功应用主要的就是得益于数据的累积和算例的提升,虽然近几年很多研究者竭力的攻克半监督和无监督学习,减少对大量数据的依赖,但是目前数据在计算机视觉、自然语言处理等人工智能技术领域依然占据着非常重要的地位。甚至可以说,大规模的数据是计算机视觉成功应用的前提条件。但是由于种种原因导致数据的采集变的十分困难,因此图像增广技术就在数据的准备过程中占据着举足轻重的角色,本文就概括一下常用的图像增广技术并编程实现相应手段。