栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

BMP转YUV文件

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

BMP转YUV文件

一.bmp文件介绍

    1.简介

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

2.文件格式

BMP(bitmap) 文件由文件头、位图信息头、颜色信息和图 形数据 4 部分组成。文件头主要包含文件的大小、文件类型、 图像数据偏离文件头的长度等信息;位图信息头包含图像的 尺寸信息、图像用几个比特数值来表示一个像素、图像是否 压缩、图像所用的颜色数等信息。颜色信息包含图像所用到 的颜色表,显示图像时需用到几个颜色表来生成调色板,但 如果图像为真彩色,即图像的每个像素用 24 个比特来表示, 文件中就没有这一块信息,也就不需要操作调色板。文件中 的数据块表示图像的相应像素值,需要注意的是:图像的像 素值在文件中的存放顺序为从左到右,从下到上,也就是说, 在 BMP 文件中首先存放的是图像的最后一行像素,最后才存 储图像的第一行像素,但对于同一行的像素,则是按照先左边后右边的顺序存储的;另外一个需要关注的细节是:文件 存储图像的每一行像素值时,如果存储该行像素值所占的字 节数为 4 的倍数,则正常存储;否则,需要在后端补 0,凑足 4 的倍数

     2.1位图头文件

//第一部分为位图文件头 BITMAPFILEHEADER,是一个
结构,其定义如下:
typedef struct tagBITMAPFILEHEADER
{
WORD bfType; // 位图文件的类型,必须为 BM
DWORD bfSize; // 位图文件的大小,字节单位
WORD bfReserved1; // 位图文件保留字,必须为 0
WORD bfReserved2; // 位图文件保留字,必须为 0
DWORD bfOffBits; // 位图文件头到数据的偏移
}BITMAPFILEHEADER ;

     2.2位图信息头

//第二部分为位图信息头 BITMAPINFOHEADER,也是一
个结构,其定义如下:
typedef struct tagBITMAPINFOHEADER
{
DWORD biSize; // 该结构所占字节数
LONG biWidth; // 位图的宽度,像素单位
LONG biHeight; // 位图的高度,像素单位
WORD biPlanes; // 目标设备的位面数,必须为 1
WORD biBitCount; // 颜色深度,即每个像素所占的
位数
DWORD biCompression; // 位图的压缩类型
DWORD biSizeImage; // 位图的大小,字节单位
LONG biXPelsPerMeter; // 位图水平分辨率
LONG biYPelsPerMeter; // 位图的垂直分辨率
DWORD biClrUsed; // 位图实际使用的颜色表中
颜色数
DWORD biClrImportant; // 位图显示中比较重要的颜
色数
} BITMAPINFOHEADER;

    2.3调色板

第三部分为调色板 RGBQUAD。当然这是对那些需要调
色板的位图文件而言的。有些位图,如真彩色图,是不需要
调色板的,BITMAPINFOHEADER 后直接是位图数据。
颜色表实际上是一个数组,共有 biClrUsed 个元素(如果
该值为零,则有 2biBitCount 个元素)。数组中每个元素的类
型是一个 RGBQUAD 结构,占 4 个字节,其定义如下:
typedef struct tagRGBQUAD
{
BYTE rgbBlue; // 该颜色的蓝色分量
BYTE rgbGreen; // 该颜色的绿色分量
BYTE rgbRed; // 该颜色的红色分量
BYTE rgbReserved; // 保留值
} RGBQUAD;

位图信息头和颜色表组成位图信息结构 BITMAPINFO, 其定义如下:

typedef struct tagBITMAPINFO
{
BITMAPINFOHEADER bmiHeader; // 位图信息头
RGBQUAD bmiColors[1]; // 颜色表
} BITMAPINFO

二.上机实操

大致思路:

main函数

1.打开文件,读取头信息,开辟缓存区


2.将RGB数据写入缓存区


3.调用rgbtoyuv函数转化


4.清理内存,释放缓存区

bmptoyuv函数

1.建立查找表,对像素值进行处理

2.根据位数进行相应处理

函数转化核心

 三.代码解析

bmp2rgb

#include
#include

 


 
 
int bmp2rgb(BITMAPFILEHEADER &filh,BITMAPINFOHEADER &pich,FILE* pFile,unsigned char* rgbbuf)
///读取图像尺寸,以像素数为单位
int w,h,i,j;
w=pich.biWidth;
h=pich.biHeight;
 
unsigned char* dataBuf=(unsigned char*)malloc(w*h*pich.bit);///创建数据缓冲区
fseek(pFile,filh.bfOffBits,0);///使指针指向对应地方
fread(dataBuf,1,w*h*pich.bit,pFile);///将相应字节大小的数据读入dataBuf
 bool MakePalette(FILE * pFile,BITMAPFILEHEADER &filh,BITMAPINFOHEADER & pich,RGBQUAD *pRGB_out);申明创建调色板函数
 
int color;///定义颜色数变量
if(pich.biClrUsed==0)
{
m=pow(2,pich.8*bit);///若信息头中颜色数为0,则实际颜色数为2的位数次方
}
else
{
	color=pich.biClrUsed;
}
 

switch(info_h.8*bit)用switch选择语句对不同的位数图像进行不同的操作
{
casw 16;

for (j = 0; j < h; j++)//j控制行循环
{
    int pixCnt = 0;
    for (i = 0; i < w; i+=2)//i控制列循环
    {
        *rgb = (data[i + w*j] & 0x1F) << 3;//B
        *(rgbbuf + 1) = ((dataBuf[i + w*j] & 0xE0) >> 3) + ((data[i + w*j + 1] & 0x07) << 5);
        *(rgbbuf+ 2) = dataBuf[i + w*j + 1] & 0xF8; //R
        rgbbuf += 3;
        
        pixCnt++;
        if (pixCnt == info_h.biWidth)
            i = w - 1;
    }
}
break;

case 24:
	for (j = 0; j < h; j++)//j控制行循环
{
    int pixCnt = 0;
    for (i = 0; i < w; i += 3)//i控制列循环
    {
        *rgbbuf = data[i + w*j];//B
        *(rgbbuf + 1) = data[i + w*j + 1];//G
        *(rgbbuf + 2) = data[i + w*j + 2];//R
        rgbbuf += 3;
        //如果到了行尾补充位则直接转到下一行
        pixCnt++;
        if (pixCnt == info_h.biWidth)
            i = w - 1;
    }
}
    break;
RGBQUAD *pRGB = (RGBQUAD *)malloc(sizeof(RGBQUAD)*color);///开辟调色板区域,RGBQUAD元素数目与所用颜色数相同,
 
 for(j=0;j>(8-indext*pich.8*bit));
			* rgbbuf = pRGB[index2].rgbBlue;
			* (rgbbuf+1) = pRGB[index2].rgbGreen;
			* (rgbbuf+2) = pRGB[index2].rgbRed;
			if(pic.8*bit == 8)	index = 0;
			else 	index >>= pic.8*bit;
			rgbbuf+=3;
			index2 ++;
		 }
		 }
}
if(dataBuf!=NULL)
{
	free(dataBuf);
}  
return 0;
}

rbgb2yuv定义查找表,节省代码

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

rgb2yuv

#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;
}

调色板

bool MakePalette(FILE * pFile,BITMAPFILEHEADER &file_h,BITMAPINFOHEADER & info_h,RGBQUAD *pRGB_out)///定义创建调色板函数
{
	int Clr;///定义颜色数变量
	if(info_h.biClrUsed==0)
	{
		Clr=pow(2,info_h.biBitCount);
	}
	else
	{
		Clr=info_h.biClrUsed;
	}
 
	if ((file_h.bfOffBits - sizeof(BITMAPFILEHEADER) - info_h.biSize) == sizeof(RGBQUAD)*Clr)///判断实际数据偏移量-文件头-信息头
		///是否等于调色板大小
	{
		fseek(pFile,sizeof(BITMAPFILEHEADER)+info_h.biSize,0);///bmpFile文件指针指向调色板处
		fread(pRGB_out,sizeof(RGBQUAD),Clr,pFile);//在新的调色板区域写入数据
		return true;
	}
	else
		return false;
}

主函数主体代码

定义文件头和信息头,打开五张图片

BITMAPFILEHEADER File_header;
   BITMAPINFOHEADER Info_header;
	 char* yuvFileName = NULL;
	 char* bmpFileName = NULL;
	 
	 
	 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");
}

读取文件头,判断是否是bmp类型的

if (fread(&File_header, sizeof(BITMAPFILEHEADER), 1, bmpFile) != 1)
		{
			printf("read file header error!");
			exit(0);
		}
		if (File_header.bfType != 0x4D42)
		{
			printf("Not bmp file!");
			exit(0);
		}
		else
		{
			printf("this is a %cn", File_header.bfType);//debug
		}
		if (fread(&Info_header, sizeof(BITMAPINFOHEADER), 1, bmpFile) != 1)
		{
			printf("read info header error!");
			exit(0);
		}
		else
		{
}
int width = Info_header.biWidth;
int height = Info_header.biHeight;//读取图像尺寸
unsigned char* rgbBuf=(unsigned char*)malloc(width*height*3);
unsigned char* yBuf=(unsigned char*)malloc(width*height);
unsigned char* uBuf=(unsigned char*)malloc((width*height)/4);
unsigned char* vBuf=(unsigned char*)malloc((width*height)/4);//分配缓存区域

调用文件格式函数

bmp2rgb(File_header,Info_header,bmpFile,rgbBuf);
rgb2yuv(width,height,rgbBuf,yBuf,uBuf,vBuf,flip);

读入yuv

for(int k=0;k<30;k++)
		{
			fwrite(yBuf,1,size,yuv);
			fwrite(uBuf,1,size/4,yuv);
			fwrite(vBuf,1,size/4,yuv);
		}

释放缓存

        free(rgbBuf);
		free(yBuf);
		free(uBuf;
		free(vBuf);	
      fclose(yuv);

四.实验结果

刚好英语pre时看了泰坦尼克号,这次就用泰坦尼克号的照片当例子

 上面时五张bmp格式的图片,经过转换播放后

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1009481.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号