数据压缩第二次实验--bmp转yuv文件

本文介绍了如何将BMP图像文件转换为YUV格式,详细阐述了BMP文件的结构,并提供了C++代码实现。实验通过读取24位真彩色BMP文件,进行RGB到YUV的色彩空间转换,最后将转换后的YUV数据写入文件。实验结果表明转换过程正确有效,强调了理解文件格式和正确处理数据的重要性。
摘要由CSDN通过智能技术生成

BMP文件转YUV文件


前言

BMP是 Windows 操作系统中的标准图像文件格式,其分成两类:设备相关位图(DDB)和设备无关位图(DIB)。它采用位映射存储格式,除了图像深度可选以外,在绝大多数应用中不采用其他任何压缩,因此,BMP 文件所占用的空间很大。
BMP 文件的图像深度可选 lbit、4bit、8bit、16bit 及 24bit。BMP 文件存储数据时,图像的扫描方式是按从左到右、从下到上的顺序。由于 BMP 文件格式是 Windows 环境中交换与图有关的数据的一种标准,因此在 Windows 环境中运行的图形图像软件都支持 BMP 图像格式。


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

(1)位图头文件数据结构,它包含 BMP 图像文件的类型、显示内容等信息。
(2)位图信息数据结构,它包含有 BMP 图像的宽、高、压缩方法,以及定义颜色等信息。
(3)调色板,这个部分具有可选择性,有些位图需要调色板,有些位图,比如真彩色图(24位的 BMP)就不需要调色板。
(4)位图数据,这部分的内容根据 BMP 位图使用的位数不同而不同,在 24 位图中直接使用 RGB,而其他的小于 24 位的使用调色板中颜色索引值。

以下为相应的数据结构:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

实验步骤:

1.制作BMP文件:

我选择的是制作真彩色图24位的BMP文件,使用画板与Photoshop制作了5张720*576的24位BMP文件图像。分别如下:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

代码如下(示例):

2.编写程序,实现文件转换
思路:

1,参考老师给的读取头文件的代码读取位图文件头与位图信息头。
2,开辟rgb yuv缓冲区,读取BMP文件数据,由于选择的是24位文件,其图像数据区存储的内容就是R G B的真值,就可以直接读取了。
3,调用rgb2yuv的函数,将其最终转换成yuv文件。
4,每个画面出现50帧,yuv文件中一共出现5种不同的画面,写入两个for循环,在命令栏设置相应参数。
在这里插入图片描述

主函数代码如下:
main.cpp

#include <Windows.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include "rgb2yuv.h"
using namespace std;


 int main(int argc, char** argv)
 {
	 BITMAPFILEHEADER File_header;
     BITMAPINFOHEADER Info_header;
	 char* yuvFileName = NULL;
	 char* bmpFileName = NULL;
	 int zhen=50;
	 zhen=atoi(argv[7]);
	 bool flip = false;
	 FILE* bmpFile = NULL;
	 FILE* yuvFile = NULL;
	 yuvFileName = argv[6];
	 yuvFile=fopen(yuvFileName,"wb");
	 unsigned char *rgbBuf, *yBuf, *uBuf,*vBuf;
	 unsigned char *bmpbuf;
   for(int i=1;i<6;i++)
	 {
		 bmpFileName = argv[i];
		
		 bmpFile = fopen(bmpFileName, "rb");
	 
 //读取位图文件头
		if(fread(&File_header,sizeof(BITMAPFILEHEADER),1,bmpFile)!=1)
			{
				printf("erro!");
				exit(0);
		}
		if(File_header.bfType != 0x4D42)
		{
			printf("no bmp!");
			exit(0);}
		else
		{printf("this is a bmp file!");}
  //读取位图信息头
     if(fread(&Info_header,sizeof(BITMAPINFOHEADER),1,bmpFile)!=1)
	 {printf("erro!");
	 exit(0);}

	 unsigned int frameWidth,frameHeight;
	     frameWidth=Info_header.biWidth;
	     frameHeight=Info_header.biHeight;
 //开辟rgbyuv缓冲区
rgbBuf = (unsigned char*)malloc( frameWidth * frameHeight * 3);//输入的rgb文件的数组缓冲区
	yBuf = (unsigned char*)malloc(frameWidth * frameHeight);
	uBuf = (unsigned char*)malloc((frameWidth * frameHeight) / 4);
	vBuf = (unsigned char*)malloc((frameWidth * frameHeight) / 4);

	fread(rgbBuf, 1, frameWidth * frameHeight*3, bmpFile);//读图像数据
	
	   
		if(!RGB2YUV(frameWidth ,frameHeight, rgbBuf, yBuf, uBuf, vBuf, flip))
		{
			for(int j=0;j<zhen;j++)
	{
			
			fwrite(yBuf, 1,  frameWidth * frameHeight, yuvFile);
		    fwrite(uBuf, 1, (frameWidth * frameHeight) / 4, yuvFile);
		    fwrite(vBuf, 1, (frameWidth * frameHeight) / 4, yuvFile);
					}
		}
   }
	 fclose(bmpFile);
	 fclose(yuvFile);

	 return(0);
	 }

RGB2YUV.CPP

#include "stdlib.h"
#include "rgb2yuv.h"

static float RGBYUV02990[256], RGBYUV05870[256], RGBYUV01140[256];
static float RGBYUV01684[256], RGBYUV03316[256];
static float RGBYUV04187[256], RGBYUV00813[256];

int 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;

	if (init_done == 0)
	{
		InitLookupTable();
		init_done = 1;
	}

	// check to see if x_dim and y_dim are divisible by 2
	if ((x_dim % 2) || (y_dim % 2)) return 1;
	size = x_dim * y_dim;

	// allocate memory
	y_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 YUV
	if (!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 UV
	for (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;
}


void InitLookupTable()
{
	int i;

	for (i = 0; i < 256; i++) RGBYUV02990[i] = (float)0.2990 * i;
	for (i = 0; i < 256; i++) RGBYUV05870[i] = (float)0.5870 * i;
	for (i = 0; i < 256; i++) RGBYUV01140[i] = (float)0.1140 * i;
	for (i = 0; i < 256; i++) RGBYUV01684[i] = (float)0.1684 * i;
	for (i = 0; i < 256; i++) RGBYUV03316[i] = (float)0.3316 * i;
	for (i = 0; i < 256; i++) RGBYUV04187[i] = (float)0.4187 * i;
	for (i = 0; i < 256; i++) RGBYUV00813[i] = (float)0.0813 * i;
}




实验结果:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

总结

1,命令行的使用使程序变得更加简洁方便。
2,做文件转换时必须事先清楚文件构成,BMP文件每像素所占的比特数不同其存储的规则也不同,处理方法当然也就不同。
3,用结构体读BMP文件的各部分信息非常方便。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值