实验4.1python实现BMP⽂件8位转24位
⽂章⽬录
BMP图像⽂件格式
BMP⽂件简介
BMP(全称 Bitmap)是 Windows 操作系统中的标准图像⽂件格式,可以分成两类:设备相关位图(DDB)和设备⽆关位图(DIB),使⽤⼴泛。它采⽤位映射存储格式,除了图像深度可选以外,在绝⼤多数应⽤中不采⽤其他任何压缩,因此,BMP ⽂件所占⽤的空间很⼤。
BMP ⽂件的图像深度可选 1bit、4bit、8bit、16bit 及 24bit。BMP ⽂件存储数据时,图像的扫描⽅式是按从左到右、从下到上的顺序。
由于 BMP ⽂件格式是 Windows 环境中交换与图有关的数据的⼀种标准,因此在 Windows 环境中运⾏的图形图像软件都⽀持 BMP 图像格式。
BMP⽂件组成结构
典型的 BMP 图像⽂件由四部分组成:
(1)位图头⽂件数据结构,它包含 BMP 图像⽂件的类型、显⽰内容等信息;
(2)位图信息数据结构,它包含有 BMP 图像的宽、⾼、压缩⽅法,以及定义颜⾊等信息;
(3)调⾊板,这个部分是可选的,有些位图需要调⾊板,有些位图,⽐如真彩⾊图(24位的 BMP)就不需要调⾊板;
(4)位图数据,这部分的内容根据 BMP 位图使⽤的位数不同⽽不同,在 24 位图中直接使⽤ RGB,⽽其他的⼩于 24 位的使⽤调⾊板中颜⾊索引值。
相应的数据结构可表⽰如下:
位图⽂件头
该部分⼀共有14个字节。可以提供⽂件的格式、⼤⼩等信息
typedef struct tagBITMAPFILEHEADER
{
新生儿喝什么奶粉好UINT16 bfType; // 说明位图类型 2字节
DWORD bfSize; // 说明位图⼤⼩ 4字节
UINT16 bfRerved1; // 保留字,必须为0 2字节
UINT16 bfRerved2; // 保留字,必须为0 2字节
DWORD bfOffBits; // 从⽂件头到实际的图像数据的偏移量是多少 4字节
} BITMAPFILEHEADER; //⼀共14个字节
位图信息头主要包括:
typedef struct tagBITMAPINFOHEADER {
DWORD biSize; /* 说明结构体所需字节数 */ 4字节
LONG biWidth; /* 以像素为单位说明图像的宽度 */ 4字节
LONG biHeight; /* 以像素为单位说明图像的⾼速 */ 4字节
WORD biPlanes; /* 说明位⾯数,必须为 1 */ 2字节
WORD biBitCount; /* 说明位数/像素,1、2、4、8、24 */ 2字节
DWORD biCompression; /* 说明图像是否压缩及压缩类型*/ 4字节
DWORD biSizeImage; /* 以字节为单位说明图像⼤⼩,必须是 4 的整数倍*/ 4字节
LONG biXPelsPerMeter; /*⽬标设备的⽔平分辨率,像素/⽶ */ 4字节
LONG biYPelsPerMeter; /*⽬标设备的垂直分辨率,像素/⽶ */ 4字节
DWORD biClrUd; /* 说明图像实际⽤到的颜⾊数,如果为 0,则颜⾊数为 2 的 biBitCount次⽅ */ 4字节
DWORD biClrImportant; /*说明对图像显⽰有重要影响的颜⾊索引的数⽬,如果是 0,表⽰都重要。*/ 4字节
} BITMAPINFOHEADER;// ⼀共**40个**字节
作为真彩⾊位图,我们主要关⼼的是biWidth和biHeight这两个数值,两个数值告诉我们图像的尺⼨。biSize,biPlanes,biBitCount这⼏个数值是固定的
调⾊板实际上是⼀个数组,它所包含的元素与位图所具有的颜⾊数相同,决定于
biClrUd 和 biBitCount 字段。数组中每个元素的类型是⼀个 RGBQUAD 结构。真彩⾊⽆调⾊板部分。
typedef struct tagRGBQUAD {
BYTE rgbBlue; /*指定蓝⾊分量*/
BYTE rgbGreen; /*指定绿⾊分量*/
BYTE rgbRed; /*指定红⾊分量*/
BYTE rgbRerved; /*保留,指定为 0*/
} RGBQUAD;
紧跟在调⾊板之后的是图像数据字节阵列。对于⽤到调⾊板的位图,图像数据就是该像素颜⾊在调⾊板中的索引值(逻辑⾊)。对于真彩⾊图,图像数据就是实际的 R、G、B值。图像的每⼀扫描⾏由表⽰图像像素的连续的字节组成,每⼀⾏的字节数取决于图像的颜⾊数⽬和⽤像素表⽰的图像宽度。规定每⼀扫描⾏的字节数必须是 4 的整倍数,也就是DWORD 对齐的。
扫描⾏是由底向上存储的,这就是说,阵列中的第⼀个字节表⽰位图左下⾓的像素,⽽最后⼀个字节表⽰位图右上⾓的像素。
BMP⽂件字节序
不同的计算机系统采⽤不同的字节序存储数据,同样⼀个 4 字节的 32 位整数,在内存中存储的⽅式不同。字节序分为⼩尾字节序(Little Endian)和⼤尾字节序(Big Endian)。
⼩尾就是低位字节排放在内存的低端,⾼位字节排放在内存的⾼端,即所谓的“低位在前,⾼位在后”。⼤尾就是⾼位字节排放在内存的低端,低位字节排放在内存的⾼端,即所谓的“⾼位在前,低位在后”。
在实现 BMP ⽂件头信息的写⼊和读出时,需要注意整数保存时的字节序。
如图,实验所⽤⽂件⼤⼩是以 Intel 序保存的,低位在前,⾼位在后。
高高的白杨需要注意的是,Windows系统中有“补零”的习惯!即要求位图的每⼀⾏像素所占字节数必须被4整除。若不能倍4整除,则在该位图每⼀⾏的⼗六进制码末尾“补”1⾄3个字节的“00”。
世界上第一枚邮票实验内容
不同像素深度的BMP⽂件互转
(1)在图像处理软件中⾃⾏⽣成多种像素深度的BMP⽂件,要求带含有班级、学号后四位和本⼈姓名(缩写或昵称均可)的logo。(基本要求为8bit和24bit BMP⽂件的互转,进阶要求为其它像素深度和24bit BMP⽂件的互转。)
(2)编写程序实现不同像素深度BMP⽂件的互转。重点掌握函数定义、缓冲区分配、倒序读写、结构体的操作。
(3)调试程序,并验证程序的正确性。
实验⽂件·
实验步骤
导⼊库
import numpy as np #装像素数据和颜⾊表
import struct #进⾏字节转换
import matplotlib.pyplot as plt #显⽰最终的图⽚
from PIL import Image #保存图⽚
打开BMP⽂件并获取⽂件的基本信息
木偶奇遇记简介def main(InFileName,OutFileName):
'先将位图打开'
f=open(InFileName,'rb')#打开对应的⽂件
'下⾯部分⽤来读取BMP位图的基础信息'
f_type=ad(2))#这个就可以⽤来读取⽂件类型需要读取2个字节
file_size_ad(4)# 这个可以⽤来读取⽂件的⼤⼩需要读取4个字节
f.ll()+4)# 跳过中间⽆⽤的四个字节
file_oft_ad(4)# 读取位图数据的偏移量
f.ll()+4)# 跳过⽆⽤的四个字节
file_wide_ad(4)#读取宽度字节
file_height_ad(4)#读取⾼度字节
f.ll()+2)## 跳过中间⽆⽤的两个字节
file_bitcount_ad(4)#得到每个像素占位⼤⼩
#下⾯就是将读取的字节转换成指定的类型
f_size,=struct.unpack('l',file_size_byte)
f_oft,=struct.unpack('l',file_oft_byte)
f_wide,=struct.unpack('l',file_wide_byte)
f_height,=struct.unpack('l',file_height_byte)
f_bitcount,=struct.unpack('i',file_bitcount_byte)
print("类型:",f_type,"⼤⼩:",f_size,"位图数据偏移量:",f_oft,"宽度:",f_wide,"⾼度:",f_height,"位图:",f_bitcount)
读取调⾊版
共青团团章'然后来读取调⾊版'
color_pty(shape=[256,3],dtype=int)
f.ek(54)#跳过⽂件信息头和位图信息头
for i in range(0,256):
b=struct.unpack('B',f.read(1))[0];
g = struct.unpack('B', f.read(1))[0];
r = struct.unpack('B', f.read(1))[0];
alpha = struct.unpack('B', f.read(1))[0];
color_table[i][0]=r
color_table[i][1]=g
color_table[i][2]=b
# color_table[i][3]=255
# print(color_table)
获得BMP⽂件字节序
'下⾯部分⽤来读取BMP位图数据区域,将数据存⼊numpy数组'
地骨皮的功效与作用#⾸先对⽂件指针进⾏偏移⾄数据处
f.ek(f_oft)
#因为图像是8位伪彩⾊图像,所以⼀个像素点占⼀个字节,即8位
pty(shape=[f_height,f_wide,3],dtype=int)
# print(img)
皮蛋豆腐cout = 0
for y in range(0, f_height):
for x in range(0,f_wide):
cout=cout+1
index=struct.unpack('B',f.read(1))[0]
img[f_height-y-1,x]=color_table[index]
while cout %4 !=0:
cout=cout+1
⽣成图⽚并转换为BMP24位
plt.imshow(img)
plt.show()
f.clo()
#将元素类型更改为'uint8'
out=np.array(img,dtype='uint8')
out=Image.fromarray(out)
#第⼀个参数为存储的地址和名称,第⼆个参数为存储的图⽚类型
out.save(OutFileName,'bmp')
将5幅图⽚全部转为24位BMP格式
if __name__ =='__main__':
main("1.bmp","out_1.bmp")
main("2.bmp","out_2.bmp")
main("3.bmp","out_3.bmp")
main("4.bmp","out_4.bmp")
main("5.bmp","out_5.bmp")
总结
1.要注意数据的格式转换,*Intel 序转换为数值型
吃海参好处2.读取调⾊板时要注意去掉第4个通道alpha的值,否则会⽣成32bit的bmp⽂件,⽽不是24bit
3.要注意⽂件读取位置,先赋值给最后⼀⾏。