绪论
最近在着手用纯C语言,写一些图像处理的算法,偶然间发现用Win10自带的画图软件按像素点更改几次图片大小后进会出现数据丢失,使得图像变得模糊的问题,这就使我萌生了通过程序来改变图片的大小的想法。
说干就干,想着我对bmp格式的图片最为了解就从把bmp格式的图片开始吧。经过我一顿猛如虎的操作成功地将代码雏形给敲了出来。来吧展示!
1.图片放缩的逻辑
众所周知图像数据是由一个个像素点构成的,改变图像的大小无非就是根据一定的算法来改变像素的数量。如何才能改变像素数量还能使图像看起来不失真呢?这一下子好像还真没点思路。经过我三分钟的了解后,瞬间就使我来了灵感,开干!
要使图像在经过放缩后不失真就必须使得到的新图片上的像素点与原图片上的像素点有一一对应的关系,新图像中的像素点数据要在源图像中找到,下面就列举一种颇为巧妙的方法。
两式中x1、y1表示源图像的宽和高,x2、y2表示目标图像的宽和高。
这样就找到了一种放缩算法的基本原理,下面开始进行代码实现。
dwsrcY = (uint64_t)(((float)i + 0.5) / dstHeight * srcHeight - 0.5);
dwsrcX = (uint64_t)(((float)j + 0.5) / dstWidth * srcWidth - 0.5);
为了使得图片在方所前后图像中心点的相对位置保持不变,因此需要在原始坐标上进行±0.5操作,具体为什么笔者在这里不做赘述。
2.bmp图像的读取与显示
前面我们知道了图像是以像素点的形式保存在二进制文件中的,计算机是通过解析这些数据从而进行相应的显示的。 一个bmp格式的文件由以下几部分组成:1.bmp头文件、2.bmp头信息文件、3.调色板(位深度小于等于8位时才会使用)、4.像素数据。改变bmp图像的大小首先要改变头文件和头信息文件中的相应选项,否则bmp图片无法正常显示。这是一张800 * 480的bmp图片,接下来将使用它来演示缩放效果。
原图
使用win10自带画图软件经过10次更改大小后的图像
2.1 bmp文件行四字节对齐问题
在图片缩放过程中笔者发现当图像宽度为4的整数倍时图片可以正常显示,否则会出现图片倾斜问题。
803 * 480 bmp 读取效果图
不难发现当原图片的宽度不为4的倍数时图片会发生倾斜。我们转换思路将原图宽重新改成800,而将目标图片的宽度改成803看看又会发生什么。
803 * 480 bmp图片保存效果图
可以看出同样发生了倾斜,只是发生倾斜的方向不同。这是什么原因呢?经查阅相关文献得知,这是由于计算机内部数据读取方式造成的。计算机通常为提高工作效率会以四字节为单位进行数据读取,这就导致了在读取宽度不为4的整数倍的图像时会将上一行数据的结尾与下一行数据的开头读到一起,从而发生错误。解决办法就是在每行数据的结尾进项补充操作,将每行的像素数大小变成4的整数倍。
srcRowSize = (((infoHeader.width * infoHeader.bit_count) + 31) / 32) * 4;
在计算大小过程中需要将图像的行字节数进行向上取整,以解决4字节读取问题。
修改后效果图
修改后注意在读取过程中跳过原图形每行末尾的0,而在新图像每行的末尾补充上相应字节数的0.(图像宽度不为4的整数倍时)。
2.2彻底解决图片模糊问题
笔者在改进图像写入算法后,再次随意更改了十次图片的大小,未出现图像偏移和图像模糊的问题,这标志着此次算法改进圆满完成!
利用新算法改变十次图像大小后的结果