bmp2yuv

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

 

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

 

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

 

息;

 

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

 

位的 BMP)就不需要调色板;

 

(4)位图数据,这部分的内容根据 BMP 位图使用的位数不同而不同,在 24 位图中直接

 

使用 RGB,而其他的小于 24 位的使用调色板中颜色索引值。

位图文件头主要包括:

 

typedef struct tagBITMAPFILEHEADER {WORD bfType; /* 说明文件的类型 */ DWORD bfSize; /* 说明文件的大小,用字节为单位 */ WORD bfReserved1; /* 保留,设置为 0 */

DWORD bfOffBits; /* 说明从 BITMAPFILEHEADER 结构开始到实际的图像数据之间的字节偏移量 */} BITMAPFILEHEADER;

(2) 位图信息头主要包括:

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,表示都重要。*/

 

} BITMAPINFO

(3) 调色板实际上是一个数组,它所包含的元素与位图所具有的颜色数相同,决定于

 

biClrUsed 和 biBitCount 字段。数组中每个元素的类型是一个 RGBQUAD 结构。真彩色无调

 

色板部分。

typedef struct tagRGBQUAD { BYTE rgbBlue; /*指定蓝色分量*/ BYTE rgbGreen; /*指定绿色分量*/ BYTE rgbRed; /*指定红色分量*/

BYTE rgbReserved; /*保留,指定为 0*/

 

} RGBQUAD;

实验流程:


关键程序:

main函数

#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<math.h>
#include"BMP2YUV.h"
#include<Windows.h>


BITMAPFILEHEADER File_header;
BITMAPINFOHEADER Info_header;

int main(int argc, char** argv)
{
	/*input order:
	bmpfilename1  output framenumber1
	bmpfilename2  output framenumber2
	.....
	output yuvfilename
	*/
	//input:1bit.bmp 30 4bit.bmp 40 8bit.bmp 30 16bit.bmp 30 24bit.bmp 40 32bit.bmp 40 final.yuv
	bool flip = FALSE;
	/*图像上下翻转*/
	char* bmpFileName = NULL;
	char* yuvFileName = NULL;
	FILE* bmpFile = NULL;
	FILE* yuvFile = NULL;
	u_int8_t* rgbBuf = NULL;
	u_int8_t* yBuf = NULL;
	u_int8_t* uBuf = NULL;
	u_int8_t* vBuf = NULL;
	u_int32_t videoFramesWritten = 0;
	u_int frameWidth, frameHeight;
	int i = 0, j = 0;

	yuvFileName = argv[argc - 1];
	if ((yuvFile = fopen(yuvFileName, "wb")) == NULL)
	{
		printf("cannot find yuv file\n");
		exit(1);
	}
	else
	{
		printf("The output yuv file is %s\n", yuvFileName);
	}
	/*利用循环依次读bmp文件(像素宽高一致) 按照输入的帧数写到同一个YUV文件*/
	for (i = 0; i < argc / 2 - 1; i++)
	{
		videoFramesWritten = 0;
		bmpFileName = argv[2 * i + 1];
		/* 命令行参数输入1bit.bmp 40 2bit.bmp 40 …… */
		if ((bmpFile = fopen(bmpFileName, "rb")) == NULL)
		{
			printf("cannot find bmp file\n");
			exit(1);
		}
		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);
		}
		if (File_header.bfType != 0x4D42)
		{
			printf("Not bmp file!");
			exit(0);
		}
		else
		{
			printf("this is a %c%c\n", File_header.bfType);
		}
		if (fread(&Info_header, sizeof(BITMAPINFOHEADER), 1, bmpFile) != 1)
		{
			printf("read info header error!");
			exit(0);
		}
		printf("bitcount==%d\n", (unsigned char)Info_header.biBitCount);
		//  end read header
		frameWidth = Info_header.biWidth;
		frameHeight = Info_header.biHeight;
		rgbBuf = (unsigned char *)malloc(sizeof(unsigned char)*frameHeight*frameWidth * 3);
		memset(rgbBuf, 0, frameHeight*frameWidth * 3);
		yBuf = (unsigned char*)malloc(sizeof(unsigned char)*frameHeight*frameWidth);
		uBuf = (unsigned char*)malloc(sizeof(unsigned char)*frameHeight*frameWidth / 4);
		vBuf = (unsigned char*)malloc(sizeof(unsigned char)*frameHeight*frameWidth / 4);
		ReadRGB(rgbBuf, bmpFile, File_header, Info_header);
		if (RGB2YUV(frameWidth, frameHeight, rgbBuf, yBuf, uBuf, vBuf, flip))
		{
			printf("error");
			return 0;
		}
		//根据命令行输入的参数,不同位数的bmp图像写入不同帧数
		for (j = 0; j <atoi(argv[2 * i + 2]); j++)
		{
			fwrite(yBuf, 1, frameWidth * frameHeight, yuvFile);
			fwrite(uBuf, 1, (frameWidth * frameHeight) / 4, yuvFile);
			fwrite(vBuf, 1, (frameWidth * frameHeight) / 4, yuvFile);
			printf("\r...%d", ++videoFramesWritten);
		}
		printf("\n\n");
		if (rgbBuf != NULL) free(rgbBuf);
		if (yBuf != NULL) free(yBuf);
		if (uBuf != NULL) free(uBuf);
		if (vBuf != NULL) free(vBuf);
		if (bmpFile != NULL) fclose(bmpFile);
	}
	if (yuvFile != NULL) fclose(yuvFile);
	return 0;
}

转换函数

#include<stdio.h>
#include<math.h>
#include"BMPtoYUV.h"
#include<Windows.h>

static float RGBYUV02990[256], RGBYUV05870[256], RGBYUV01140[256];
static float RGBYUV01684[256], RGBYUV03316[256];
static float RGBYUV04187[256], RGBYUV00813[256];
bool MakePalette(FILE * pFile, BITMAPFILEHEADER &file_h, BITMAPINFOHEADER & info_h, RGBQUAD *pRGB_out)
{
	/*若图像开始位置与INFOHEADER结束处位置,还有pow(2, info_h.biBitCount)个
	结构体RGBQUAQ的空间(颜色数为2的biBitCount次方,调色板为数组),
	则说明该bmp图像有调色板。*/
	if ((file_h.bfOffBits - sizeof(BITMAPFILEHEADER) - info_h.biSize) == sizeof(RGBQUAD)*pow(2, info_h.biBitCount))
	{
		fseek(pFile, sizeof(BITMAPFILEHEADER) + info_h.biSize, 0);
		fread(pRGB_out, sizeof(RGBQUAD), (unsigned int)pow(2, info_h.biBitCount), pFile);
		return true;
	}
	else
		return false;
}
void ReadRGB(unsigned char * rgbbuf, FILE *bmpfile, BITMAPFILEHEADER &file_h, BITMAPINFOHEADER & info_h)
{
	u_int Height = 0, Width = 0;
	long Loop = 0;
	unsigned char *bmpbuf = NULL;
	unsigned char *rgb = NULL;
	unsigned char mask = 0;
	int deltaw = 0;
	rgb = rgbbuf;

	if (((info_h.biWidth  * info_h.biBitCount / 8) % 4) == 0)
		Width = info_h.biWidth*info_h.biBitCount / 8;
	else
		Width = (info_h.biWidth  * info_h.biBitCount + 31) / 32 * 4;

	if ((info_h.biHeight % 2) == 0)
		Height = info_h.biHeight;
	else
		Height = info_h.biHeight + 1;
	deltaw = Width - info_h.biWidth * info_h.biBitCount / 8;
	bmpbuf = (unsigned char *)malloc(sizeof(unsigned char)*Height*Width);
	printf("word_width :%d , word_height: %d \n", Width, Height);
	RGBQUAD *pRGB = (RGBQUAD *)malloc(sizeof(RGBQUAD) * (unsigned int)pow(2.0, (double)info_h.biBitCount));
	if (!MakePalette(bmpfile, file_h, info_h, pRGB))
	{
		printf("No palette!\n");
	}
	fread(bmpbuf, 1, Height*Width, bmpfile);
	if (info_h.biBitCount == 24)
	{
		for (Loop = 0; Loop<Height*Width; Loop++)
		{
			if (deltaw != 0)
			{
				if (deltaw == 1)
				{
					if ((Loop + 1) % Width == 0)
						continue;
				}
				else if (deltaw == 2)
				{
					if ((Loop + 1) % Width == 0 || (Loop + 2) % Width == 0)
						continue;
				}
				else
				{
					if ((Loop + 1) % Width == 0 || (Loop + 2) % Width == 0 || (Loop + 3) % Width == 0)
						continue;
				}
			}
			*rgb = *(bmpbuf + Loop);
			rgb++;
		}
	}
	else if (info_h.biBitCount == 16)
	{
		for (Loop = 0; Loop < Height * Width; Loop += 2)
		{
			*rgb = (bmpbuf[Loop] & 0x1F) << 3;
			*(rgb + 1) = ((bmpbuf[Loop] & 0xE0) >> 2) + ((bmpbuf[Loop + 1] & 0x03) << 6);
			*(rgb + 2) = (bmpbuf[Loop + 1] & 0x7C) << 1;
			rgb += 3;
		}
	}
	else
	{
		for (Loop = 0; Loop < Height*Width; Loop++)
		{
			if (deltaw != 0)
			{
				if (deltaw == 1)
				{
					if ((Loop + 1) % Width == 0)
						continue;
				}
				else if (deltaw == 2)
				{
					if ((Loop + 1) % Width == 0 || (Loop + 2) % Width == 0)
						continue;
				}
				else
				{
					if ((Loop + 1) % Width == 0 || (Loop + 2) % Width == 0 || (Loop + 3) % Width == 0)
						continue;
				}
			}

			switch (info_h.biBitCount)
			{
			case 1:
				mask = 0x80;
				break;
			case 2:
				mask = 0xC0;
				break;
			case 4:
				mask = 0xF0;
				break;
			case 8:
				mask = 0xFF;
				break;
			}
			int shiftCnt = 1;
			while (mask)
			{
				/*根据从数据中提取出的索引号index,以index为调色板数组下标去查询
				数据中每info_h.biBitCount位所代表的颜色。
				while 循环的次数:
				1bit 图像 每字节循环8次
				2bit 图像 每字节循环4次
				4bit 图像 每字节循环2次
				8bit 图像 每字节循环1次。
				*/
				unsigned char index =
					mask == 0xFF ? bmpbuf[Loop] : ((bmpbuf[Loop] & mask) >> (8 - shiftCnt *info_h.biBitCount));
				*rgb = pRGB[index].rgbBlue;
				*(rgb + 1) = pRGB[index].rgbGreen;
				*(rgb + 2) = pRGB[index].rgbRed;
				if (info_h.biBitCount == 8) mask = 0;
				else    mask >>= info_h.biBitCount;
				rgb += 3;
				shiftCnt++;
			}
		}

	}
	if (pRGB != NULL) free(pRGB);
	if (bmpbuf != NULL)free(bmpbuf);
}

头文件

#ifndef BMP2YUV_H_
#define BMP2YUV_H_
#endif

void ReadRGB(unsigned char * rgbbuf, FILE *bmpfile, BITMAPFILEHEADER &file_h, BITMAPINFOHEADER & info_h);

转换结果

bmp


yuv


bmp2


yuv2


bmp3


yuv3


bmp4


yuv4


bmp5


yuv5



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值