图像处理之读取bmp(1/4/8/16/24位)
之前做图像处理作业,要求用read读取bmp,但是网上好像都没有找到能够读取各种位图的python程序。。。实属无奈
首先要获得1bit,4bit,8bit,16bit和24bit的图像。首先用Photoshop打开一张正常的jpg图片,接着在储存中选择bmp格式,分别选择24位和16位,但是1,4,8位无法选择,此时新建一张画布,在创建时选择8位,然后将上述图片导入画布,点击图像-模式-位图,并且按照上述方式为8,4位图像。对于1位的图像,再点击图像-模式-位图然后储存为1位bmp格式图片即可。
分析:对于不同位数的bmp图片的数据构建方式不同,因此对于不同位数的bmp读取应该采用不同的方法。总体上,应当先读取bmp图片前54个字节里面关于文件头和位图信息头的信息。从中提取图片的长宽和图片位数等,然后依据这些信息构建数组,再将每一个像素的信息添加到数组的对应位置中,最后将数组以图片的形式显示,储存。
文件读取
- 读取文件头和位图信息头得到图片的位数bit_num;图片长宽像素值img_width,img_height;像素信息的起始字节位置to_img_data.
- 对于2,4,8位的bmp图像,是有调色板的,其中的信息位于54字节到to_img_data之间,因为bmp数据按照小端的顺序排列,因此读取的调色板信息应当为bgr,alpha的顺序,这里将bgr按顺序填入一个2^bit_num13的数组中,其中每种颜色占四个字节(bgr,alpha各一个)因为透明度都没有设置,因此舍弃alpha部分。
- 对于16和24位的bmp没有调色板,因此构建调色板这一步跳过。通过seek函数,使文件指针跳到to_img_data的位置,对于2,4,8位每个字节分别表示4,2,1个像素,对应的10进制值为调色板的索引值。因为read只能一个个字节地读取,也没找到按位读取的函数,因此自定义函数Breakup_byte,将一个字节按照2,2,2,2;4,4,或8位一个数字的方式返回,这里先将read读取的二进制转为10进制,然后通过bin将该十进制数转为二进制数形式的字符串,通过拆解字符串来达到拆解一个字节的目的。接着利用得到的像素的索引,将对应调色板中的值填入预先设定好的dax大小为(img_height*img_width)名为img_np的array中.
- 对于16位,图片通过2个字节表示rgb的三个值,分别占(555)字节,通过查询资料也有565方式的,但通过测试发现有一个位数在整张图片中都为0,因此推测该位数是不表示信息的。这里自定义了breakup_16byte函数,采用类似breakup_byte函数的方法将两个字节的信息输入得到对应的555的数字信息。由于这里也是小端表示的,因此读入的第二个字节应当放在第一个字节前面,同时表示的顺序也是bgr。将对应的像素值填入img_np中
- 对于24位,每个字节表示rgb中的一个,按照rgb的顺序填入img_np中。
注意事项:
6. 这里注意由于windows扫描都是以4字节为单位的,因此读取每一行的数据时,要是读取的数目不是4的倍数,应当继续读取无用的信息,直到为4的倍数
7. 同时注意bmp像素信息是从左到右,从下到上的。
实验过程中的问题:
8. 在进行16位bmp读取的时候发现图片整体偏暗,经过思考,每一位最大为2^5=32,无法达到最大的255值,这里应该是通过某种方式进行了归一化,通过多次测试,发现将每一个rgb数值*9是一个较为合理的值(这里查阅资料也没看到是要如何处理)
图像直方图显示:
Python中使用matplotlib的hist函数,对于灰度的bmp(2,4,8),直接读取像素的值,然后将该array展开,然后传到hist函数中。对于三个通道的bmp(16,24位),将每一个通道的array展开并显示,然后用不同的颜色在图像中显示出来。
保存为txt:
将图片像素保存到txt文件中,由于numpy中的savetxt只能保存一维或者二维的数组,因此用reshape将img_np展开,将g和b通道的值保存在r通道所有值的下放,即展开为img_height*3,img_width的尺寸
python实现
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
import os
from struct import unpack
def byte_to_int(str1):
#从一个str类型的byte到int
result=0
for i in range(len(str1)):
y=int(str1[len(str1)-1-i])
result+=y*2**i
return result
# 具体详见代码和文件详见资源页
结果
1位
8位
16位
24位