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

  • 相关阅读:
    设计模式--工厂模式
    docker
    学习的网址
    showslow小记
    .Net学习线路图
    《掌握软件测试九大技术》
    Apache和Tomcat
    Visual Studio 2017 更新到15.3后 提示错误:包含了重复的“Compile”项 的解决方法
    Asp.Net Core MVC项目实现多语言(Globalization/Localization)
    7月23日 会议纪要(项目有重要变动)
  • 原文地址:https://www.cnblogs.com/zl1991/p/6433848.html
Copyright © 2011-2022 走看看