[数据压缩作业]BMP 转 YUV

news/2025/2/1 12:59:48/

文章目录

  • BMP文件格式回顾
  • 一、BMP转YUV文件转换流程分析
  • 二、读取BMP文件
    • 1.代码
    • 2.实验结果


BMP文件格式回顾

典型的BMP图像文件由四部分组成:

1:位图头文件数据结构,它包含BMP图像文件的类型、显示内容等信息;

2:位图信息数据结构,它包含有BMP图像的宽、高、压缩方法,以及定义颜色等信息;

3:调色板,这个部分是可选的,有些位图需要调色板,有些位图,比如真彩色图(24位的BMP)就不需要调色板;

4:位图数据,这部分的内容根据BMP位图使用的位数不同而不同,在24位图中直接使用RGB,而其他的小于24位的使用调色板中颜色索引值。

位图文件头

typedef struct tagBITMAPFILEHEADER {
WORD bfType; /* 说明文件的类型 */
DWORD bfSize; /* 说明文件的大小,用字节为单位 */
/*注意此处的字节序问题
WORD bfReserved1; /* 保留,设置为0 */
WORD bfReserved2; /* 保留,设置为0 */
DWORD bfOffBits; /* 说明从BITMAPFILEHEADER结构
开始到实际的图像数据之间的字节偏移量 */
} BITMAPFILEHEADER

位图信息头

typedef struct tagBITMAPINFOHEADER { 
DWORD biSize; /* 说明结构体所需字节数 */
LONG biWidth; /* 以像素为单位说明图像的宽度 */
LONG biHeight; /* 以像素为单位说明图像的高速 */
WORD biPlanes; /* 说明位面数,必须为1 */
WORD biBitCount; /* 说明位数/像素,1、2、4、8、24 */
DWORD biCompression; /* 说明图像是否压缩及压缩类型BI_RGB,BI_RLE8,BI_RLE4,BI_BITFIELDS */
DWORD biSizeImage; /* 以字节为单位说明图像大小 ,必须是4的整数倍*/
LONG biXPelsPerMeter; /* 目标设备的水平分辨率,像素/米 */
LONG biYPelsPerMeter; /*目标设备的垂直分辨率,像素/米 */
DWORD biClrUsed; /* 说明图像实际用到的颜色数,如果为0则颜色数为2的biBitCount次方 */
DWORD biClrImportant; /*说明对图像显示有重要影响的颜色索引的数目,如果是0,表示都重要。*/
} BITMAPINFOHEADER

调色板实际上是一个数组,它所包含的元素与位图所具有的颜色 数相同,决定于biClrUsed和biBitCount字段。数组中每个元素的类型 是一个RGBQUAD结构。真彩色无调色板部分。

typedef struct tagRGBQUAD { 
BYTE rgbBlue; /*指定蓝色分量*/
BYTE rgbGreen; /*指定绿色分量*/
BYTE rgbRed; /*指定红色分量*/
BYTE rgbReserved; /*保留,指定为0*/
} RGBQUAD;

位图数据,这部分的内容根据BMP位图使用的位数不同而不同,在24位图中直接使用RGB,而其他的小于24位的使用调色板中颜色索引值

当biBitCount=1时,8个像素占1个字节;

当biBitCount=4时,2个像素占1个字节;

当biBitCount=8时,1个像素占1个字节;

当biBitCount=24时,1个像素占3个字节,按顺序分别为B,G,R;

一、BMP转YUV文件转换流程分析

1. 程序初始化(打开两个文件、定义变量和缓冲区等)

2. 读取BMP文件,抽取或生成RGB数据写入缓冲区

3. 调用RGB2YUV的函数实现RGB到YUV数据的转换

4. 写YUV文件

5. 程序收尾工作(关闭文件,释放缓冲区)

二、读取BMP文件

rgb2yuv.h

void RGB2YUV(int x_dim, int y_dim, void *bmp, void *y_out, void *u_out, void *v_out, int flip)
{static int init_done = 0;long i, j, size;unsigned char *r, *g, *b;unsigned char *y, *u, *v;unsigned char *pu1, *pu2, *pv1, *pv2, *psu, *psv;unsigned char *y_buffer, *u_buffer, *v_buffer;unsigned char *sub_u_buf, *sub_v_buf;void InitLookupTable();if (init_done == 0){InitLookupTable();init_done = 1;}if ((x_dim % 2) || (y_dim % 2)) return 1;size = x_dim * y_dim;// allocate memoryy_buffer = (unsigned char *)y_out;sub_u_buf = (unsigned char *)u_out;sub_v_buf = (unsigned char *)v_out;u_buffer = (unsigned char *)malloc(size * sizeof(unsigned char));v_buffer = (unsigned char *)malloc(size * sizeof(unsigned char));if (!(u_buffer && v_buffer)){if (u_buffer) free(u_buffer);if (v_buffer) free(v_buffer);return 2;}b = (unsigned char *)bmp;y = y_buffer;u = u_buffer;v = v_buffer;// convert RGB to YUVif (!flip) {for (j = 0; j < y_dim; j++){y = y_buffer + (y_dim - j - 1) * x_dim;u = u_buffer + (y_dim - j - 1) * x_dim;v = v_buffer + (y_dim - j - 1) * x_dim;for (i = 0; i < x_dim; i++) {g = b + 1;r = b + 2;*y = (unsigned char)(RGBYUV02990[*r] + RGBYUV05870[*g] + RGBYUV01140[*b]);*u = (unsigned char)(-RGBYUV01684[*r] - RGBYUV03316[*g] + (*b) / 2 + 128);*v = (unsigned char)((*r) / 2 - RGBYUV04187[*g] - RGBYUV00813[*b] + 128);b += 3;y++;u++;v++;}}}else {for (i = 0; i < size; i++){g = b + 1;r = b + 2;*y = (unsigned char)(RGBYUV02990[*r] + RGBYUV05870[*g] + RGBYUV01140[*b]);*u = (unsigned char)(-RGBYUV01684[*r] - RGBYUV03316[*g] + (*b) / 2 + 128);*v = (unsigned char)((*r) / 2 - RGBYUV04187[*g] - RGBYUV00813[*b] + 128);b += 3;y++;u++;v++;}}// subsample UVfor (j = 0; j < y_dim / 2; j++){psu = sub_u_buf + j * x_dim / 2;psv = sub_v_buf + j * x_dim / 2;pu1 = u_buffer + 2 * j * x_dim;pu2 = u_buffer + (2 * j + 1) * x_dim;pv1 = v_buffer + 2 * j * x_dim;pv2 = v_buffer + (2 * j + 1) * x_dim;for (i = 0; i < x_dim / 2; i++){*psu = (*pu1 + *(pu1 + 1) + *pu2 + *(pu2 + 1)) / 4;*psv = (*pv1 + *(pv1 + 1) + *pv2 + *(pv2 + 1)) / 4;psu++;psv++;pu1 += 2;pu2 += 2;pv1 += 2;pv2 += 2;}}free(u_buffer);free(v_buffer);return 0;
}

读取RGB数据

//bmp转rgb
void ReadRGB( BITMAPFILEHEADER & file_h, BITMAPINFOHEADER & info_h, FILE * bmpFile,unsigned char * rgbDataOut)
{unsigned long Loop, i, j;unsigned char mask=0;unsigned char  *Data;unsigned long width, height;/*计算实际的宽高*///由于需与DWORD对齐,所以每行需满足为4字节的整数倍,若不是则需补成其整数倍if (((info_h.biWidth*info_h.biBitCount)%4) == 0)width = info_h.biWidth/ 8 * info_h.biBitCount;elsewidth = (info_h.biWidth*info_h.biBitCount + 31) / 32 * 4;//判断高是否为偶数,若不是,补齐if ((info_h.biHeight % 2) == 0)height = info_h.biHeight;elseheight = info_h.biHeight + 1;Data = (unsigned char *)malloc(height*width);//写入数据到Data中fseek(bmpFile, file_h.bfOffBits, 0);if (fread(Data, height*width, 1, bmpFile) != 1){printf("read file error!");exit(0);}RGBQUAD *pRGB = (RGBQUAD *)malloc(sizeof(RGBQUAD)*(unsigned int)pow(2,(float)info_h.biBitCount));//把unsigned char 改为unsigned int,否则溢出if (!MakePalette(bmpFile, file_h, info_h, pRGB))printf("No palette!");/*判断深度,根据不同深度做出不同操作*///深度为24bit时,不需要调用调色板if (info_h.biBitCount == 24){memcpy(rgbDataOut, Data, height*width);//将Data中的数据直接拷到rgbDataOutfree(Data);return;}//深度为16bit时,位与移位取像素数据转换为8bit/彩色分量写RGB缓冲区if (info_h.biBitCount == 16){for (Loop = 0; Loop < height * width ; Loop+=2)//loop每次循环中应该要逐次增加2个字节(16位)。{*rgbDataOut = (Data[Loop] & 0x1F) << 3;*(rgbDataOut + 1) = ((Data[Loop] & 0xE0) >> 2) + ((Data[Loop + 1] & 0x03) << 6);*(rgbDataOut + 2) = (Data[Loop + 1] & 0x7C) << 1;rgbDataOut += 3;}}//深度小于等于8时,构造调色板for (Loop = 0; Loop<height*width; Loop++){switch (info_h.biBitCount){case 1:mask = 0x80;break;case 2:mask = 0xC0;break;case 4:mask = 0xF0;break;case 8:mask = 0xFF;}int shiftCnt = 1;while (mask){unsigned char index = mask == 0xFF ? Data[Loop] : ((Data[Loop] & mask) >> (8 - shiftCnt * info_h.biBitCount));*rgbDataOut = pRGB[index].rgbBlue;*(rgbDataOut + 1) = pRGB[index].rgbGreen;*(rgbDataOut + 2) = pRGB[index].rgbRed;if (info_h.biBitCount == 8)mask = 0;elsemask >>= info_h.biBitCount;rgbDataOut += 3;shiftCnt++;}}free(Data);free(pRGB);}

bmp2yuv.h部分代码

bool MakePalette(FILE * pFile, BITMAPFILEHEADER &file_h, BITMAPINFOHEADER & info_h, RGBQUAD *pRGB_out)
{/*如果图像开始位置与信息头结束的位置中间,还有2的info_h.biBitCount次方(颜色数)个RGBUAQ空间,则存在调色板*/if ((file_h.bfOffBits - sizeof(BITMAPFILEHEADER) - info_h.biSize) == sizeof(RGBQUAD)*pow(2, (float)info_h.biBitCount)){fseek(pFile, sizeof(BITMAPFILEHEADER) + info_h.biSize, 0);fread(pRGB_out, sizeof(RGBQUAD), (unsigned int)pow(2, (float)info_h.biBitCount), pFile);return true;}elsereturn false;
}

main.cpp

#include <stdio.h>
#include <iostream>
#include <windows.h>
#include "bmp2yuv.h"
#include "rgb2yuv.h"void main(int argc, char *argv[])
{FILE *bmpFile = NULL, *yuvFile = NULL;BITMAPFILEHEADER File_header;BITMAPINFOHEADER Info_header;char* bmpFileName=NULL;char* yuvFileName=NULL;unsigned char * rgbBuf = NULL;unsigned char * yBuff = NULL;unsigned char * uBuff = NULL;unsigned char * vBuff = NULL;int flip = 0;//flip=1时正序,为0时上下翻转int frame_count = 250;//每图50帧,1bit,4bit,8bit,16bit,24bit各一张,共250帧int frame_width, frame_height;//打开yuv文件yuvFileName=argv[6];if ((yuvFile = fopen(yuvFileName, "wb")) == NULL){printf("yuv file failed!");exit(0);}else{printf("The output yuv file is %s\n",yuvFileName);}for (int n = 1; n < 6; n++){//	循环打开bmp文件if ((bmpFile = fopen(argv[n], "rb")) == NULL){printf("bmp file open failed!");exit(0);}else{printf("The input bmp file is %s\n",bmpFileName);}//	读文件头信息if (fread(&File_header, sizeof(BITMAPFILEHEADER), 1, bmpFile) != 1){printf("read file header error!");exit(0);}//判断是否为bmp文件if (File_header.bfType != 0x4D42){printf("Not bmp file!");exit(0);}//读信息头信息if (fread(&Info_header, sizeof(BITMAPINFOHEADER), 1, bmpFile) != 1){printf("read info header error!");exit(0);}frame_width = Info_header.biWidth;frame_height=Info_header.biHeight;printf("This is a %d bits image!\n", Info_header.biBitCount);printf("\nbmp size: \t%d X %d\n", Info_header.biWidth, Info_header.biHeight);//开辟缓冲区rgbBuf = (unsigned char *)malloc(frame_height*frame_width * 3);memset(rgbBuf, 0, frame_height*frame_width * 3);//初始化函数,用于清0yBuff = (unsigned char *)malloc(frame_height*frame_width);uBuff = (unsigned char *)malloc((frame_height*frame_width) / 4);vBuff = (unsigned char *)malloc((frame_height*frame_width) / 4);ReadRGB(File_header, Info_header, bmpFile, rgbBuf);if (RGB2YUV(frame_width, frame_height, rgbBuf, yBuff, uBuff, vBuff, flip)){printf("rgb2yuv error");exit(1);}for (int i = 0; i < frame_width*frame_height; i++){if (yBuff[i] < 16) yBuff[i] = 16;if (yBuff[i] > 235) yBuff[i] = 235;}for (int i = 0; i < frame_width*frame_height / 4; i++){if (uBuff[i] < 16) uBuff[i] = 16;if (uBuff[i] > 240) uBuff[i] = 240;if (vBuff[i] < 16) vBuff[i] = 16;if (vBuff[i] > 240) vBuff[i] = 240;}for (int f = 0; f < 50; f++){fwrite(yBuff, 1, frame_width * frame_height, yuvFile);fwrite(uBuff, 1, (frame_width * frame_height) / 4, yuvFile);fwrite(vBuff, 1, (frame_width * frame_height) / 4, yuvFile);}}free(rgbBuf);free(yBuff);free(uBuff);free(vBuff);fclose(bmpFile);fclose(yuvFile);getchar();}

实验用图:

 实验结果

 

 

参考:【数据压缩】实验二 BMP2YUV_yejia1280的博客-CSDN博客


http://www.ppmy.cn/news/807484.html

相关文章

BMP转YUV文件

一.bmp文件介绍 1.简介 BMP&#xff08;全称Bitmap&#xff09;是Windows操作系统中的标准图像文件格式&#xff0c;可以分成两类&#xff1a;设备相关位图&#xff08;DDB&#xff09;和设备无关位图&#xff08;DIB&#xff09;&#xff0c;使用广泛。它采用位映射存储格式&…

(数据压缩作业)BMP转YUV

一 BMP文件格式 典型的BMP图像文件由四部分组成&#xff1a; &#xff08;1&#xff09;位图头文件数据结构&#xff0c;它包含BMP图像文件的类型、显示内容等信息&#xff1b; &#xff08;2&#xff09;位图信息数据结构&#xff0c;它包含有BMP图像的宽、高、压缩方法&…

图像文件转换实验:BMPtoYUV

一、实验目的 1.理解图像文件的基本组成。 2.掌握结构体作为复杂数据对象的用法。进一步熟悉由问题到程序的解决方案&#xff0c;并掌握编程细节&#xff1a;如内存分配、倒序读写、字节序、文件读写过程等。 二、实验原理 BMP文件的组成结构 BMP&#xff08;全称Bitmap&a…

BMP序列转YUV文件

目录 一、基本原理 1.BMP文件格式 2.文件组成 位图文件头&#xff1a; 位图信息头&#xff1a; 调色板&#xff1a; 位图数据&#xff1a; 二、实验思路 三、代码实现 修改命令行参数 1.rgbtoyuv rgb2yuv.h main函数 rgb2yuv.cpp 2.bmptoyuv bmp2yuv.h main函数…

【数据压缩】实验1:将BMP文件转换为YUV文件

BMP文件简介 位图文件(Bitmap-File&#xff0c;BMP)格式是Windows采用的图像文件存储格式&#xff0c;其位图文件默认的文件扩展名是bmp或者dib。BMP文件的图像深度可选1bit、4bit、8bit、16bit及24bit。BMP文件存储数据时&#xff0c;图像的扫描方式是按从左到右、从下到上的…

babylonjs

如何引入babylonjs到项目中 babylonjs中文文档 https://doc.cnbabylon.com/3-0-how-to-get-babylon-js/ “babylonjs/core”: “^5.0.0”, BabylonOne.vue <template> <div class"mainbox " touchmove.prevent><div :class"tipsBox?tipsBox…

半监督3D医学图像分割(三):URPC

Efficient Semi-supervised Gross Target Volume of Nasopharyngeal Carcinoma Segmentation via Uncertainty Rectified Pyramid Consistency 深度学习归根结底是数据驱动的&#xff0c;模型训练的好坏依赖于数据集。在医学图像分割领域&#xff0c;即使是像nn-UNet那样强大的…

[数据压缩]bmp序列转yuv文件

目录 bmp文件分析 bmp转yuv思路 代码实现 结果展示 bmp文件分析 bmp简介 BMP是英文Bitmap&#xff08;位图&#xff09;的简写&#xff0c;是Windows采用的图像文件存储格式。在Windows环境下运行的所有图像处理软件都支持这种格式。在Windows环境下运行的所有图像处理软件…