zoukankan      html  css  js  c++  java
  • 图像旋转算法与实现

    好吧,先下个定义,图像旋转是指图像以某一点为中心旋转一定的角度,形成一幅新的图像的过程。当然这个点通常就是图像的中心。既然是按照中心旋转,自然会有这样一个属性:旋转前和旋转后的点离中心的位置不变.

    根据这个属性,我们可以得到旋转后的点的坐标与原坐标的对应关系。由于原图像的坐标是以左上角为原点的,所以我们先把坐标转换为以图像中心为原点。假设原图像的宽为w,高为h,(x0,y0)为原坐标内的一点,转换坐标后的点为(x1,y1)。那么不难得到:

    x1 = x0 - w/2; y1 = -y0 + h/2;

    在新的坐标系下,假设点(x0,y0)距离原点的距离为r,点与原点之间的连线与x轴的夹角为b,旋转的角度为a,旋转后的点为(x1,y1), 如下图所示。

    那么有以下结论:

    x0=rcosb;y0=rsinb

    x1 = rcos(b-a) = rcosbcosa+rsinbsina=x0cosa+y0sina;

    y1=rsin(b-a)=rsinbcosa-rcosbsina=-x0sina+y0cosa;

    得到了转换后的坐标,我们只需要把这些坐标再转换为原坐标系即可。这里还有一点要注意,旋转后的图像的长和宽会发生变化,因此要计算新图像的长和宽。

    以下为源程序:

      1 #include "stdafx.h"
      2 #include <stdio.h>
      3 #include <string>
      4 #include <math.h>
      5 #include <windows.h>
      6  using namespace std;
      7 
      8  #define PI 3.1415926535
      9 //角度到弧度转化
     10 #define RADIAN(angle) ((angle)*PI/180.0)
     11 
     12 void Rotation(const string& srcFile,const string& desFile,int angle)
     13 {
     14     BITMAPFILEHEADER bmfHeader;
     15     BITMAPINFOHEADER bmiHeader;
     16     
     17     FILE *pFile;
     18     if ((pFile = fopen(srcFile.c_str(),"rb")) == NULL)
     19     {
     20         printf("open bmp file error.");
     21         exit(-1);
     22     }
     23     //读取文件和Bitmap头信息
     24     fseek(pFile,0,SEEK_SET);
     25     fread(&bmfHeader,sizeof(BITMAPFILEHEADER),1,pFile);
     26     fread(&bmiHeader,sizeof(BITMAPINFOHEADER),1,pFile);
     27     //先不支持小于16位的位图
     28     int bitCount = bmiHeader.biBitCount;
     29     if (bitCount < 16)
     30     {        
     31         exit(-1);
     32     }
     33     int srcW = bmiHeader.biWidth;
     34     int srcH = bmiHeader.biHeight;
     35     //原图像每一行去除偏移量的字节数
     36     int lineSize = bitCount * srcW / 8;
     37     //偏移量,windows系统要求每个扫描行按四字节对齐
     38     int alignBytes = ((bmiHeader.biWidth * bitCount + 31) & ~31) / 8L
     39         - bmiHeader.biWidth * bitCount / 8L;
     40     //原图像缓存
     41     int srcBufSize = lineSize * srcH;
     42     BYTE* srcBuf = new BYTE[srcBufSize];
     43     int i,j;
     44     //读取文件中数据
     45     for (i = 0; i < srcH; i++)
     46     {        
     47         fread(&srcBuf[lineSize * i],lineSize,1,pFile);
     48         fseek(pFile,alignBytes,SEEK_CUR);
     49     }
     50     //以图像中心为原点左上角,右上角,左下角和右下角的坐标,用于计算旋转后的图像的宽和高
     51     POINT pLT,pRT,pLB,pRB;
     52     pLT.x = -srcW/2;pLT.y = srcH/2;
     53     pRT.x = srcW/2;pRT.y = srcH/2;
     54     pLB.x = -srcW/2;pLB.y = -srcH/2;
     55     pRB.x = srcW/2; pRB.y = -srcH/2;
     56     //旋转之后的坐标
     57     POINT pLTN,pRTN,pLBN,pRBN;
     58     double sina = sin(RADIAN(angle));
     59     double cosa = cos(RADIAN(angle));
     60     pLTN.x = pLT.x*cosa + pLT.y*sina;    
     61     pLTN.y = -pLT.x*sina + pLT.y*cosa;
     62     pRTN.x = pRT.x*cosa + pRT.y*sina;
     63     pRTN.y = -pRT.x*sina + pRT.y*cosa;
     64     pLBN.x = pLB.x*cosa + pLB.y*sina;
     65     pLBN.y = -pLB.x*sina + pLB.y*cosa;
     66     pRBN.x = pRB.x*cosa + pRB.y*sina;
     67     pRBN.y = -pRB.x*sina + pRB.y*cosa;
     68     //旋转后图像宽和高
     69     int desWidth = max(abs(pRBN.x - pLTN.x),abs(pRTN.x - pLBN.x));
     70     int desHeight = max(abs(pRBN.y - pLTN.y),abs(pRTN.y - pLBN.y));
     71     //分配旋转后图像的缓存
     72     int desBufSize = ((desWidth * bitCount + 31) / 32) * 4 * desHeight;
     73     BYTE *desBuf = new BYTE[desBufSize];
     74     //将所有像素都预置为白色
     75     memset(desBuf,255,desBufSize);
     76     //新图像每一行字节数,带有偏移量
     77     int desLineSize = ((desWidth * bitCount + 31) / 32) * 4;        
     78     //通过新图像的坐标,计算对应的原图像的坐标
     79     for (i = 0; i < desHeight; i++)
     80     {        
     81         for (j = 0; j < desWidth; j++)
     82         {
     83             //转换到以图像为中心的坐标系,并进行逆旋转
     84             int tX = (j - desWidth / 2)*cos(RADIAN(360 - angle)) + (-i + desHeight / 2)*sin(RADIAN(360 - angle));
     85             int tY = -(j - desWidth / 2)*sin(RADIAN(360 - angle)) + (-i + desHeight / 2)*cos(RADIAN(360 - angle));
     86             //如果这个坐标不在原图像内,则不赋值
     87             if (tX > srcW / 2 || tX < -srcW / 2 || tY > srcH / 2 || tY < -srcH / 2)
     88             {
     89                 continue;
     90             }
     91             //再转换到原坐标系下
     92             int tXN = tX + srcW / 2; int tYN = abs(tY - srcH / 2);
     93             //值拷贝
     94             memcpy(&desBuf[i * desLineSize + j * bitCount / 8],&srcBuf[tYN * lineSize + tXN * bitCount / 8],3);            
     95         }
     96     }
     97 
     98     //创建目标文件
     99     HFILE hfile = _lcreat(desFile.c_str(),0);    
    100     //文件头信息
    101     BITMAPFILEHEADER nbmfHeader;    
    102     nbmfHeader.bfType = 0x4D42;
    103     nbmfHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)
    104         + desWidth * desHeight * bitCount / 8;
    105     nbmfHeader.bfReserved1 = 0;
    106     nbmfHeader.bfReserved2 = 0;
    107     nbmfHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
    108     //Bitmap头信息
    109     BITMAPINFOHEADER   bmi; 
    110     bmi.biSize=sizeof(BITMAPINFOHEADER); 
    111     bmi.biWidth=desWidth; 
    112     bmi.biHeight=desHeight; 
    113     bmi.biPlanes=1; 
    114     bmi.biBitCount=bitCount; 
    115     bmi.biCompression=BI_RGB; 
    116     bmi.biSizeImage=0; 
    117     bmi.biXPelsPerMeter=0; 
    118     bmi.biYPelsPerMeter=0; 
    119     bmi.biClrUsed=0; 
    120     bmi.biClrImportant=0; 
    121     
    122     //写入文件头信息
    123     _lwrite(hfile,(LPCSTR)&nbmfHeader,sizeof(BITMAPFILEHEADER));
    124     //写入Bitmap头信息
    125     _lwrite(hfile,(LPCSTR)&bmi,sizeof(BITMAPINFOHEADER));
    126     //写入图像数据
    127     _lwrite(hfile,(LPCSTR)desBuf,desBufSize);
    128     _lclose(hfile);
    129 }
    130 
    131 int main(int argc, char* argv[])
    132 {
    133     FILE *pFile;
    134     if ((pFile = fopen("e://t.bmp","rb")) == NULL)
    135     {
    136         printf("open bmp file error.");
    137         return -1;
    138     }
    139     string srcFile("e://t.bmp");
    140     string desFile("e://Rotation.bmp");
    141     Rotation(srcFile,desFile,150);
    142     system("pause");
    143     return 0;
    144 }

    测试效果如下,旋转前:


    旋转后:
     

    转自:http://www.cnblogs.com/tingshuo/archive/2011/05/15/2047016.html

  • 相关阅读:
    HDOJ 2095 find your present (2)
    HDOJ 2186 悼念512汶川大地震遇难同胞——一定要记住我爱你
    九度 1337 寻找最长合法括号序列
    九度 1357 疯狂地Jobdu序列
    HDOJ 1280 前m大的数
    九度 1343 城际公路网
    九度 1347 孤岛连通工程
    HDOJ 2151 Worm
    九度 1342 寻找最长合法括号序列II
    九度 1346 会员积分排序
  • 原文地址:https://www.cnblogs.com/zl1991/p/6433848.html
Copyright © 2011-2022 走看看