BMP格式图片的放缩(解决Win10画图软件的GUG)

         绪论

        最近在着手用纯C语言,写一些图像处理的算法,偶然间发现用Win10自带的画图软件按像素点更改几次图片大小后进会出现数据丢失,使得图像变得模糊的问题,这就使我萌生了通过程序来改变图片的大小的想法。

        说干就干,想着我对bmp格式的图片最为了解就从把bmp格式的图片开始吧。经过我一顿猛如虎的操作成功地将代码雏形给敲了出来。来吧展示!

1.图片放缩的逻辑

        众所周知图像数据是由一个个像素点构成的,改变图像的大小无非就是根据一定的算法来改变像素的数量。如何才能改变像素数量还能使图像看起来不失真呢?这一下子好像还真没点思路。经过我三分钟的了解后,瞬间就使我来了灵感,开干!

        要使图像在经过放缩后不失真就必须使得到的新图片上的像素点与原图片上的像素点有一一对应的关系,新图像中的像素点数据要在源图像中找到,下面就列举一种颇为巧妙的方法。

                        \boldsymbol{1:} x' = x'' \div x_{2} \times x_{1} \boldsymbol \rightarrow {2:} y' = y'' \div x_{2} \times y_{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彻底解决图片模糊问题

        笔者在改进图像写入算法后,再次随意更改了十次图片的大小,未出现图像偏移和图像模糊的问题,这标志着此次算法改进圆满完成!

利用新算法改变十次图像大小后的结果

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值