首页 > 其他分享 >Bmp图像原理与应用

Bmp图像原理与应用

时间:2024-05-24 21:08:03浏览次数:26  
标签:int 图像 bmp unsigned width Bmp BMP 原理

BMP图像原理与应用

简介

BMP(Bitmap)是一种常见的位图图像文件格式,它使用像素点阵列来表示图像。BMP文件通常以.bmp为扩展名。

BMP格式最大的特征是没有任何的压缩,因此文件尺寸比较大,不适合网络传输,但是优点是这种图像格式中的数据读取出来不需要任何解码器解码就可以直接使用,所以为了便于大家对图像格式进行了解,就先以BMP格式进行讲解。

image-20240524124457607

文件结构

BMP文件由文件头、信息头和图像数据组成。

文件头(File Header)

BMP文件的文件头长度为14个字节,包含文件类型、大小和图像数据的偏移量等信息。

字段 长度 (字节) 描述
文件类型 2 文件类型标识,一般为"BM"
文件大小 4 整个BMP文件的大小
保留字段1 2 保留字段,一般为0
保留字段2 2 保留字段,一般为0
数据偏移量 4 图像数据相对于文件头的偏移量

信息头(Bitmap Information Header)

BMP文件的信息头长度为40个字节,包含图像的宽度、高度、颜色平面数、比特数等信息。

根据OS的不同,长度也会有所不同,Windows and OS/2 bitmap headers

具体长度可查询[https://en.wikipedia.org/wiki/BMP_file_format]

字段 长度 (字节) 描述
头大小 4 信息头的长度,一般为40
图像宽度 4 图像的宽度(以像素为单位)
图像高度 4 图像的高度(以像素为单位)
颜色平面数 2 颜色平面数,一般为1
比特数 2 每个像素的位数,常见的值为1、4、8、16、24、32
压缩方式 4 图像压缩方式,常见的值为0(不压缩)
图像大小 4 图像的大小(字节为单位),可以为0
水平分辨率 4 每米像素数,一般为0
垂直分辨率 4 每米像素数,一般为0
颜色索引数 4 使用的颜色索引数,如果为0则表示使用所有可能的颜色索引

图像数据

图像数据紧随信息头之后,按照从左到右、自下而上的顺序存储每个像素的颜色信息。根据比特数的不同,每个像素的颜色信息可能占用不同的字节数。 注意存储颜色分量的存储顺序,因为是小端存储,3 个字节的数据(蓝、绿、红)-->BGR。显示时要注意转换。

出于文件存储目的,只有每行的大小必须是 4 字节的倍数,而文件偏移量可以是任意的。

存储一行像素所需的总字节数可以按以下方式计算:

image-20240524125329726

int width_th=(width*24/8)+((4-(width*24/8)%4)%4);

示例

以下是一个简单的BMP文件的文件头示例:

文件类型: BM
文件大小: 300
保留字段1: 0
保留字段2: 0
数据偏移量: 54

以下是一个简单的BMP文件的信息头示例:

头大小: 40
图像宽度: 100
图像高度: 100
颜色平面数: 1
比特数: 24
压缩方式: 0
图像大小: 0
水平分辨率: 0
垂直分辨率: 0
颜色索引数: 0
#pragma pack(1) //字节对齐
typedef struct BITMAPFILEHEADER /* size: 14 */
{
   unsigned short bfType;	// 文件的类型,该值必需是0x4D42,也就是字符'BM'。
   unsigned int  bfSize;	// 位图文件的大小,用字节为单位
   unsigned short bfReserved1;// 保留,必须设置为0
   unsigned short bfReserved2;// 保留,必须设置为0
   unsigned int  bfOffBits;// 位图数据距离文件开头偏移量,用字节为单位
} BMPFILEHEADER;

  
typedef struct BITMAPINFOHEADER  /* size: 40 */
{
   unsigned int  biSize;			// BITMAPINFOHEADER结构所需要的字数
   unsigned int  Width;				// 图像宽度,单位为像素
   unsigned int  Height;			// 图像高度,单位为像素,负数,则说明图像是正向的
   unsigned short biPlanes;			// 为目标设备说明位面数,其值将总是被设为1
   unsigned short biBitCount;		// 一个像素占用的bit位,值位1、4、8、16、24、32
   unsigned int  biCompression;		// 压缩类型
   unsigned int  biSizeImage;		// 位图数据的大小,以字节为单位
   unsigned int  biXPelsPerMeter;	// 水平分辨率,单位 像素/米
   unsigned int  biYPelsPerMeter;	// 垂直分辨率,单位 像素/米
   unsigned int  biClrUsed;			// 当该字段设置为 0 时,颜色表中的颜色数量基于 biBitCount 字段(1 表示 2 种颜色,4 表示 16 种,8 表示 256 种,24 表示无颜色表)。
   unsigned int  biClrImportant;	// 指定颜色表的前 x 颜色对 DIB 很重要。如果其余颜色不可用,图像仍然以可接受的方式保留其含义。 
} BMPINFOHEADER;
#pragma pack() //取消字节对齐

BMP图片数据结构信息

使用HexWorkshop HexEditor(x64)打开bmp文件查看数据信息,方便运行调试

image-20240512224420993

代码练习

显示一张BMP格式的图片在LCD任意位置上

设计程序,实现在LCD上显示一张分辨率为800*480大小的24bit的bmp图片,要求图像不失真可以在开发板的LCD上显示。

int ShowBmp(int x,int y,int*lcd_mp)
{

	//1.打开待显示的BMP图像  fopen
	FILE * bmp_sss = fopen("10.bmp","rb");
	if (NULL == bmp_sss)
	{
		return -1;
	}
	//2.读取BMP文件的图像信息,获取BMP的宽和高
	BITMAPINFOHEADER headerinfosss;
	fseek(bmp_sss,14,SEEK_SET);
	fread(&headerinfosss,1,40,bmp_sss); //读取40字节
	printf("bmp width = %d,height = %d biSizeImage=%d\n",headerinfosss.biWidth,headerinfosss.biHeight);

	int width=headerinfosss.biWidth;
	int height=headerinfosss.biHeight;

	int width_th=(width*24/8)+((4-(width*24/8)%4)%4);
	int th=((4-(width*24/8)%4)%4);
	//3.读取BMP图*片的颜色分量  
	//char bmp_buf[(378*3+2)*306] = {0};
	char bmp_buf[width_th*height*3];
	fread(bmp_buf,1,width_th*height*3,bmp_sss);

	printf("读取图片颜色分量成功");
	//4.关闭BMP
	fclose(bmp_sss);


	//5.循环的把BMP图像的颜色分量依次写入到LCD的像素点中 
	int i = 0;
	int data = 0;

	for (int h = height; h > 0; h--)   //BMP文件的存储方式自下而上的
	{
		
		for (int hx =0; hx < width ; ++hx)   //从左到右
		{
			
			//把BMP图片的一个像素点的颜色分量转换为LCD屏幕的一个像素点的颜色分量格式  ARGB <--- BGR
			data |= bmp_buf[i];			//B
			data |= bmp_buf[i+1]<<8;	//G
			data |= bmp_buf[i+2]<<16;  	//R

			lcd_mp[(h+y-1)*800+hx+x] = data;  //RGB RGB RGB ....    //

			i+=3;  
			data = 0;
		}
		i+=th;    //字节补齐
		printf("i=%d\n",i);
	}
	return 0;

}

缩放BMP图片为原来的二分之一

设计算法,要求把一张任意尺寸的BMP图片等比例且不失真的缩小为原来的1/2,并生成一张新的BMP图片,要求BMP图片的路径都需要通过命令行进行传递

int ZoomBmp()
{
	//1.打开待显示的BMP图像  fopen
	FILE * bmp_fp = fopen("10.bmp","rb");
	if (NULL == bmp_fp)
	{
		return -1;
	}

	//2.读取BMP文件的图像信息,获取BMP的宽和高
	BITMAPFILEHEADER fileinfo;
	BITMAPINFOHEADER headerinfo;
	fread(&fileinfo,14,1,bmp_fp); //读取14字节
	fread(&headerinfo,40,1,bmp_fp); //读取40字节
	printf("bmp bfSize = %d\n",fileinfo.bfSize);
	printf("bmp width = %d,height = %d\n",headerinfo.biWidth,headerinfo.biHeight);

	int width=headerinfo.biWidth;
	int height=headerinfo.biHeight;
	int width_th=(width*24/8)+((4-(width*24/8)%4)%4);
    int th=((4-(width*24/8)%4)%4);
	printf("width_th=%d\n",width_th);

	//3.准备缩略图

	int width2=headerinfo.biWidth/2;   
	int height2=headerinfo.biHeight/2;
	int width_th2=(width2*24/8)+((4-(width2*24/8)%4)%4);

	fileinfo.bfSize= sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +width_th2*height2;
	headerinfo.biWidth=width2;
	headerinfo.biHeight=height2;
	headerinfo.biSizeImage=width_th2*height2*3;

	printf("bmp bfSize = %d\n",fileinfo.bfSize);
	printf("bmp width = %d,height = %d\n",headerinfo.biWidth,headerinfo.biHeight);
	printf("width_th2=%d\n",width_th2);

	FILE * bmp_zoomp = fopen("z.bmp","wb");

    fwrite(&fileinfo,sizeof(fileinfo),1,bmp_zoomp); // 写入文件头
    fwrite(&headerinfo,sizeof(headerinfo),1,bmp_zoomp); // 写入信息头


	int a=ftell(bmp_zoomp);
	printf("%d\n",a);

	unsigned char buffer[3]; // 用于存储一个像素的颜色分量(RGB)

	for(int i=0;i<height;i+=2)
	{
		fseek(bmp_fp,54+width_th*i,SEEK_SET);
		//printf("%ld\n",ftell(bmp_fp));
		for(int j=0;j<width2;j++)
		{
			fread(buffer, 3, 1, bmp_fp); // 从源文件读取一个像素的颜色分量
			fwrite(buffer,3,1,bmp_zoomp);
			fseek(bmp_fp,3,SEEK_CUR);
			//printf("%d\n",j);
		}
		if(th)    //判断是否需要字节补齐
		{	
			printf("%d",th);
			unsigned char padding = 0;
			fwrite(&padding,th, 1, bmp_zoomp);	
		}
	}

	fclose(bmp_fp);
	fclose(bmp_zoomp);
	return 0;
}

标签:int,图像,bmp,unsigned,width,Bmp,BMP,原理
From: https://www.cnblogs.com/san39/p/18211681

相关文章

  • LCD显示原理及应用
    Linux环境下LCD显示原理及应用1.LCD原理概述LCD(LiquidCrystalDisplay)液晶显示器是一种广泛应用于各种电子设备中的显示技术,它利用液晶分子在电场作用下的排列状态来控制光的透过,从而实现图像显示。2.LCD驱动原理LCD显示屏的驱动通常需要硬件和软件两方面的支持:硬件支持:......
  • 5.14.6 TransMed:Transformer推进多模态医学图像分类
    卷积神经网络(CNN)在医学图像分析任务中表现出了非常有竞争力的性能,例如疾病分类、肿瘤分割和病灶检测。CNN在提取图像局部特征方面具有很大的优势。然而,由于卷积运算的局部性,它不能很好地处理长程关系。多模态医学图像具有明确且重要的长程依赖性,有效的多模态融合策略可以极大......
  • 响应式框架WebFlux架构和原理介绍
    WebFlux响应式框架原理介绍WebFlux简介WebFlux是什么?什么是响应式程序为什么使用响应式程序SpringBoot中的响应式架构图开发使用SpringMVC还是WebFlux?特点响应式宣言(TheReactiveManifesto)WebFlux的特点代码实现maven配置Controller接口理论支撑阿姆达尔定......
  • HTTP基本原理
    HTTP基本原理URI和URLURI全程UniformResourceIdentifier即统一资源标志符。URL全程``UniformResourceLocator`即统一资源定位符。举例来讲https://github.com/favicon.ico,既是一个URI又是一个URL。favicon.ico这样一个图标资源,我们用上一行中的URI/URL指定了访问它的唯......
  • 说说webpack的热更新是如何做到的?原理是什么?
    一、是什么HMR全称 HotModuleReplacement,可以理解为模块热替换,指在应用程序运行过程中,替换、添加、删除模块,而无需重新刷新整个应用例如,我们在应用运行过程中修改了某个模块,通过自动刷新会导致整个应用的整体刷新,那页面中的状态信息都会丢失如果使用的是 HMR,就可以实现只......
  • 全国产化服务器设计原理图:905-多路PCIe的阵列计算全国产化服务器
    多路PCIe的阵列计算全国产化服务器      多路PCIe的阵列计算全国产化服务器以国产化处理器(海光、飞腾ARM、算能RSICV)为主板,扩展6-8路PCIe3.0X4计算卡;计算卡为全国产化的AI处理卡(瑞星微ARM,算能AI,灵犀类脑计算),低功耗FPGAPCIe计算卡;同时扩展万兆以太......
  • Django+Vue前后端分离的原理
    Django+Vue创建项目并实现前后端分离的原理,主要涉及两个主要部分:Django作为后端框架,负责处理业务逻辑和数据;Vue作为前端框架,负责构建用户界面和与后端进行通信。以下是对这一原理的详细讲解:前后端分离的概念:前后端分离是一种软件架构模式,它将应用程序的前端(用户界面)和后端(数......
  • 系统IO读BMP图片
    使用Linux中的系统I/O读取BMP图片信息#include<stdio.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<unistd.h>#include<sys/mman.h>#pragmapack(1)structfile_header{ unsignedshort file_type;//文件标识......
  • 数据库原理第二次实验报告
    目录写在前面实验报告要求任务一(数据库CAP)初始化CAP12任务二:视图(数据库GlobalToyz)123任务三:触发器(数据库GlobalToyz)12测试任务四:存储过程与事务(数据库GlobalToyz)1测试任务五:游标与SQL(数据库GlobalToyz)12参考写在前面因为任务四说的实在是太说得道理了如果没有欧内的手很难做这......
  • 第二题-塔子哥的编译原理实验【KMP】
    本题的模式串可以展开,使用栈来模拟即可,每次一个(放入栈中对应的位置以及前面的数量,每次)弹出栈顶元素,然后将栈顶元素的数量乘以当前的字符串加上栈顶元素的前面的字符串加入到模式串中即可。需要注意有可能模式串非常长,所以中间需要判断是否已经超过了匹配串的长度,超过则直接返......