YUV2RGB实验

1.实验目的

YUV 转换为 RGB 的程序。将给定的实验数据用该程序转换为 RGB 文件。 并与原 RGB 文件进行比较, 如果有误差,分析误差来自何处。

2.实验原理

本实验中将256 * 256 YUV文件转化为256 * 256 RGB文件,对应关系为:
B=Y+1.773U-226.944
R=Y+1.403V-179.584
G=Y-0.714V-0.344U+135.424
而实验中YUV文件为4:2:0采样,这样就导致Y与UV不是1:1对应的,在转化时采取了这样的处理具体操作在代码中有标注

for (i = 0; i < x_dim; i++) {
/*以下对应找到RGB的位置,在RBG文件中,数据是
BGRBGRBGR...储存,因此确定第一个B,以此来找到G和R。*/
			g = b + 1;
			r = b + 2;
/*此处的处理是,找到一个Y,然后寻找对应的U和V,这种方法在人脑逻
辑上更容易操作,但是并不是最好的程序*/
			u = y + x_dim * y_dim - (i + 1) / 2 - j * 2 * x_dim / 2 + (j + 1) / 2 * x_dim / 2;
			v = y + x_dim * y_dim + x_dim / 2 * y_dim / 2 - (i + 1) / 2 - j * 2 * x_dim / 2 + (j + 1) / 2 * x_dim / 2;
//此处代码省略,原代码进行转换运算,在下面单独进行了说明
            ‘yuv2rgb’
//以下接收数据
			*r = rr;
			*g = gg;
			*b = bb;
//Y向后移1
			y++;
//B向后移3指向下一个B
			b += 3;
		}

在转换过程中,为避免出现像素越界,这里直接将越界的值置为最小值0(最大值255)

int rr, gg, bb;
			rr = (int)(*y + R_V01403[*v]);
			gg = (int)(*y + G_U_0344[*u] + G_V_0714[*v]);
			bb = (int)(*y + B_U01773[*u]);
//此处为了避免像素值越界,直接将越界的像素值置为最小值0(最大值255)
			if (rr < 0) rr = 0;
			if (rr > 255) rr = 255;
			if (gg < 0) gg = 0;
			if (gg > 255) gg = 255;
			if (bb < 0) bb = 0;
			if (bb > 255) bb = 255;

3.程序实现

完整程序
YUV2RGB.cpp

/*
  B=Y+1.773U-226.944
  R=Y+1.403V-179.584
  G=Y-0.714V-0.344U+135.424
  */
#include "stdlib.h"
#include "yuv2rgb.h"

static float R_V01403[256], B_U01773[256], G_U_0344[256], G_V_0714[256];
int YUV2RGB(int x_dim, int y_dim, void* bmp, void* rgb_out)
{
	static int init_done = 0;

	long i, j, size;
	unsigned char* r, * g, * b;
	unsigned char* y, * u, * v;
	//这里添加了示例中的检测,此处YUV4:2:0采样,如果此处不能被2整除,UV分量的转化将无法正常进行
	if ((x_dim % 2) || (y_dim % 2)) return 1;
	size = x_dim * y_dim;
	//创建查找表
	if (init_done == 0)
	{
		InitLookupTable();
		init_done = 1;
	}
	y = (unsigned char*)bmp;
	b = (unsigned char*)rgb_out;
	//此处进行运算
	for (j = 0; j < y_dim; j++)
	{
		for (i = 0; i < x_dim; i++) {
			g = b + 1;
			r = b + 2;
			u = y + x_dim * y_dim - (i + 1) / 2 - j * 2 * x_dim / 2 + (j + 1) / 2 * x_dim / 2;
			v = y + x_dim * y_dim + x_dim / 2 * y_dim / 2 - (i + 1) / 2 - j * 2 * x_dim / 2 + (j + 1) / 2 * x_dim / 2;
			int rr, gg, bb;
			rr = (int)(*y + R_V01403[*v]);
			gg = (int)(*y + G_U_0344[*u] + G_V_0714[*v]);
			bb = (int)(*y + B_U01773[*u]);
			//此处为了避免像素值越界,直接将越界的像素值置为最小值0(最大值255)
			if (rr < 0) rr = 0;
			if (rr > 255) rr = 255;
			if (gg < 0) gg = 0;
			if (gg > 255) gg = 255;
			if (bb < 0) bb = 0;
			if (bb > 255) bb = 255;
			*r = rr;
			*g = gg;
			*b = bb;
			y++;
			b += 3;
		}
	}

	return 0;
}

//查找表
void InitLookupTable()
{
	int i;
	for (i = 0; i < 256; i++) R_V01403[i] = (float)1.403 * (i - 128);
	for (i = 0; i < 256; i++) B_U01773[i] = (float)1.773 * (i - 128);
	for (i = 0; i < 256; i++) G_U_0344[i] = (float)-0.344 * (i - 128);
	for (i = 0; i < 256; i++) G_V_0714[i] = (float)-0.714 * (i - 128);
}

main.cpp

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include "yuv2rgb.h"

#define u_int8_t	unsigned __int8
#define u_int		unsigned __int32
#define FALSE		false
#define TRUE		true

int main(int argc, char** argv)
{
	u_int frameWidth = 352;			
	u_int frameHeight = 240;		
	bool flip = TRUE;				
	unsigned int i;

	char* rgbFileName = NULL;
	char* yuvFileName = NULL;
	FILE* rgbFile = NULL;
	FILE* yuvFile = NULL;
	u_int8_t* yuvBuf = NULL;
	u_int8_t* rgbBuf = NULL;

	yuvFileName = argv[1];
	rgbFileName = argv[2];

	frameWidth = atoi(argv[3]);
	frameHeight = atoi(argv[4]);

	//打开yuv文件
	yuvFile = fopen(yuvFileName, "rb");
	if (yuvFile == NULL)
	{
		printf("cannot find yuv file\n");
		exit(1);
	}
	else
	{
		printf("The input yuv file is %s\n", yuvFileName);
	}

	//准备rgb文件
	rgbFile = fopen(rgbFileName, "wb");
	if (rgbFile == NULL)
	{
		printf("cannot find rgb file\n");
		exit(1);
	}
	else
	{
		printf("The output rgb file is %s\n", rgbFileName);
	}
	yuvBuf = (u_int8_t*)malloc(frameWidth * frameHeight * 1.5);
	rgbBuf = (u_int8_t*)malloc(frameWidth * frameHeight * 3);
	//错误检测
	if (yuvBuf == NULL || rgbBuf == NULL)
	{
		printf("no enough memory\n");
		exit(1);
	}

	while (fread(yuvBuf, 1, frameWidth * frameHeight * 1.5, yuvFile))
	{
		if (YUV2RGB(frameWidth, frameHeight, yuvBuf, rgbBuf))
		{
			printf("error");
			return 0;
		}

		fwrite(rgbBuf, 1, frameWidth * frameHeight * 3, rgbFile);

	}


	fclose(rgbFile);
	fclose(yuvFile);

	return(0);
}

头文件

#pragma once
int YUV2RGB(int x_dim, int y_dim, void* bmp, void* rgb_out);
void InitLookupTable();

4.处理结果

YUV原图
在这里插入图片描述
处理后对比图,左侧为转换得到的图,右侧为RGB例图
在这里插入图片描述

5.误差分析

在YUV转RGB时,由于YUV采用的是4:2:0量化,色度信号与原RGB不是一一对应的,且在处理时对溢出数据直接赋为最大(最小)值,都会产生误差,但在最终结果可以看出,本实验中产生的误差不明显影响人眼视觉 体验

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值