实验步骤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
重点区别有两处。
- 溢出的处理问题,由于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);
}