作业4 彩色空间转换

实验步骤1

编写rgb2yuv程序,并运用查表以及缓冲函数。

1.根据IDE和实验文件修改相应参数

  • u_int frameWidth = 256; 等
  • 调试>属性>调试>工作目录,命令参数 down.rgb down.yuv 256 256

2.设计程序步骤,重点关注指针与子函数的设计

读入部分:利用char指针filename直接读取命令参数,增加适用性,方便后续修改。


char *yuvname = NULL;
char *rgbname = NULL;
FILE* yuvFile = NULL;
FILE* rgbFile = NULL;

yuvname = argv[2];
rgbname = argv[1];
width = atoi(argv[3]);
height = atoi(argv[4]);
rgbFile = fopen(rgbname, "rb");
if (!rgbFile)
	printf("open rgb fail");
else
	printf("open rgb success\n");
yuvFile = fopen(yuvname, "wb");
if (!yuvFile)
	printf("open yuv fail");
else
	printf("create yuv success\n");

申请内存存放yuv,注意色度取样格式,设置uv 内存为y的四分之一。

	unsigned char* rgbBuf = NULL;
	unsigned char* yBuf = NULL;
	unsigned char* uBuf = NULL;
	unsigned char* vBuf = NULL;
	rgbBuf = (unsigned char*)malloc(width*height * 3);
	yBuf = (unsigned char*)malloc(width*height);
	uBuf = (unsigned char*)malloc(width*height*0.25);
	vBuf = (unsigned char*)malloc(width*height*0.25);

检验内存申请成功与否:

	if (rgbBuf == NULL || yBuf == NULL || uBuf == NULL || vBuf == NULL)
	{
		printf("ASK MEMORY FAIL");

	}

调用子函数部分,注意检测调用成功与否:

if (yuv2rgb(width, height, rgbBuf, yBuf, uBuf, vBuf))
		{
			printf("fail");
			return 0;
		}

根据要求设置量化电平,使用if语句完成即可
记得关闭文件。

子函数部分:参数设置为6个,分别为分辨率xy,rgb的输入rgb_in,以及yuv的分别输出y_out,u_out,v_out;

int yuv2rgb(int x_dim, int y_dim, void *rgb_in, void *y_out, void *u_out, void *v_out)

定义变量:

long i, j;//循环用
	unsigned char *r, *g, *b;
	unsigned char *y, *u, *v,*op,*ov,*u1,*u2,*v1,*v2;//op,ov为最终输出的uv,u1,u2,v1,v2为中间运算用指针
	unsigned char *y_buffer, *u_buffer, *v_buffer,*u_buffer_out,*v_buffer_out;

定义完后为*u_buffer,*v_buffer申请内存,因为他们不做直接输出,需要缓存数据

然后首先查表,利用静态数组以及数学公式计算0-255的七项结果,查表函数应在子函数中首先调用。

计算完表格,将形参与定义的变量结合。

	y_buffer = (unsigned char *)y_out;
	u_buffer_out = (unsigned char *)u_out;
	v_buffer_out = (unsigned char *)v_out;

	b = (unsigned char *)rgb_in;

	y = y_buffer;
	u = u_buffer;
	v = v_buffer;

输出部分:
y分量输出较为简单,循环中根据公式查表可得
根据bgr的排列顺序,循环中bgr的变化规律很容易想到
记得uv+128

	for (i = 0; i < y_dim; i++) {

		for (j = 0; j < x_dim; j++) {
			g = b + 1;
			r = b + 2;
			*y = (unsigned char)(RGBYUV02990[*r] + RGBYUV05870[*g] + RGBYUV01140[*b]);
			*u = (unsigned char)(-RGBYUV01684[*r] - RGBYUV03316[*g] + (*b) / 2 + 128);
			*v = (unsigned char)((*r) / 2 - RGBYUV04187[*g] - RGBYUV00813[*b] + 128);
			b += 3;
			y++;
			u++;
			v++;

		}
	}

输出uv:
上面我们将256*256的uv存入了两个缓冲区
下面我们4个u为1组,计算平均值

	op = u_buffer_out;
	ov = v_buffer_out;//输出部分写好
	for (j = 0; j < y_dim / 2; j++)
	{
		u1 = u_buffer + 2 * j * x_dim;
		u2 = u_buffer + (2 * j + 1) * x_dim;
		v1 = v_buffer + 2 * j * x_dim;
		v2 = v_buffer + (2 * j + 1) * x_dim;//直接写在内循环里太臃肿,用中间变量来表示四个uv,同时同行的变化放进内循环,用+=实现
		for (i = 0; i < x_dim / 2; i++)
		{
			*op = (*u1 + *(u1 + 1) + *u2 + *(u2 + 1)) / 4;
			*ov = (*v1 + *(v1 + 1) + *v2 + *(v2 + 1)) / 4;//采取4个u取平均方式,也可4取1
			op++;
			ov++;
			u1 += 2;
			u2 += 2;
			v1 += 2;
			v2 += 2;
		}
	}

释放缓冲,子函数返回。

2.编写yuv2rgb

与rgb2yuv大同小异。列出不同点,并贴出完整代码

子函数参数设计不同
主函数中命令参数调整
主程序中缓冲大小调整,相应读取写入大小也要调整。
子程序查表公式不同,所用公式由myx同学友情提供
写入方式不同,注意rgb文件分量的排列规则。
无需量化电平。
查表中记得u,v-128

重点区别有两处。

  1. 溢出的处理问题,由于uv是由例1计算得来,公式也有误差指出会造成少部分点变红点。
    采用等比例缩放将它消除。
		for (int i = 0; i < width*height; i++)
		{
			
			if (rBuf[i] >= 240) rBuf[i] = (gBuf[i]+bBuf[i])/500*rBuf[i];
		}

2.子函数中rgb输出问题,由于rgb输出没有uv那么复杂,没有用中间指针,一个循环全部可以输出。

for (i = 0; i < y_dim; i++) {
		
		for (j = 0; j < x_dim; j++) {
			u = y+(x_dim*y_dim-i*x_dim-j)+x_dim/2*(i/2)+j/2;
			v = u+ x_dim*y_dim/4;
			*r = (unsigned char)(*y + R14075[*v]);
			*g = (unsigned char)(*y - G03455[*u]- G07169[*v]);
			*b = (unsigned char)(*y + B1779[*u]);
			y += 1;
			r++;
			g++;
			b++;

		}
	}

yuv2rgb项目的完整代码

main:

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include "yuv2rgb.h"
int main(int argc, char** argv)
{
	unsigned __int32 width = 256;
	unsigned __int32 height = 256;
	//创建数组,申请内存,读取文件
	char *yuvname = NULL;
	char *rgbname = NULL;
	FILE* yuvFile = NULL;
	FILE* rgbFile = NULL;

	yuvname = argv[1];
	rgbname = argv[2];
	width = atoi(argv[3]);
	height = atoi(argv[4]);
	yuvFile = fopen(yuvname, "rb");
	if (!yuvFile)
		printf("open yuv fail");
	else
		printf("open yuv success\n");
	rgbFile = fopen(rgbname, "wb");
	if (!rgbFile)
		printf("open rgb fail");
	else
		printf("create rgb success\n");
	//建立缓冲区准备读取数组
	unsigned char* yuvBuf = NULL;
	unsigned char* rBuf = NULL;
	unsigned char* gBuf = NULL;
	unsigned char* bBuf = NULL;
	yuvBuf = (unsigned char*)malloc(width*height * 1.5);
	rBuf = (unsigned char*)malloc(width*height);
	gBuf = (unsigned char*)malloc(width*height);
	bBuf = (unsigned char*)malloc(width*height);
	if (yuvBuf == NULL || rBuf == NULL || gBuf == NULL || bBuf == NULL)
	{
		printf("ASK MEMORY FAIL");

	}

	while (fread(yuvBuf, 1, width * height * 1.5, yuvFile))
	{
		if (yuv2rgb(width, height, yuvBuf, rBuf, gBuf, bBuf))
		{
			printf("error");
			return 0;
		}

		for (int i = 0; i < width*height; i++)
		{
			
			if (rBuf[i] >= 240) rBuf[i] = (gBuf[i]+bBuf[i])/500*rBuf[i];
		}
		/*for (int i = 0; i < width*height; i++)
		{
			if (gBuf[i] <= 16) gBuf[i] = 16;
			if (gBuf[i] >= 240) gBuf[i] = 240;
		}
		for (int i = 0; i < width*height; i++)
		{
			if (bBuf[i] <= 16) bBuf[i] = 16;
			if (bBuf[i] >= 240) bBuf[i] = 240;
		}
		*/
	
		for (int i = 0; i < width*height; i++) {


			fwrite(bBuf+i, 1, 1, rgbFile);
			fwrite(gBuf+i, 1, 1, rgbFile);
			fwrite(rBuf+i, 1, 1, rgbFile);
		}
		
	}
	fclose(rgbFile);
	fclose(yuvFile);

	return 0;
}

yuv2rgb子函数:

#include <stdlib.h>
#include "yuv2rgb.h"
static float R14075[256],G03455[256], G07169[256],B1779[256];
int yuv2rgb(int x_dim, int y_dim, void *yuv_in, void *r_out, void *g_out, void *b_out )
{

	

	long i, j;
	unsigned char *r,*g,*b;
	unsigned char *y, *u, *v;
	
	
	unsigned char *r_buffer, *g_buffer, *b_buffer;
	LookupTable();
	r_buffer= (unsigned char *)r_out;
	g_buffer = (unsigned char *)g_out;
	b_buffer = (unsigned char *)b_out;
	
	y = (unsigned char *)yuv_in;
	
	r = r_buffer;
	g = g_buffer;
	b = b_buffer;
	for (i = 0; i < y_dim; i++) {
		
		for (j = 0; j < x_dim; j++) {
			u = y+(x_dim*y_dim-i*x_dim-j)+x_dim/2*(i/2)+j/2;
			v = u+ x_dim*y_dim/4;
			*r = (unsigned char)(*y + R14075[*v]);
			*g = (unsigned char)(*y - G03455[*u]- G07169[*v]);
			*b = (unsigned char)(*y + B1779[*u]);
			y += 1;
			r++;
			g++;
			b++;

		}
	}

	return 0;

}
void LookupTable() {

	int i;

	for (i = 0; i < 256; i++) R14075[i] = (float)1.4075 * (i - 128);
	for (i = 0; i < 256; i++) G03455[i] = (float)0.3455 * (i - 128);
	for (i = 0; i < 256; i++) G07169[i] = (float)0.7169 * (i - 128);
	for (i = 0; i < 256; i++) B1779[i] = (float)0.1779 * (i - 128);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值