1. 程式人生 > >實驗二 影象檔案的讀寫和轉換(BMP轉YUV)

實驗二 影象檔案的讀寫和轉換(BMP轉YUV)

實驗二 影象檔案的讀寫和轉換(BMPYUV)

一、實驗基本原理

1.BMP點陣圖檔案格式

BMP(全稱Bitmap)Windows作業系統中的標準影象檔案格式,可以分成兩類:裝置相關點陣圖(DDB)和裝置無關點陣圖(DIB),採用位對映儲存格式,除了影象深度可選(148162432bit)以外,在絕大多數應用中不進行其他任何壓縮,因此BMP檔案所佔用的空間很大。BMP檔案儲存資料時,影象的掃描方式是按從左到右、從下到上的順序。由於BMP檔案格式是 Windows 環境中交換與圖有關的資料的一種標準,因此在Windows環境中執行的圖形影象軟體都支援BMP影象格式。BMP點陣圖檔案預設的副檔名是
bmp或者dib

BMP檔案大體上分為四個部分:

(1)點陣圖標頭檔案資料結構

typedef struct tagBITMAPFILEHEADER 
{
	WORD bfType; /* 說明檔案的型別 */  
	DWORD bfSize; /* 說明檔案的大小,用位元組為單位 */  
	WORD bfReserved1; /* 保留,設定為0 */  
	WORD bfReserved2; /* 保留,設定為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,表示都重要。*/
} BITMAPINFOHEADER;

(3)調色盤

調色盤實際上是一個數組,它所包含的元素與點陣圖所具有的顏色數相同,決定於biClrUsedbiBitCount欄位。陣列中每個元素的型別是一個RGBQUAD結構。這部分資訊並不是所有型別的點陣圖都有,真彩色圖如24 bitBMP不需要調色盤。

typedef struct tagRGBQUAD
{
	BYTE rgbBlue; /*指定藍色分量*/
	BYTE rgbGreen; /*指定綠色分量*/
	BYTE rgbRed; /*指定紅色分量*/
	BYTE rgbReserved; /*保留,指定為0*/
} RGBQUAD;

(1)(2)(3)部分的結構體在#include<windows.h>標頭檔案中已定義。

(4)影象資料位元組陣列:即點陣圖資料。

對於用到調色盤的點陣圖,影象資料就是該畫素顏色在調色盤中的索引值(邏輯色),真彩色點陣圖如24bit BMP直接使用實際的RGB值。

2.相關重要知識點

(1) 掩碼組:

實驗過程中發現,RGB565格式的16bit點陣圖與壓縮引數biCompression=3 (BI_BITFIELDS:位域存放方式)32bit點陣圖——這兩類圖片的頭部資訊中雖然沒有偽彩色圖片的調色盤資訊,但是在調色盤的位置存在有指示RGB位元位的掩碼組資訊,為了簡化後續的程式演算法我在標頭檔案中定義了兩個代表掩碼組資料資訊的結構體如下:

//define mask struct
typedef struct bit32Mask
{
	unsigned int rgbRed;
	unsigned int rgbGreen;
	unsigned int rgbBlue;	
	unsigned int reserved;
}Mas32;
typedef struct bit16Mask
{
	unsigned int rgbRed;
	unsigned int rgbGreen;
	unsigned int rgbBlue;
}Mas16;

為了能更清楚掩碼組的作用,下面以一幅biCompression=332bit點陣圖為例,對掩碼組資訊解讀過程如下簡圖:


(2) DWORD對齊:

影象的每一掃描行由表示影象畫素的連續的位元組構成,每一行的位元組數取決於影象的顏色數目和用畫素表示的影象寬度,特別的規定每一掃描行的位元組數必須是4的倍數,即DWORD對齊方式。寫入點陣圖檔案資料時,如果影象每行畫素位元組總數[ X biBiCount % 8 != 0 ],系統會自動在每行最後填充若干0值使滿足整數字節,接著,如果[每行畫素位元組數 % 4 != 0 ]系統會自動在每行最後填充若干位元組0值使滿足DWORD對齊。所以我們對點陣圖載入處理時要注意判斷每行資料是否有0值填充,若有0值填充則從點陣圖中讀取資料的過程中要注意指標偏移量和即時跳轉。

(3)自下而上掃描:

掃描行是由底向上儲存的,:陣列中的第一個位元組表示點陣圖左下角的畫素,而最後一個位元組表示點陣圖右上角的畫素。

如下簡圖

(4) 位元組序:

計算機系統儲存資料採用的位元組序有兩種:小尾位元組序(Little Endian)和大尾位元組序(Big Endian)Intel處理器大多數採用小尾位元組序,“低位在前高位在後”,Motorola處理器大多數使用大尾位元組序,“高位在前低位在後”。

為更好地理解Little Endian的資料儲存格式,這裡以一張RGB565 16bitBMP點陣圖為例,對頭部資訊的解讀示意圖如下所示:

二、實驗流程

實驗流程圖:

演算法並不是很難,這裡僅以16bitBMP提取RGB過程作一個簡單示意圖如下:

三、具體演算法原始碼

1.BMP2YUV.h

#ifndef BMP2YUV_H_
#define BMP2YUV_H_

//define mask struct
typedef struct bit32Mask
{
	unsigned int rgbRed;
	unsigned int rgbGreen;
	unsigned int rgbBlue;	
	unsigned int reserved;
}Mas32;
typedef struct bit16Mask
{
	unsigned int rgbRed;
	unsigned int rgbGreen;
	unsigned int rgbBlue;
}Mas16;

int BMP2RGB32bit(int bitcount, int x_dim, int y_dim, void *bmpbuf, void *rgbbuf, void *mask);
int BMP2RGB24bit(int bitcount, int x_dim, int y_dim, void *bmpbuf, void *rgbbuf);
int BMP2RGB16bit(int bitcount, int x_dim, int y_dim, void *bmpbuf, void *rgbbuf,void *mask);
int BMP2RGBNOT24bit(int bitcount, int x_dim, int y_dim, void *bmpbuf, void *rgbbuf, void *pRGB);
int RGB2YUV(int x_dim, int y_dim, void *bmp, void *y_out, void *u_out, void *v_out, int flip);
void InitLookupTable();
void adjust(unsigned char *b, unsigned char *g, unsigned char *r, unsigned char *y, unsigned char *u, unsigned char  *v);
#endif

2.main.c

#include <stdio.h>
#include <stdlib.h>
#include <windows.h> 
#include <math.h> 
#include "bmp2yuv.h"

#define u_int8_t	unsigned __int8
#define u_int		unsigned __int32
#define u_int32_t	unsigned __int32

int main(int argc,char **argv)
{
	int count;
	BITMAPFILEHEADER File_header;
	BITMAPINFOHEADER Info_header;
	RGBQUAD *pRGB = NULL;
	FILE* bmp = NULL;
	FILE* yuvFile = NULL;	
	Mas16 *mask16 = NULL;
	Mas32 *mask32 = NULL;

	u_int8_t* yBuf = NULL;
	u_int8_t* uBuf = NULL;
	u_int8_t* vBuf = NULL;
	u_int8_t* rgbBuf = NULL;
	u_int8_t* bmpBuf = NULL;
	u_int8_t* mask = NULL;
	u_int frameWidth;		/* --width=<uint> */
	u_int frameHeight;
	u_int bitcount;
	u_int py;
	u_int m;
	u_int8_t i;
	int sum = 0;

	char bmpf[][50] = { "park.bmp", "tree.bmp", "girlstwo.bmp", "02.bmp", "bea.bmp", "street.bmp" };
	char yuvname[50] = "CometoYUV.yuv";
	FILE *yuv=NULL;
	int framenumber;

	/* build the RAW file */
	fopen_s(&yuv, yuvname, "wb+");
	if (yuv == NULL)
	{
		printf("Fail to Build yuv file\n");
		exit(0);
	}
	else
	{
		printf("The output rgb file is %s\n", yuvname);
		printf("\n");
		printf("-------------------------------------------------------------------------\n");
	}


	for (i = 0; i<6; i++)
	{
		
		count = 0;
		framenumber = atoi(argv[i + 1]);
		//open the bmp file
		fopen_s(&bmp, bmpf[i], "rb");
		if (!bmp)
		{
			printf("cannot find the specific file %s:\n", bmpf[i]);
			exit(0);
		}
		else
		{
			printf("The input bmp file:   %s\n", bmpf[i]);
		}
		if (!framenumber)
		{
			printf("\n寫入幀數:0\n");
			continue;
		}
		else
		{
			if (fread(&File_header, sizeof(BITMAPFILEHEADER), 1, bmp) != 1)
			{
				printf("read file header error!");
				exit(0);
			}
			if (File_header.bfType != 0x4D42)
			{
				printf("Not bmp file!");
				exit(0);
			}
			//printf("this is a 0x%04X:\n", File_header.bfType);	
			if (fread(&Info_header, sizeof(BITMAPINFOHEADER), 1, bmp) != 1)
			{
				printf("read info header error!");
				exit(0);
			}
			//	end read header
			frameWidth = Info_header.biWidth;			/* --width=<uint> */
			frameHeight = Info_header.biHeight;
			py = File_header.bfOffBits;
			bitcount = Info_header.biBitCount;
			/* get an output buffer for a frame */
			if ((frameWidth*bitcount % 8 == 0) && (frameWidth*bitcount / 8 % 4 == 0))//DWORD 對齊
			{
				yBuf = (u_int8_t*)malloc(frameWidth * frameHeight);
				uBuf = (u_int8_t*)malloc((frameWidth * frameHeight) / 4);
				vBuf = (u_int8_t*)malloc((frameWidth * frameHeight) / 4);

				/* get an input buffer for a frame */
				bmpBuf = (u_int8_t*)malloc(frameWidth * frameHeight * bitcount / 8);

				/* get an output buffer for a frame */
				rgbBuf = (u_int8_t*)malloc(frameWidth * frameHeight * 3);				

				if (rgbBuf == NULL || yBuf == NULL || uBuf == NULL || vBuf == NULL || bmpBuf == NULL)
				{
					printf("no enought memory\n");
					exit(1);
				}

				////////////////////////////////BMP 2 RGB
				while (framenumber)
				{
					fseek(bmp, py, SEEK_SET);
					if (!fread(bmpBuf, 1, frameWidth * frameHeight * bitcount / 8, bmp))
					{
						printf("the image has problems!");
						return 0;
					}
					if (bitcount == 32)
					{
						if (Info_header.biCompression==0)
						{ 
							if (BMP2RGB32bit(bitcount, frameWidth, frameHeight, bmpBuf, rgbBuf,0))
							{
								printf("32bit BMP2RGB program runs error!");
								return 0;
							}						
						}
						else if (Info_header.biCompression == 3)
						{
							//取掩碼組
							m = 4*4;
							mask32 = (Mas32*)malloc(sizeof(Mas32));
							fseek(bmp, sizeof(BITMAPFILEHEADER) + Info_header.biSize - m, SEEK_SET);
							fread(mask32, sizeof(Mas32),1, bmp);
							if (BMP2RGB32bit(bitcount, frameWidth, frameHeight, bmpBuf, rgbBuf, mask32))
							{
								printf("32bit BMP2RGB program runs error!");
								return 0;
							}
						}
					}
					else if (bitcount == 24)
					{//真彩點陣圖
						if (BMP2RGB24bit(bitcount, frameWidth, frameHeight, bmpBuf, rgbBuf))
						{
							printf("24bit BMP2RGB program runs error!");
							return 0;
						}
					}
					else if (bitcount == 16)
					{						
						//16bit BMP RGB位元位根據biCompression確定
						if (Info_header.biCompression == 0)//555
						{
							if (BMP2RGB16bit(bitcount, frameWidth, frameHeight, bmpBuf, rgbBuf, 0))
							{
								printf("16bit BMP2RGB program runs error!");
								return 0;
							}
						}
						else if (Info_header.biCompression == 3)
						{
							//取掩碼組
							m = 4 * 3;
							mask16 = (Mas16*)malloc(sizeof(Mas16));
							fseek(bmp, py-m, SEEK_SET);
							fread(mask16, 1, m, bmp);							
							if (BMP2RGB16bit(bitcount, frameWidth, frameHeight, bmpBuf, rgbBuf, mask16))
							{
								printf("16bit BMP2RGB program runs error!");
								return 0;
							}
						}						
					}
					else
					{						
						if ((py - sizeof(BITMAPFILEHEADER) - Info_header.biSize) == sizeof(RGBQUAD)*pow(2, bitcount))
						{//1、2、4、8 bit 有調色盤部分
							m = (unsigned int)pow(2, bitcount);
							pRGB = (RGBQUAD *)malloc(sizeof(RGBQUAD)*m);
							fseek(bmp, sizeof(BITMAPFILEHEADER) + Info_header.biSize, SEEK_SET);
							fread(pRGB, sizeof(RGBQUAD), m, bmp);
							if (BMP2RGBNOT24bit(bitcount, frameWidth, frameHeight, bmpBuf, rgbBuf, pRGB))
							{
								printf("BMP 2 RGB program runs error!");
								return 0;
							}
						}						
					}
					/////////////////////////////RGB2YUV
					if (RGB2YUV(frameWidth, frameHeight, rgbBuf, yBuf, uBuf, vBuf, 0/*flip=0*/))//bmp影象格式從最後一行起逐行掃描
					{
						printf("RGB2YUV program runs error!");
						return 0;
					}
					fwrite(yBuf, 1, frameWidth * frameHeight, yuv);
					fwrite(uBuf, 1, (frameWidth * frameHeight) / 4, yuv);
					fwrite(vBuf, 1, (frameWidth * frameHeight) / 4, yuv);

					printf("\r...%d", ++count);
					framenumber--;
				}
				printf("\n寫入幀數:%u   %ux%u(%d bit)\n", count, frameWidth, frameHeight, bitcount);
				sum += count;
				printf("\n");
				printf("\n");
			}
		}				
	}
	printf("%d幀YUV寫入成功!\n",sum);

	/* cleanup */
	fclose(bmp);
	fclose(yuv);
	//free the memory   
	if (yBuf)	{ free(yBuf); }
	if (uBuf)	{ free(uBuf); }
	if (vBuf)	{ free(vBuf); }
	if (rgbBuf)	{ free(rgbBuf); }
	if (bmpBuf)	{ free(bmpBuf); }
	if (pRGB)	{ free(pRGB); }
	if (mask16)	{ free(mask16); }
	if (mask32)  { free(mask32); }
	return 0;
}

3.BMP2RGB.c

#include "stdlib.h"
#include "bmp2yuv.h"
#include <windows.h> 
#include <math.h> 

int BMP2RGB32bit(int bitcount, int x_dim, int y_dim, void *bmpbuf, void *rgbbuf, void *mask)
{
	long i;
	unsigned char *bmp, *rgb;
	Mas32 *mas;
	long size = x_dim*y_dim;
	bmp = (unsigned char *)bmpbuf;
	rgb = (unsigned char *)rgbbuf;
	mas = (Mas32 *)mask;

	if (mask == NULL)
	{
		for (i = 0; i < size; i++)
		{
			*(rgb + 0) = *(bmp + 0);
			*(rgb + 1) = *(bmp + 1);
			*(rgb + 2) = *(bmp + 2);
			rgb += 3;
			bmp += 4;
		}
		return 0;
	}
	else
	{//根據掩碼確定RGB位元位
		int Gkey, Bkey, Rkey;
		if (mas->rgbGreen == 0)
			Gkey= 0;
		else if (mas->rgbGreen == 0xFF000000)
			Gkey = 3;
		else if (mas->rgbGreen == 0xFF0000)
			Gkey = 2;
		else if (mas->rgbGreen == 0xFF00)
			Gkey = 1;
		else
			return 1;
		
		if (mas->rgbBlue == 0)
		   Bkey = 0;
		else if (mas->rgbBlue == 0xFF000000)
			Bkey = 3;
		else if (mas->rgbBlue == 0xFF0000)
			Bkey = 2;
		else if (mas->rgbBlue == 0xFF00)
			Bkey = 1;
		else
			return 1;

		if (mas->rgbRed == 0)
			Rkey = 0;
		else if (mas->rgbRed == 0xFF000000)
			Rkey = 3;
		else if (mas->rgbRed == 0xFF0000)
			Rkey = 2;
		else if (mas->rgbRed == 0xFF00)
			Rkey = 1;
		else
			return 1;

		for (i = 0; i < size; i++)
		{
			*(rgb + 0) = *(bmp + Bkey);
			*(rgb + 1) = *(bmp + Gkey);
			*(rgb + 2) = *(bmp + Rkey);
			rgb += 3;
			bmp += 4;
		}
		return 0;
	}
	
}

int BMP2RGB24bit(int bitcount, int x_dim, int y_dim, void *bmpbuf, void *rgbbuf)
{
	long i;
	unsigned char *rgb;// , *raw;
	unsigned char *bmp;
	long size = x_dim*y_dim;
	rgb = (unsigned char *)rgbbuf;
	bmp = (unsigned char *)bmpbuf;
	for (i = 0; i < size*3; i++)
	{
		*(rgb + i) = *(bmp + i);
	}
	return 0;
}
int BMP2RGB16bit(int bitcount, int x_dim, int y_dim, void *bmpbuf, void *rgbbuf, void *mask)
{
	long loop;
	unsigned char *Data, *rgbDataOut;
	long size = x_dim*y_dim*bitcount / 8;
	Data = (unsigned char*)bmpbuf;
	rgbDataOut = (unsigned char*)rgbbuf;
	Mas16 *mas;
	mas = (Mas16 *)mask;

	if (mask == NULL)
	{
		for (loop = 0; loop < size; loop += 2)
		{
			*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;
		}
	}
	else//555 OR 565決定於rgbGreen的位元位
	{
		if (mas->rgbGreen == 0x07E0)
		{
			for (loop = 0; loop < size; loop += 2)
			{
				*rgbDataOut = (*(Data + loop) & 0x1F) << 3;
				*(rgbDataOut + 1) = ((*(Data + loop) & 0xE0) >> 3) + ((*(Data + loop + 1) & 0x07) << 5);
				*(rgbDataOut + 2) = (*(Data + loop + 1) & 0xF8);
				rgbDataOut += 3;
			}
		}
		else
		{
			for (loop = 0; loop < size; loop += 2)
			{
				*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;
			}
		}
	}
	return 0;
}
int BMP2RGBNOT24bit(int bitcount, int x_dim, int y_dim, void *bmpbuf, void *rgbbuf, void *ppRGB)//1\4\8 bit BMP
{
	unsigned char *rgb;
	unsigned char *bmp;
	unsigned char index;
	
	bmp = (unsigned char *)bmpbuf;
	rgb = (unsigned char *)rgbbuf;

	int shiftCnt;
	unsigned char mask;

	long loop = 0;
	unsigned char *Data, *rgbDataOut;
	RGBQUAD* p;

	long size = x_dim*y_dim*bitcount/8;
	Data = (unsigned char*)bmpbuf;
	rgbDataOut = (unsigned char*)rgbbuf;
	p = (RGBQUAD*)ppRGB;
	for (loop = 0; loop<size; loop++)
	{
		shiftCnt = 1;
		mask = (unsigned char)pow(2, bitcount) - 1;
		mask = mask << (8-bitcount);
		while (mask)
		{
			//索引號的確定
			index = (mask == 0xFF) ? *(Data + loop) : (*(Data + loop) & mask) >> (8 - shiftCnt * bitcount);
			*rgbDataOut = (p + index)->rgbBlue;
			*(rgbDataOut + 1) = (p + index)->rgbGreen;
			*(rgbDataOut + 2) = (p + index)->rgbRed;
			if (bitcount == 8)
				mask = 0;
			else
				mask >>= bitcount;
			rgbDataOut += 3;
			shiftCnt++;
		}
	}
	return 0;
}

4.RGB2YUV.c

#include "stdlib.h"
#include "bmp2yuv.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;
				adjust(b, g, r, y, u, v);
				b += 3;
				y ++;
				u ++;
				v ++;
			}
		}
	} else {
		for (i = 0; i < size; i++)
		{
			g = b + 1;
			r = b + 2;			
			adjust(b, g, r, y, u,v);
			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;
}

void adjust(unsigned char *b, unsigned char *g, unsigned char *r, unsigned char *y, unsigned char *u, unsigned char  *v)
{
	float temp = 0;
	temp = (float)(RGBYUV02990[*r] + RGBYUV05870[*g] + RGBYUV01140[*b]);
	temp = temp>235 ? 235 : temp;
	temp = temp<16 ? 16 : temp;
	*y = (unsigned char)temp;

	temp = (float)(-RGBYUV01684[*r] - RGBYUV03316[*g] + (*b) / 2 + 128);
	temp = temp>240 ? 240 : temp;
	temp = temp<16 ? 16 : temp;
	*u = (unsigned char)temp;

	temp = (float)((*r) / 2 - RGBYUV04187[*g] - RGBYUV00813[*b] + 128);
	temp = temp>240 ? 240 : temp;
	temp = temp<16 ? 16 : temp;
	*v = (unsigned char)temp;
}

四、實驗結果

根據實驗指導書要求:生成帶有個人logo的多張bmp圖片(測試程式使用6幅圖片),程式執行時可在命令列中設定每個畫面出現的幀數,最後形成的YUV檔案不少於200幀。

測試圖片原始檔均來自網路,後續測試中所用的1481632bit點陣圖是利用畫圖板/PS軟體由原圖轉換得到。

由命令列設定每幅圖片播放幀數:

程式執行結果如下圖所示:

生成的YUV檔案取其中六幀截圖如下:對於148 bit顏色深度的BMP點陣圖到明顯顏色內容的失真。

五、實驗總結

緩衝區分配、結構體操作、倒序讀寫檔案、函式定義等操作是這次實驗應該重點掌握的內容。