编写彩色空间转换程序:YUVtoRGB

Y=+0.299R+0.587G+0.114B
U0=0.564(B-Y)=−0.1684R−0.3316G+0.5B
V0=0.713(R-Y)=+0.5R−0.4187G−0.0813B

所以
B-Y=U0/0.564 B=Y+1.773U0
R-Y=V0/0.713 R=Y+1.403V0
G=(Y-(0.299R+0.114B))/0.587 G=Y-0.714V0-0.344U0

U=U0+128
V=V0+128

所以
B=Y+1.773U-226.944
R=Y+1.403V-179.584
G=Y-0.714V-0.344U+135.424

yuv2rgb.cpp:

#include "stdlib.h"
#include "yuv2rgb.h"
#include <stdio.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* y, * u, * v;
	unsigned char* r, * g, * b;
	size = x_dim * y_dim;

	if (init_done == 0)
	{
		InitLookupTable();
		init_done = 1;
	}

	// allocate memory


	y = (unsigned char*)bmp;
	b = (unsigned char*)rgb_out;

	// convert RGB to YUV
		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 + 1)/2 * x_dim/2;
				v = y + x_dim * y_dim + x_dim / 2 * y_dim / 2 - (i + 1) / 2 - (j + 1)/2  * x_dim/2;
				int rr, gg, bb;
				rr= (int)(*y + R_V01403[*v]); //-179.584
				gg=(int)(*y + G_U_0344[*u] + G_V_0714[*v]);//+ 135.424
				bb=(int)(*y + B_U01773[*u]);//- 226.944
				*r = rr;//(unsigned char)(*y + R_V01403[*v] ); //-179.584
				*g = gg;// (unsigned char)(*y + G_U_0344[*u] + G_V_0714[*v]);//+ 135.424
				*b = bb;//(unsigned char)(*y + B_U01773[*u] );//- 226.944
				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"
#pragma warning(disable:4996)
#define u_int8_t	unsigned __int8
#define u_int		unsigned __int32
#define u_int32_t	unsigned __int32
#define FALSE		false
#define TRUE		true

int main(int argc, char** argv)
{
	/* variables controlable from command line */
	u_int frameWidth = 352;			/* --width=<uint> */
	u_int frameHeight = 240;		/* --height=<uint> */
	bool flip = TRUE;				/* --flip */
	unsigned int i;

	/* internal variables */
	char* rgbFileName = NULL;
	char* yuvFileName = NULL;
	FILE* rgbFile = NULL;
	FILE* yuvFile = NULL;
	u_int8_t* yuvBuf = NULL;
	u_int8_t* rgbBuf = NULL;
	u_int32_t videoFramesWritten = 0;

	/* begin process command line */
	/* point to the specified file names */
	yuvFileName = argv[1];
	rgbFileName = argv[2];

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

	/* open the RGB file */
	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);
	}

	/* open the RAW file */
	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);
	}

	/* get an input buffer for a frame */
	yuvBuf = (u_int8_t*)malloc(frameWidth * frameHeight * 1.5);

	/* get the output buffers for a frame */
	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;
		}
		
		for (i = 0; i < frameWidth * frameHeight*3; i++)
		{
			if (rgbBuf[i] < 0) rgbBuf[i] = 0;
			if (rgbBuf[i] > 255) rgbBuf[i] = 255;
		}
/*
		for (i = 0; i < frameWidth * frameHeight / 4; i++)
		{
			if (uBuf[i] < 16) uBuf[i] = 16;
			if (uBuf[i] > 240) uBuf[i] = 240;

			if (vBuf[i] < 16) vBuf[i] = 16;
			if (vBuf[i] > 240) vBuf[i] = 240;
		}
		
		fwrite(bBuf, 1, frameWidth * frameHeight, yuvFile);
		fwrite(gBuf, 1, (frameWidth * frameHeight) / 4, yuvFile);
		fwrite(rBuf, 1, (frameWidth * frameHeight) / 4, yuvFile);*/
		fwrite(rgbBuf, 1, frameWidth*frameHeight*3, rgbFile);

		printf("\r...%d", ++videoFramesWritten);
	}

	printf("\n%u %ux%u video frames written\n",
		videoFramesWritten, frameWidth, frameHeight);
	/* cleanup */

	fclose(rgbFile);
	fclose(yuvFile);

	return(0);
}

yuv2rgb.h

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

void InitLookupTable();

图片出现以下错误:
在这里插入图片描述

观察正确的yuv与rgb大小和获得的yuv与rgb大小:

正确值:
在这里插入图片描述

在这里插入图片描述

获得值:
在这里插入图片描述

在这里插入图片描述

​对比可知获得的u、v值异常偏小,导致rgb图像错误。
检验得偏移量错误。

改正偏移量部分:

		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]);
				*r=rr;
				*g=gg;
				*b=bb;
				y++;
				b+=3;
			}
		}

改正后结果:
在这里插入图片描述
有部分像素值越界。

将值限定在0~255:

				rr= (int)(*y + R_V01403[*v]); //-179.584
				gg=(int)(*y + G_U_0344[*u] + G_V_0714[*v]);//+ 135.424
				bb=(int)(*y + B_U01773[*u]);//- 226.944
				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;

改正后图像:
在这里插入图片描述
变换前yuv图像:
在这里插入图片描述

该yuv文件为4:2:0格式,u与v的数量为y的1/4,由总数1/4的u与v生成r、g、b会带来一定误差,同时进行转换计算时由小数变为整数也会产生一定误差,但只观察图像时难以辨别。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值