数据压缩学习实验(二)BMP文件读取及转换至YUV色彩空间的C++实现

实验目的

  1. 熟悉BMP文件结构,进一步学习多媒体文件结构设计的思想。
  2. 编程读取BMP文件,要求程序可以处理1、2、4、8、24、32bit色深。
  3. 实践RGB与YUV色彩空间的转换,将BMP文件转换至YUV色彩空间。

实验原理

RGB与YUV空间的相互转换:

由电视原理可知,亮度和色差信号的构成如下:

Y=0.2990R+0.5870G+0.1140B

R-Y=0.7010R-0.5870G-0.1140B

B-Y=-0.2990R-0.5870G+0.8860B

为了使色差信号的动态范围控制在0.5之间,需要进行归一化,对色差信号引入压缩

系数。归一化后的色差信号为:

U=-0.1684R-0.3316G+0.5B

V=0.5R-0.4187G-0.0813B

码电平分配:

在对亮度分量信号进行8比特均匀量化时,共分为256个等间隔的量化级。为了防止信号变动造成过载,在256级上端留20级,下端留16级作为信号超越动态范围的保护带。色差信号经过归一化处理后,动态范围为-0.5-0.5,让色差零电平对应码电平128,色差信号总共占225个量化级。在256级上端留15级,下端留16级作为信号超越动态范围的保护带。

色度格式:

在数字电视中,对亮度信号和两个色差信号的分量信号有以 下几种取样格式:

• 4:4:4:表示RGB取样,RGB信号的取样点数量一样。

• 4:2:2:色差信号U和V在水平方向取样点数为Y的二分之一,而垂直方向取样点数与Y相同。

• 4:2:0:色差信号U和V在水平和垂直方向的取样点数均为Y的二分之一。

• 4:1:1:色差信号Cr和Cb在水平方向取样点数为Y的四分之一,而 垂直方向取样点数与Y相同。

本次实验中采用4:2:0色度取样格式。
实验中,程序调用easyx绘图库实现对图像的显示。

BMP文件读取

BMP文件结构

其中:

  1. bmp文件头定义如下:
typedef struct tagBITMAPFILEHEADER {
WORD         bfType;
DWORD      bfSize;
WORD         bfReserved1;
WORD         bfReserved2;
DWORD      bfOffBits;
} BITMAPFILEHEADER;
名称数据类型说明
bfTypeWORD说明文件的类型
bfSizeDWORD说明文件的大小,用字节为单位
bfReserved1WORD保留,设置为0
bfReserved2WORD保留,设置为0
bfOffBitsDWORD说明从BITMAPFILEHEADER结构 开始到实际的图像数据之间的字节偏移量
  1. 位图信息头定义如下:
typedef struct tagBITMAPINFOHEADER {
DWORD    biSize;
LONG        biWidth;
LONG        biHeight;
WORD       biPlanes;
WORD       biBitCount;
DWORD    biCompression;
DWORD    biSizeImage;
LONG        biXPelsPerMeter;
LONG        biYPelsPerMeter;
DWORD    biClrUsed;
DWORD    biClrImportant;
}  BITMAPINFOHEADER;
名称数据类型说明
biSizeDWORD说明结构体所需字节数
biWidthLONG以像素为单位说明图像的宽度
biHeightLONG以像素为单位说明图像的高度
biPlanesWORD说明位面数,必须为1
biBitCountWORD说明位数/像素,1、2、4、8、24
biCompressionDWORD说明图像是否压缩及压缩类型 BI_RGB,BI_RLE8,BI_RLE4,BI_BITFIELDS
biSizeImageDWORD以字节为单位说明图像大小,必须是4的整数倍,当用BI_RGB格式时,可以设置为0
biXPelsPerMeterLONG目标设备的水平分辨率,像素/米
biYPelsPerMeterLONG目标设备的垂直分辨率,像素/米
biClrUsedDWORD说明图像实际用到的颜色数,如果为0 则颜色数为2的biBitCount次方
biClrImportantDWORD说明对图像显示有重要影响的颜色 索引的数目,如果是0,表示都重要。
  1. 调色板信息如下 :
typedef struct tagRGBQUAD {
BYTE    rgbBlue;           /\*指定蓝色分量\*/
BYTE    rgbGreen;        /\*指定绿色分量\*/
BYTE    rgbRed;            /\*指定红色分量\*/
BYTE    rgbReserved;   /\*保留,指定为0\*/
}  RGBQUAD;

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

  1. 关于位图数据的说明:

Windows默认的扫描的最小单位是4字节,因此在BMP图像中要求每行的数据的长度必须是4的倍数,如果不够需要进行比特填充(默认为0)。

当biHeight为正数时,扫描行是由底向上存储的,这就是说,阵列中的第一个字节 表示位图左下角的像素,而最后一个字节表示位图右上角的像素;否则为正向存储。

每行数据量计算公式如下:

row_size = ((DWORD)(width * depth + 31) >> 5) << 2;

实验素材

1bit、4bit、8bit及24bit BMP位图图像:
1bit
4bit
8bit
24bit
8bit大尺寸图片:
8bit

转换至YUV420采样的图像(24bit):
24bit

实验结果

BMP文件读取

1bit文件读取结果
在这里插入图片描述
4bit文件读取结果
在这里插入图片描述
8bit文件读取结果
在这里插入图片描述
24bit文件读取结果
在这里插入图片描述
8bit大尺寸图片读取结果
在这里插入图片描述
转换用24bit图片读取结果
在这里插入图片描述

转换至YUV色彩空间后结果

在这里插入图片描述

误差分析

造成色彩空间转换的误差来源有:

  1. 1、计算误差,由上文转换公式可知,直接计算后的结果是一个浮点型数据,但实际存储和表示图片像素都是使用的8bit unsigned char型数据,舍弃小数点后小数造成误差。
  2. 2、保护边带造成的误差,在实际计算中YUV数据都会进入保护边带内,但根据转换要求需要将进入边带的数值更改为边界值,因此造成了转换误差。
  3. 3、色度采样误差,由于采用4:2:0色度采样格式,每四个像素共用一个色度采样值,因此导致了一部分色度信息的丢失,转换回RGB色彩空间时导致误差。

关于rgb色彩空间与yuv色彩空间更详细的转换误差分析如下:
数据压缩学习实验(一)RGB与YUV色彩空间转换的C++实现及误差分析

一些笔记

  1. 1、biSizeImage当用BI_RGB格式时,可以设置为0,一开始编程时在程序中使用这个数据,读取某些为0的图片时报错。实际数据大小需要计算。
  2. 2、文件储存顺序问题,bitmap文件采用little-endian顺序储存,即多字节数据低字节存放在低位地址,高字节存放在高位地址。
  3. 3、读取文件中某比特尝试过多种方法,目前认为较为简单的是先将数据根据位数位移到低位,再与上相应的数据(如取后四位就与0x15,二进制00001111),这样再读取不同色深时较为灵活。
  4. 4、读取4个小图像时上下行颜色不对,但读取其它图片时无此问题,原因尚未查明。

程序代码

bmp_file.h

#include<windows.h>
#pragma once
#ifndef qqq
#define qqq
typedef unsigned char uint1;
typedef unsigned short uint2;
typedef unsigned int uint4;
typedef int int4;
class BMP {
#pragma(push)
#pragma(2)
private:
	BITMAPFILEHEADER header;
	BITMAPINFOHEADER info;
	uint4 color_table_size;
	RGBQUAD* color_table;
	uint4 data_size;
	uint1* data;

	float Byte_per_pixel;
	int depth;
	int width;
	int height;
	int row_size;

	bool create(uint4 w, uint4 h);
	bool read(const char* path);
	uint4 calculate_index(uint4 w, uint4 h);
#pragma(pop)
public:
	explicit BMP(uint4 w, uint4 h);
	explicit BMP(const char* path);
	~BMP();
	RGBTRIPLE* get_pixel(uint4 x, uint4 y);
	int get_width();
	int get_height();
	uint2 get_depth();
	uint1* get_data();
	void show();
};
#endif // !qqq

bmp_file.cpp

#include "BMP_file.h"
#include <Windows.h>
#include <easyx.h>
#include <conio.h>
#include <iostream>
#include <fstream>
using namespace std;

bool BMP::create(uint4 w, uint4 h)
{
	Byte_per_pixel = 3;
	width = w;
	height = h;
	depth = 24;
	row_size = ((width * depth + 31) >> 5) << 2;
	data_size = height * row_size * 3;
	header.bfType = 19778;
	header.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
	header.bfReserved1 = 0;
	header.bfReserved2 = 0;
	header.bfSize = header.bfOffBits + w * h;
	info.biSize = sizeof(BITMAPINFOHEADER);
	info.biWidth = width;
	info.biHeight = height;
	info.biPlanes = 1;
	info.biBitCount = 24;
	info.biCompression = 0;
	info.biSizeImage = height * row_size;
	info.biXPelsPerMeter = 128;
	info.biYPelsPerMeter = 128;
	info.biClrUsed = 0;
	info.biClrImportant = 0;
	color_table_size = 0;
	color_table = nullptr;
	data = new uint1[data_size];
	if (data == nullptr) {
		cerr << __func__ << "()\tCan not get memory!" << endl;
		return false;
	}
	else {
		return true;
	}
}

bool BMP::read(const char* path)
{
	ifstream file_in(path, ios::binary);
	if (!file_in.is_open()) {
		cerr << __func__ << "\t Can not open file: " << path << endl;
		return false;
	}
	file_in.read(reinterpret_cast<char*>(&header), sizeof(BITMAPFILEHEADER));
	if (header.bfType != 19778) {
		cerr << __func__ << "\t Not a bitmap file!" << endl;
		return false;
	}
	file_in.read(reinterpret_cast<char*>(&info), sizeof(BITMAPINFOHEADER));
	width = info.biWidth;
	height = info.biHeight;
	depth = info.biBitCount;
	switch (depth)
	{
	case(24): {
		Byte_per_pixel = 3;
	}break;
	case(32): {
		Byte_per_pixel = 4;
	}break;
	case(8): {
		Byte_per_pixel = 1;
	}break;
	case(4): {
		Byte_per_pixel = 0.5;
	}break;
	case(2): {
		Byte_per_pixel = 0.25;
	}break;
	case(1): {
		Byte_per_pixel = 0.125;
	}break;
	default: {
		cerr << __func__ << "()\tInvalid depth!" << endl;
		return false;
	}
	}
	/*calculate the pixels per line that number must be int*4 */
	row_size = ((uint4)(width * depth + 31) >> 5) << 2;
	data_size = width * height * Byte_per_pixel; //can not use biBitCount, maybe = 0
	if (header.bfOffBits < 54) {
		cerr << __func__ << "()\tInvalid offbits!" << endl;
		return false;
	}
	else if (header.bfOffBits == 54) {
		color_table_size = 0;
		color_table = nullptr;
	}
	else {
		color_table_size = (header.bfOffBits - 54) / 4;
		color_table = new RGBQUAD[color_table_size];
		if (color_table == nullptr) {
			cerr << __func__ << "()\tCan not get memory!" << endl;
			return false;
		}
		file_in.read(reinterpret_cast<char*>(color_table), color_table_size * 4);
	}
	data = new uint1[data_size];
	if (data == nullptr) {
		cerr << __func__ << "()\tCan not get memory!" << endl;
		return false;
	}
	file_in.read(reinterpret_cast<char*>(data), data_size);
	file_in.close();
}

uint4 BMP::calculate_index(uint4 w, uint4 h)
{
	/*return the number of bytes, include all cases of depth*/
	uint4 index(0);
	if (height > 0) {
		index = (height - h - 1) * row_size + (uint4)(w * Byte_per_pixel);
	}
	else {
		index = h * row_size + (uint4)(w * Byte_per_pixel);
	}
	return index;
}

BMP::BMP(uint4 w, uint4 h)
{
	if (!create(w, h)) {
		system("pause");
		exit(1);
	}

}

BMP::BMP(const char* path)
{
	read(path);
}

BMP::~BMP()
{
	closegraph();
	if (color_table != nullptr) {
		delete[] color_table;
	}
	if (data != nullptr) {
		delete[] data;
	}
}

RGBTRIPLE* BMP::get_pixel(uint4 x, uint4 y)
{
	if (x >= width || y >= height) {
		cerr << __func__ << "\tInvalid position!" << endl;
		return nullptr;
	}
	uint4 index = calculate_index(x, y);
	uint1 pixel;
	switch (depth)
	{
	case(32):
	case(24): {
		uint1* dat;
		dat = data + index;
		return reinterpret_cast<RGBTRIPLE*>(data + index);
	}break;
	case(8): {
		pixel = *(data + index);
		return reinterpret_cast<RGBTRIPLE*>(color_table + pixel);
	}break;
	case(4): {
		pixel = (*(data + index) >> 4 * (1 - (x % 2))) & 15;  // move 4 bits to the end and extract them
		return reinterpret_cast<RGBTRIPLE*>(color_table + pixel);
	}break;
	case(2): {
		pixel = (*(data + index) >> 2 * (1 - (x % 4))) & 3;  // move 2 bits to the end and extract them
		return reinterpret_cast<RGBTRIPLE*>(color_table + pixel);
	}break;
	case(1): {
		pixel = (*(data + index) >> (7 - (x % 8))) & 1;  // move 1 bits to the end and extract them
		return reinterpret_cast<RGBTRIPLE*>(color_table + pixel);
	}break;
	default: {
		cerr << __func__ << "\tThe depth may is 16bits (555 or 565) which can't be read!" << endl;
		return nullptr;
	}
	}
	
}

int BMP::get_width()
{
	return width;
}

int BMP::get_height()
{
	return height;
}

uint2 BMP::get_depth()
{
	return depth;
}

uint1* BMP::get_data()
{
	return this->data;
}

void BMP::show( ) 
{
	initgraph(width, height, SHOWCONSOLE);
	cout << "loading..." << endl;
	RGBTRIPLE* bgr;
	for (int i = 0; i < height; i++) {
		for (int j = 0; j < width; j++) {
			bgr = this->get_pixel(j, i);
			putpixel(j, i, RGB(bgr->rgbtRed, bgr->rgbtGreen, bgr->rgbtBlue));
		}
	}
	cout << "complete!" << endl;
}

YUV_raw.h

#ifndef YUV_img
#define YUV_img
#pragma once

typedef unsigned char uint1;
typedef unsigned short uint2;
typedef unsigned int uint4;
typedef int int4;

#pragma pack(push)
#pragma pack(2)

typedef struct {
	uint1* Y_data;
	uint1* U_data;
	uint1* V_data;
}YUV_per_frame, YUV;

enum chrominace_mode { C444, C422, C420, C411 };

class YUV_raw_image {
protected:
	uint4 width;
	uint4 height;
	chrominace_mode mode;
	uint4 C_width;  //width of chrominace
	uint4 C_height;  //height of chrominace
	uint4 frame_rate;
	uint4 frame_num;
	uint4 frame_size;
	uint4 frame_Y_size;
	uint4 frame_U_size;
	uint4 frame_V_size;
	YUV_per_frame* data;

#pragma pack(pop)
public:
	explicit YUV_raw_image(uint2 w, uint2 h, uint2 f_rate, chrominace_mode m, uint4 num = 1);
	explicit YUV_raw_image(uint2 w, uint2 h, uint2 f_rate, chrominace_mode m, const char* filePath);
	virtual ~YUV_raw_image();
	void init(uint2 w, uint2 h, uint2 f_rate, chrominace_mode m);
	bool read_frame(const char* filePath);
	bool save(const char* filePath);
	uint2 get_width();
	uint2 get_height();
	chrominace_mode get_mode();
	YUV get_pixel(uint2 w, uint2 h, uint4 f = 0);
	YUV* get_data(uint4 f = 0);
};
#endif

YUV_raw.cpp

#include "YUV_raw.h"
#include <iostream>
#include <fstream>
using namespace std;

YUV_raw_image::YUV_raw_image(uint2 w, uint2 h, uint2 f_rate, chrominace_mode m, uint4 num)
{
	init(w,h,f_rate,m);
	frame_num = num;
	data = new YUV_per_frame[frame_num];
	for (int i = 0; i < frame_num; i++) {
		uint1* ptr = new uint1[frame_size]{ 0 };//set values of pixel to 0
		(data + i)->Y_data = ptr;  
		(data + i)->U_data = ptr + frame_Y_size;
		(data + i)->V_data = ptr + frame_Y_size + frame_U_size;
	}
}

YUV_raw_image::YUV_raw_image(uint2 w, uint2 h, uint2 f_rate, chrominace_mode m, const char* filePath)
{
	init(w, h, f_rate, m);
	try {
		if (!read_frame(filePath)) {
			throw ("Failed to create object\n");
		}
	}
	catch (const char* msg) {
		cerr << msg << endl;
		system("pause");
		exit(114514);
	}
}

YUV_raw_image::~YUV_raw_image()
{
	for (int i = 0; i < frame_num; i++) {
		delete[](data + i)->Y_data;
	}
	delete[] data;
}

void YUV_raw_image::init(uint2 w, uint2 h, uint2 f_rate, chrominace_mode m)
{
	width = w;
	height = h;
	mode = m;
	frame_rate = f_rate;
	switch (mode) {
	case(C444): {
		C_width = width;
		C_height = height;
	}break;
	case(C422): {
		C_width = (uint2)(width / 2);
		C_height = height;
	}break;
	case(C420): {
		C_width = (uint2)(width / 2);
		C_height = (uint2)(height / 2);
	}break;
	case(C411): {
		C_width = (uint2)(width / 4);
		C_height = height;
	}break;
	}
	frame_Y_size = width * height;
	frame_U_size = C_width * C_height;
	frame_V_size = C_width * C_height;
	frame_size = frame_Y_size + frame_U_size + frame_V_size;
}

bool YUV_raw_image::read_frame(const char* filePath)
{
	std::ifstream file_in(filePath, ios::binary); //ios::binary means open a binary file.
	if (file_in.is_open()) {
		/*obtain the address of feader, then convert it into buffer which point to type char*/
		/*the order of data in struct BMPFileHeader should be same as it's in files*/

		istream::pos_type start_pos = file_in.tellg();
		file_in.seekg(0, ios_base::end);
		istream::pos_type end_pos = file_in.tellg();
		file_in.seekg(start_pos);
		istream::pos_type file_size = end_pos - start_pos;

		if ((file_size % frame_size) != 0) {
			cout << "The file is not entire!" << endl;
			return false;
		}
		else {
			frame_num = file_size / frame_size;
		}

		data = new YUV_per_frame[frame_num];
		for (int i = 0; i < frame_num; i++) {
			uint1* ptr = new uint1[frame_size];
			file_in.read((char*)ptr, frame_size);
			(data + i)->Y_data = ptr;  //set values of pixel to 0
			(data + i)->U_data = ptr + frame_Y_size;
			(data + i)->V_data = ptr + frame_Y_size + frame_U_size;
		}

		file_in.close();
		cout << "Read finished!" << endl;
		cout << "The number of frame is " << frame_num << endl;
		return true;
	}
	else {
		cout << __func__ << "Failed to open input file" << filePath << endl;
		return false;
	}
}

bool YUV_raw_image::save(const char* filePath)
{
	YUV_per_frame* p = data;
	std::ofstream file_out(filePath, ios::binary); //ios::binary means open a binary file.
	if (file_out.is_open()) {
		for (int i = 0; i < frame_num; i++, p++) {
			file_out.write((char*)p->Y_data, frame_Y_size);
			file_out.write((char*)p->U_data, frame_U_size);
			file_out.write((char*)p->V_data, frame_V_size);
		}
		file_out.close();
		return true;
	}
	else {
		cout << __func__ << "Failed to open output file" << filePath << endl;
		return false;
	}
}

uint2 YUV_raw_image::get_width()
{
	return width;
}

uint2 YUV_raw_image::get_height()
{
	return height;
}

chrominace_mode YUV_raw_image::get_mode()
{
	return mode;
}

YUV YUV_raw_image::get_pixel(uint2 w, uint2 h, uint4 f)
{
	uint1* y(nullptr);
	uint1* u(nullptr);
	uint1* v(nullptr);
	uint2 index_x(0), index_y(0);
	switch (mode) {
	case(C444): {
		index_x = w;
		index_y = h;
	}break;
	case(C422): {
		index_x = (uint2)(w / 2);
		index_y = h;
	}break;
	case(C420): {
		index_x = (uint2)(w / 2);
		index_y = (uint2)(h / 2);
	}break;
	case(C411): {
		C_width = (uint2)(w / 4);
		C_height = height;
	}break;
	}
	if (f < frame_num && w < width && h < height) {
		y = ((data + f)->Y_data) + (index_y * width + index_x);
		u = ((data + f)->U_data) + (index_y * C_width + index_x);
		v = ((data + f)->V_data) + (index_y * C_width + index_x);
	}
	return YUV{ y,u,v };
}

YUV* YUV_raw_image::get_data(uint4 f)
{
	return data + f;
}

converter.h

#ifndef tr
#define tr
#include "BMP_file.h"
#include "YUV_raw.h"

void init_LookupTable();
uint1 clamp_Y(int t);
uint1 clamp_UV(int t);
uint1 clamp_RGB(int t);
bool bmp2yuv(BMP &img, YUV_raw_image& yuv, uint4 frame = 0);

#endif

converter.cpp

#include "converter.h"
#include <iostream>
#include <fstream>
using namespace std;

static uint1 RGBYUV02290[256];
static uint1 RGBYUV05870[256];
static uint1 RGBYUV01140[256];
static uint1 RGBYUV01684[256];
static uint1 RGBYUV03316[256];
static uint1 RGBYUV05000[256];
static uint1 RGBYUV04187[256];
static uint1 RGBYUV00813[256];
static int YUVRGB14020[256];
static int YUVRGB07141[256];
static int YUVRGB03144[256];
static int YUVRGB17720[256];
static bool init_flg = false;

void init_LookupTable()
{
	if (init_flg == false) {
		for (int i = 0; i < 256; i++) {
			RGBYUV02290[i] = (float)i * 0.299;
			RGBYUV05870[i] = (float)i * 0.587;
			RGBYUV01140[i] = (float)i * 0.114;
			RGBYUV01684[i] = (float)i * 0.1684;
			RGBYUV03316[i] = (float)i * 0.3316;
			RGBYUV05000[i] = (float)i * 0.5;
			RGBYUV04187[i] = (float)i * 0.4187;
			RGBYUV00813[i] = (float)i * 0.0813;
			YUVRGB14020[i] = (float)(i - 128) * 1.402;
			YUVRGB07141[i] = (float)(i - 128) * 0.71414;
			YUVRGB03144[i] = (float)(i - 128) * 0.314414;
			YUVRGB17720[i] = (float)(i - 128) * 1.772;
		}
		init_flg = true;
	}
}

uint1 clamp_Y(int t)
{
	if (t < 16) {
		return 16;
	}
	else if (t > 235) {
		return 235;
	}
	else {
		return t;
	}
}

uint1 clamp_UV(int t)
{
	if (t < 16) {
		return 16;
	}
	else if (t > 240) {
		return 240;
	}
	else {
		return t;
	}
}

uint1 clamp_RGB(int t)
{
	if (t < 0) {
		return 0;
	}
	else if (t > 255) {
		return 255;
	}
	else {
		return t;
	}
}

bool bmp2yuv(BMP& img, YUV_raw_image& yuv, uint4 frame)
{
	if (init_flg == false) {
		init_LookupTable();
	}
	int width = img.get_width();
	int height = img.get_height();
	chrominace_mode mode = yuv.get_mode();
	if (yuv.get_width() != width || yuv.get_height() != height) {
		cerr << __func__ << "\t The size of yuv file doesn\t match with bmp!" << endl;
		return false;
	}
	int y, u, v;
	RGBTRIPLE* bgr_data;
	YUV* yuv_data = yuv.get_data();
	/*loop to traverse all pixels*/
	int loop_y(0), loop_uv(0);
	for (int loop_i = 0; loop_i < height; loop_i++) {
		for (int loop_j = 0; loop_j < width; loop_j++) {
			bgr_data = img.get_pixel(loop_j, loop_i);
			y = RGBYUV02290[bgr_data->rgbtRed] + RGBYUV05870[bgr_data->rgbtGreen]
				+ RGBYUV01140[bgr_data->rgbtBlue];
			u = RGBYUV05000[bgr_data->rgbtBlue] - RGBYUV01684[bgr_data->rgbtRed]
				- RGBYUV03316[bgr_data->rgbtGreen] + 128;
			v = RGBYUV05000[bgr_data->rgbtRed] - RGBYUV04187[bgr_data->rgbtGreen]
				- RGBYUV00813[bgr_data->rgbtBlue] + 128;
			y = clamp_Y(y);
			u = clamp_UV(u);
			v = clamp_UV(v);
			switch (mode)
			{
			case(C444): {
				*(yuv_data->Y_data + loop_y) = y;
				*(yuv_data->U_data + loop_y) = u;
				*(yuv_data->V_data + loop_y) = v;
			}break;
			case(C422): {
				*(yuv_data->Y_data + loop_y) = y;
				if (loop_y % 2 == 0) {
					*(yuv_data->U_data + loop_uv) = u;
					*(yuv_data->V_data + loop_uv) = v;
					loop_uv++;
				}
			}break;
			case(C420): {
				*(yuv_data->Y_data + loop_y) = y;
				if ((loop_y % 2 == 0) && (((loop_y - (loop_y % width)) / width) % 2 == 0)) {
					/*this condition means the position of chrominace sample*/
					*(yuv_data->U_data + loop_uv) = u;
					*(yuv_data->V_data + loop_uv) = v;
					loop_uv++;
				}
			}break;
			case(C411): {
				*(yuv_data->Y_data + loop_y) = y;
				if (loop_y % 4 == 0) {
					*(yuv_data->U_data + loop_uv) = u;
					*(yuv_data->V_data + loop_uv) = v;
					loop_uv++;
				}
			}break;
			}
			loop_y++;  //Important!!!!!!!!!!!!!!!!
		}
	}
	return true;
}

main.cpp

#include"BMP_file.h"
#include"YUV_raw.h"
#include"converter.h"
#include<windows.h>
#include<iostream>
using namespace std;

void process(BMP& img);

int main(int argc, char** argv)
{
	BMP img(argv[1]);
	img.show();
	process(img);
	system("Pause");
	return 0;
}

void process(BMP& img)
{
	int width = img.get_width();
	int height = img.get_height();
	chrominace_mode m = C420;
	YUV_raw_image yuv_img(width, height, 1, m);
	bmp2yuv(img, yuv_img);
	yuv_img.save("./result.yuv");
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值