C/C++ BMP(24位真彩色)图像处理(4)------图像の旋转
来源:互联网 发布:如何自学成为程序员 编辑:程序博客网 时间:2024/06/05 18:57
历经一个多月,CSDN貌似终于好像把文章列表阅读量信息归零BUG给修好了,于是乎放篇做期末大作业时写的文章上来测测效果,可别又像上次一样一发文章就又坑爹了啊!
本篇谈的是图像的旋转,不算是什么新鲜的题目了。但是现在由于很多工具如MATLAB、OpenCV等都把算法写好给用户调用,导致大多用户只知其然不知其所以然,所以回顾一下也是好的。
图像的旋转,说到底就是每个像素点绕着某个圆心旋转一定角度。如果是写代码的话,旋转的角度和圆心应该是已知的条件,我们第一个思路是根据已知条件求取出图像经过旋转后的新的像素点的坐标。这个思路显然是没有错的,然而有个问题就是旋转之后的图像有些像素点已经被转出到图像的大小之外,而另外有一些像素点无法跟原图像相对应。这就使得顺着这样一个思路编程变得复杂。因而我们反过来想,不如先将旋转后的图像规划好,然后通过一个方法去计算新图像每个像素点是否对应于原图像的像素点,如果对应那么该像素点处于原图像的什么位置,如果不对应那该像素点又该取值多少。通过这个方法我们遍历新图像的所有像素点则可得到旋转后的图像。
OK,上面我们已经将图像旋转的思路理清了。现在我们还不知道的就是图像旋转前后的像素点对应关系。这个关系稍微复杂一点,本人参考了这个博客的计算方法,下面进行推导或者说重现。
请看上图,经过上面的推导,我们是要从x’,y’去得到x,y的。这也就是说我们最终要得到的形式是:
x=f(x’,y’)
y=g(x’,y’)
这样子的。OK,计算公式推导如下(用word编写的,风格略不同。。。):
OK,理论工作做完了,接下来就是编程了,需要注意的是由于旋转后图像的点对应于旋转前图像的点的位置基本上不大可能是正对着的,所以需要用到双线性插值(该理论的具体分析在上一篇文章详细提到)。
主要代码如下:
- /*******************图像旋转******************/
- int centerofrotation_x = MYDRAW_WIDTH / 2;//旋转中心x坐标
- int centerofrotation_y = MYDRAW_HEIGHT / 2;//旋转中心y坐标
- double degree = 60;//逆时针旋转角度
- double radian = degree / 180 * pi;//角度转弧度
- for (int hnum = 0; hnum < MYDRAW_HEIGHT; hnum++)
- for (int wnum = 0; wnum < MYDRAW_WIDTH; wnum++)
- {
- int pixel_point = hnum*write_width + wnum * 3;//映射尺度变换图像数组位置偏移量
- double d_original_img_wnum = (wnum - centerofrotation_x)*cos(radian) - (hnum - centerofrotation_y)*sin(radian) + centerofrotation_x;
- double d_original_img_hnum = (wnum - centerofrotation_x)*sin(radian) + (hnum - centerofrotation_y)*cos(radian) + centerofrotation_y;
- if (d_original_img_wnum<0 || d_original_img_wnum>width || d_original_img_hnum<0 || d_original_img_hnum>height)//找不到与原图像的对于关系
- {
- pColorDataMid[pixel_point] = pColorDataMid[pixel_point + 1] = pColorDataMid[pixel_point + 2] = 0;
- continue;
- }
- int i_original_img_hnum = d_original_img_hnum;
- int i_original_img_wnum = d_original_img_wnum;
- double distance_to_a_x = d_original_img_wnum - i_original_img_wnum;//在原图像中与a点的水平距离
- double distance_to_a_y = d_original_img_hnum - i_original_img_hnum;//在原图像中与a点的垂直距离
- int original_point_a = i_original_img_hnum*l_width + i_original_img_wnum * 3;//数组位置偏移量,对应于图像的各像素点RGB的起点,相当于点A
- int original_point_b = i_original_img_hnum*l_width + (i_original_img_wnum + 1) * 3;//数组位置偏移量,对应于图像的各像素点RGB的起点,相当于点B
- int original_point_c = (i_original_img_hnum + 1)*l_width + i_original_img_wnum * 3;//数组位置偏移量,对应于图像的各像素点RGB的起点,相当于点C
- int original_point_d = (i_original_img_hnum + 1)*l_width + (i_original_img_wnum + 1) * 3;//数组位置偏移量,对应于图像的各像素点RGB的起点,相当于点D
- if (i_original_img_hnum == MYDRAW_HEIGHT - 1)
- {
- original_point_c = original_point_a;
- original_point_d = original_point_b;
- }
- if (i_original_img_wnum == MYDRAW_WIDTH - 1)
- {
- original_point_a = original_point_b;
- original_point_c = original_point_d;
- }
- pColorDataMid[pixel_point] =
- pColorData[original_point_a] * (1 - distance_to_a_x)*(1 - distance_to_a_y) +
- pColorData[original_point_b] * distance_to_a_x*(1 - distance_to_a_y) +
- pColorData[original_point_c] * distance_to_a_y*(1 - distance_to_a_x) +
- pColorData[original_point_c] * distance_to_a_y*distance_to_a_x;
- pColorDataMid[pixel_point + 1] =
- pColorData[original_point_a + 1] * (1 - distance_to_a_x)*(1 - distance_to_a_y) +
- pColorData[original_point_b + 1] * distance_to_a_x*(1 - distance_to_a_y) +
- pColorData[original_point_c + 1] * distance_to_a_y*(1 - distance_to_a_x) +
- pColorData[original_point_c + 1] * distance_to_a_y*distance_to_a_x;
- pColorDataMid[pixel_point + 2] =
- pColorData[original_point_a + 2] * (1 - distance_to_a_x)*(1 - distance_to_a_y) +
- pColorData[original_point_b + 2] * distance_to_a_x*(1 - distance_to_a_y) +
- pColorData[original_point_c + 2] * distance_to_a_y*(1 - distance_to_a_x) +
- pColorData[original_point_c + 2] * distance_to_a_y*distance_to_a_x;
- }
- /*******************图像旋转******************/
- #include <string.h>
- #include <math.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <malloc.h>
- #include<time.h>//时间相关头文件,可用其中函数计算图像处理速度
- #define WIDTHBYTES(bits) (((bits)+31)/32*4)//用于使图像宽度所占字节数为4byte的倍数
- #define MYDRAW_HEIGHT 1054 //目标图像高度
- #define MYDRAW_WIDTH 1500 //目标图像宽度
- #define pi 3.1415926535
- typedef unsigned char BYTE;
- typedef unsigned short WORD;
- typedef unsigned long DWORD;
- typedef long LONG;
- //位图文件头信息结构定义
- //其中不包含文件类型信息(由于结构体的内存结构决定,要是加了的话将不能正确读取文件信息)
- typedef struct tagBITMAPFILEHEADER {
- DWORD bfSize; //文件大小
- WORD bfReserved1; //保留字,不考虑
- WORD bfReserved2; //保留字,同上
- DWORD bfOffBits; //实际位图数据的偏移字节数,即前三个部分长度之和
- } BITMAPFILEHEADER;
- //信息头BITMAPINFOHEADER,也是一个结构,其定义如下:
- typedef struct tagBITMAPINFOHEADER{
- //public:
- DWORD biSize; //指定此结构体的长度,为40
- LONG biWidth; //位图宽
- LONG biHeight; //位图高
- WORD biPlanes; //平面数,为1
- WORD biBitCount; //采用颜色位数,可以是1,2,4,8,16,24,新的可以是32
- DWORD biCompression; //压缩方式,可以是0,1,2,其中0表示不压缩
- DWORD biSizeImage; //实际位图数据占用的字节数
- LONG biXPelsPerMeter; //X方向分辨率
- LONG biYPelsPerMeter; //Y方向分辨率
- DWORD biClrUsed; //使用的颜色数,如果为0,则表示默认值(2^颜色位数)
- DWORD biClrImportant; //重要颜色数,如果为0,则表示所有颜色都是重要的
- } BITMAPINFOHEADER;
- void main()
- {
- long now = 0;
- now = clock();//存储图像处理开始时间
- BITMAPFILEHEADER bitHead, writebitHead;
- BITMAPINFOHEADER bitInfoHead, writebitInfoHead;
- FILE* pfile;//输入文件
- FILE* wfile;//输出文件
- char strFile[50] = "15.bmp";//打开图像路径,BMP图像必须为24位真彩色格式
- char strFilesave[50] = "16.bmp";//处理后图像存储路径
- fopen_s(&pfile, strFile, "rb");//文件打开图像
- fopen_s(&wfile, strFilesave, "wb");//打开文件为存储修改后图像做准备
- //读取位图文件头信息
- WORD fileType;
- fread(&fileType, 1, sizeof(WORD), pfile);
- fwrite(&fileType, 1, sizeof(WORD), wfile);
- if (fileType != 0x4d42)
- {
- printf("file is not .bmp file!");
- return;
- }
- //读取位图文件头信息
- fread(&bitHead, 1, sizeof(tagBITMAPFILEHEADER), pfile);
- writebitHead = bitHead;//由于截取图像头和源文件头相似,所以先将源文件头数据赋予截取文件头
- //读取位图信息头信息
- fread(&bitInfoHead, 1, sizeof(BITMAPINFOHEADER), pfile);
- writebitInfoHead = bitInfoHead;//同位图文件头相似
- writebitInfoHead.biHeight = MYDRAW_HEIGHT;//为截取文件重写位图高度
- writebitInfoHead.biWidth = MYDRAW_WIDTH;//为截取文件重写位图宽度
- int mywritewidth = WIDTHBYTES(writebitInfoHead.biWidth*writebitInfoHead.biBitCount);//BMP图像实际位图数据区的宽度为4byte的倍数,在此计算实际数据区宽度
- writebitInfoHead.biSizeImage = mywritewidth*writebitInfoHead.biHeight;//计算位图实际数据区大小
- writebitHead.bfSize = 54 + writebitInfoHead.biSizeImage;//位图文件头大小为位图数据区大小加上54byte
- fwrite(&writebitHead, 1, sizeof(tagBITMAPFILEHEADER), wfile);//写回位图文件头信息到输出文件
- fwrite(&writebitInfoHead, 1, sizeof(BITMAPINFOHEADER), wfile);//写回位图信息头信息到输出文件
- int width = bitInfoHead.biWidth;
- int height = bitInfoHead.biHeight;
- //分配内存空间把源图存入内存
- int l_width = WIDTHBYTES(width*bitInfoHead.biBitCount);//计算位图的实际宽度并确保它为4byte的倍数
- int write_width = WIDTHBYTES(writebitInfoHead.biWidth*writebitInfoHead.biBitCount);//计算写位图的实际宽度并确保它为4byte的倍数
- BYTE *pColorData = (BYTE *)malloc(height*l_width);//开辟内存空间存储图像数据
- memset(pColorData, 0, height*l_width);
- BYTE *pColorDataMid = (BYTE *)malloc(mywritewidth*MYDRAW_HEIGHT);//开辟内存空间存储图像处理之后数据
- memset(pColorDataMid, 0, mywritewidth*MYDRAW_HEIGHT);
- long nData = height*l_width;
- long write_nData = mywritewidth*MYDRAW_HEIGHT;//截取的位图数据区长度定义
- //把位图数据信息读到数组里
- fread(pColorData, 1, nData, pfile);//图像处理可通过操作这部分数据加以实现
- /*******************图像处理部分******************/
- /*******************图像旋转******************/
- int centerofrotation_x = MYDRAW_WIDTH / 2;//旋转中心x坐标
- int centerofrotation_y = MYDRAW_HEIGHT / 2;//旋转中心y坐标
- double degree = 60;//逆时针旋转角度
- double radian = degree / 180 * pi;//角度转弧度
- for (int hnum = 0; hnum < MYDRAW_HEIGHT; hnum++)
- for (int wnum = 0; wnum < MYDRAW_WIDTH; wnum++)
- {
- int pixel_point = hnum*write_width + wnum * 3;//映射尺度变换图像数组位置偏移量
- double d_original_img_wnum = (wnum - centerofrotation_x)*cos(radian) - (hnum - centerofrotation_y)*sin(radian) + centerofrotation_x;
- double d_original_img_hnum = (wnum - centerofrotation_x)*sin(radian) + (hnum - centerofrotation_y)*cos(radian) + centerofrotation_y;
- if (d_original_img_wnum<0 || d_original_img_wnum>width || d_original_img_hnum<0 || d_original_img_hnum>height)//找不到与原图像的对于关系
- {
- pColorDataMid[pixel_point] = pColorDataMid[pixel_point + 1] = pColorDataMid[pixel_point + 2] = 0;
- continue;
- }
- int i_original_img_hnum = d_original_img_hnum;
- int i_original_img_wnum = d_original_img_wnum;
- double distance_to_a_x = d_original_img_wnum - i_original_img_wnum;//在原图像中与a点的水平距离
- double distance_to_a_y = d_original_img_hnum - i_original_img_hnum;//在原图像中与a点的垂直距离
- int original_point_a = i_original_img_hnum*l_width + i_original_img_wnum * 3;//数组位置偏移量,对应于图像的各像素点RGB的起点,相当于点A
- int original_point_b = i_original_img_hnum*l_width + (i_original_img_wnum + 1) * 3;//数组位置偏移量,对应于图像的各像素点RGB的起点,相当于点B
- int original_point_c = (i_original_img_hnum + 1)*l_width + i_original_img_wnum * 3;//数组位置偏移量,对应于图像的各像素点RGB的起点,相当于点C
- int original_point_d = (i_original_img_hnum + 1)*l_width + (i_original_img_wnum + 1) * 3;//数组位置偏移量,对应于图像的各像素点RGB的起点,相当于点D
- if (i_original_img_hnum == MYDRAW_HEIGHT - 1)
- {
- original_point_c = original_point_a;
- original_point_d = original_point_b;
- }
- if (i_original_img_wnum == MYDRAW_WIDTH - 1)
- {
- original_point_a = original_point_b;
- original_point_c = original_point_d;
- }
- pColorDataMid[pixel_point] =
- pColorData[original_point_a] * (1 - distance_to_a_x)*(1 - distance_to_a_y) +
- pColorData[original_point_b] * distance_to_a_x*(1 - distance_to_a_y) +
- pColorData[original_point_c] * distance_to_a_y*(1 - distance_to_a_x) +
- pColorData[original_point_c] * distance_to_a_y*distance_to_a_x;
- pColorDataMid[pixel_point + 1] =
- pColorData[original_point_a + 1] * (1 - distance_to_a_x)*(1 - distance_to_a_y) +
- pColorData[original_point_b + 1] * distance_to_a_x*(1 - distance_to_a_y) +
- pColorData[original_point_c + 1] * distance_to_a_y*(1 - distance_to_a_x) +
- pColorData[original_point_c + 1] * distance_to_a_y*distance_to_a_x;
- pColorDataMid[pixel_point + 2] =
- pColorData[original_point_a + 2] * (1 - distance_to_a_x)*(1 - distance_to_a_y) +
- pColorData[original_point_b + 2] * distance_to_a_x*(1 - distance_to_a_y) +
- pColorData[original_point_c + 2] * distance_to_a_y*(1 - distance_to_a_x) +
- pColorData[original_point_c + 2] * distance_to_a_y*distance_to_a_x;
- }
- /*******************图像旋转******************/
- /*******************图像处理部分******************/
- fwrite(pColorDataMid, 1, write_nData, wfile); //将处理完图像数据区写回文件
- fclose(pfile);
- fclose(wfile);
- printf("图像处理完成\n");
- printf("运行时间为:%dms\n", int(((double)(clock() - now)) / CLOCKS_PER_SEC * 1000));//输出图像处理花费时间信息
- }
原图像
旋转后图像
- C/C++ BMP(24位真彩色)图像处理(4)------图像の旋转
- C/C++ BMP(24位真彩色)图像处理(4)------图像の旋转
- C/C++ BMP(24位真彩色)图像处理(2)------图像の截取
- C/C++ BMP(24位真彩色)图像处理(5)------图像の线性变换
- C/C++ BMP(24位真彩色)图像处理(2)------图像の截取
- C/C++ BMP(24位真彩色)图像处理(5)------图像の线性变换
- C/C++ BMP(24位真彩色)图像处理(1)------图像の打开与数据区处理
- C/C++ BMP(24位真彩色)图像处理(1)------图像の打开与数据区处理
- C/C++ BMP(24位真彩色)图像处理(3)------图像の放大缩小(双线性插值)
- C/C++ BMP(24位真彩色)图像处理(3)------图像の放大缩小(双线性插值)
- BMP--24位真彩色转换为灰度图像
- C# 图像 24位转32位(真彩色)
- 【数字图像处理】<纯C++>读取、裁剪、缩放、旋转和存储8位bmp灰度图像
- 【数字图像处理】<纯C++>读取、裁剪、缩放、旋转和存储8位bmp灰度图像
- BMP图像的处理(24位转16位)
- C语言处理BMP图像
- 8叉数算法处理将24位真彩色变为8位伪彩色图像
- 24位真彩色图像转8位灰度图像
- java炒冷饭系列08 try-with-resources
- MySQL自定义函数用法详解
- Mac电脑如何查看CPU、操作系统和内存
- python 最大值
- java的日期类
- C/C++ BMP(24位真彩色)图像处理(4)------图像の旋转
- 序
- TCP中的四种定时器
- 两种多线程查库写法
- spring初次搭建碰到问题 Caused by: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 7; 不允许有匹配 "[xX
- 微信支付银行卡交易的限额是多少?
- Java实现爬虫给App提供数据(Jsoup 网络爬虫)
- 170620 How to install tensorflow with GPU on linux
- Learning to Rank(LTR)