Directorio de artículos
Objetivo
1. En la clase, el profesor ha entregado un programa de muestra para convertir RGB a formato YUV Lea y comprenda el programa.
2. Escriba un programa para convertir YUV a RGB. Utilice este programa para convertir los datos experimentales dados en archivos RGB. Y compare con el archivo RGB original, si hay un error, analice la causa del error.
El principio básico del algoritmo
En este experimento, el rango de imagen que utilicé es [0,255]. La fórmula de conversión comúnmente utilizada para el rango de valores de [0,255] es la siguiente.
Fórmula RGB a YUV:
Y = 0.2990R + 0.5870G + 0.1140B
U = - 0.1684R - 0.3316G + 0.5B + 128
V = 0.5R - 0.4187G - 0.0813B + 128
Correspondiente a YUV a RGB:
R = Y + 1,403 (V - 128)
G = Y - 0,343 (U - 128) - 0,714 (V - 128)
B = Y + 1.770 (U-128)
El método de muestreo del flujo YUV
El formato de almacenamiento del flujo de código YUV está estrechamente relacionado con su método de muestreo. Hay tres métodos de muestreo principales:
- YUV4: 4: 4: indica que un componente Y corresponde a un conjunto de componentes UV.
- YUV4: 2: 2: significa que dos componentes Y comparten un conjunto de componentes UV.
- YUV4: 1: 1: es el muestreo 4: 1 de cromaticidad en la dirección horizontal.
- YUV4: 2: 0: indica que los cuatro componentes Y comparten un conjunto de componentes UV.
El siguiente es un diagrama esquemático de los cuatro métodos de muestreo.
Este experimento es: YUV4: 2: 0 método de muestreo es: el componente U y el componente V son muestreo entrelazado, y el componente UV también es muestreo entrelazado en su línea de muestreo.
El método de almacenamiento rgb es que
cada píxel corresponde a tres caracteres sin firmar de bgr.
Para considerar la simplicidad del algoritmo, el valor utilizado aquí es
tomar yuv en el orden creciente de u, v , luego (y + 256) uv, luego y ++, luego yuv, luego (y + 256) uv, luego y ++, u ++, v ++. De esta forma, cuatro grupos forman un círculo.
Parte de código
Parte funcional del programa:
void YUV2RGB(FILE* yuv,FILE* rgb,int width,int height)
{
Init();
int i = 0, j = 0;
long shape = width * height;
unsigned char* y, * u, * v, * rgb1, * auxrgb, * start;
y = (unsigned char*)malloc(sizeof(unsigned char*) * shape);
u = (unsigned char*)malloc(sizeof(unsigned char*) * shape / 4);
v = (unsigned char*)malloc(sizeof(unsigned char*) * shape / 4);
rgb1 = (unsigned char*)malloc(sizeof(unsigned char*) * shape * 3);//没必要将rgb分开,*3即可
start = rgb1;//rgb1首指针
fread(y, shape, sizeof(unsigned char), yuv);
fread(u, shape / 4, sizeof(unsigned char), yuv);
fread(v, shape / 4, sizeof(unsigned char), yuv);
for (j = 0; j < height/2; j++)
{
auxrgb = rgb1 + 3 * width;//偶数行
for(i=0;i<width/2;i++)
{
*rgb1++ = Rgu(*y + YUVRGB1403[*u]);
*rgb1++ = Rgu(*y - YUVRGB0343[*u] - YUVRGB0714[*v]);
*rgb1++ = Rgu(*y + YUVRGB1770[*v]);
*auxrgb++ = Rgu(*(width + y) + YUVRGB1403[*u]);
*auxrgb++ = Rgu(*(width + y) - YUVRGB0343[*u] - YUVRGB0714[*v]);
*auxrgb++ = Rgu(*(width + y++) + YUVRGB1770[*v]);
*rgb1++ = Rgu(*y + YUVRGB1403[*u]);
*rgb1++ = Rgu(*y - YUVRGB0343[*u] - YUVRGB0714[*v]);
*rgb1++ = Rgu(*y + YUVRGB1770[*v]);
*auxrgb++ = Rgu(*(width + y) + YUVRGB1403[*u]);
*auxrgb++ = Rgu(*(width + y) - YUVRGB0343[*u++] - YUVRGB0714[*v]);
*auxrgb++ = Rgu(*(width + y++) + YUVRGB1770[*v++]);
}
y += width; rgb1 += 3 * width;
}
if (shape * 3 == fwrite(start, sizeof(unsigned char*), shape * 3, rgb))
printf("success");
else printf("failed to write");
free(start);
free(y - shape);
free(u - shape / 4);
free(v - shape / 4);
}
Parte de la tabla de búsqueda
static float YUVRGB1403[256], YUVRGB0343[256], YUVRGB0714[256], YUVRGB1770[256];
void Init()
{
int i = 0;
for (i; i < 256; i++)
{
YUVRGB1403[i] = 1.403 * (i - 128);
YUVRGB0343[i] = 0.343 * (i - 128);
YUVRGB0714[i] = 0.714 * (i - 128);
YUVRGB1770[i] = 1.770 * (i - 128);
}
}
función principal
int main(int argc,char **argv)
{
if (argc == 5)
{
FILE* yuv = fopen(argv[1], "rb");
FILE* rgb = fopen(argv[2], "wb");
YUV2RGB(yuv, rgb, atoi(argv[3]), atoi(argv[4]));
fclose(yuv);
fclose(rgb);
}
else printf("需要4个参数");
return 0;
}
Aquí, la ruta del archivo y el tamaño de la imagen se pasan directamente a * argv [], eliminando la necesidad de juicio, y el código es más conciso, a costa de menos rigor.
Código completo
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
static float YUVRGB1403[256], YUVRGB0343[256], YUVRGB0714[256], YUVRGB1770[256];
int main(int argc,char **argv)
{
if (argc == 5)
{
FILE* yuv = fopen(argv[1], "rb");
FILE* rgb = fopen(argv[2], "wb");
YUV2RGB(yuv, rgb, atoi(argv[3]), atoi(argv[4]));
fclose(yuv);
fclose(rgb);
}
else printf("需要4个参数");
return 0;
}
unsigned char Rgu(float a)
{
if (a < 0) return (unsigned char)0;
else if (a > 255) return (unsigned char)255;
else return (unsigned char)a;
}
void YUV2RGB(FILE* yuv,FILE* rgb,int width,int height)
{
Init();
int i = 0, j = 0;
long shape = width * height;
unsigned char* y, * u, * v, * rgb1, * auxrgb, * start;
y = (unsigned char*)malloc(sizeof(unsigned char*) * shape);
u = (unsigned char*)malloc(sizeof(unsigned char*) * shape / 4);
v = (unsigned char*)malloc(sizeof(unsigned char*) * shape / 4);
rgb1 = (unsigned char*)malloc(sizeof(unsigned char*) * shape * 3);//没必要将rgb分开,*3即可
start = rgb1;//rgb1首指针
fread(y, shape, sizeof(unsigned char), yuv);
fread(u, shape / 4, sizeof(unsigned char), yuv);
fread(v, shape / 4, sizeof(unsigned char), yuv);
for (j = 0; j < height/2; j++)
{
auxrgb = rgb1 + 3 * width;//偶数行
for(i=0;i<width/2;i++)
{
*rgb1++ = Rgu(*y + YUVRGB1403[*u]);
*rgb1++ = Rgu(*y - YUVRGB0343[*u] - YUVRGB0714[*v]);
*rgb1++ = Rgu(*y + YUVRGB1770[*v]);
*auxrgb++ = Rgu(*(width + y) + YUVRGB1403[*u]);
*auxrgb++ = Rgu(*(width + y) - YUVRGB0343[*u] - YUVRGB0714[*v]);
*auxrgb++ = Rgu(*(width + y++) + YUVRGB1770[*v]);
*rgb1++ = Rgu(*y + YUVRGB1403[*u]);
*rgb1++ = Rgu(*y - YUVRGB0343[*u] - YUVRGB0714[*v]);
*rgb1++ = Rgu(*y + YUVRGB1770[*v]);
*auxrgb++ = Rgu(*(width + y) + YUVRGB1403[*u]);
*auxrgb++ = Rgu(*(width + y) - YUVRGB0343[*u++] - YUVRGB0714[*v]);
*auxrgb++ = Rgu(*(width + y++) + YUVRGB1770[*v++]);
}
y += width; rgb1 += 3 * width;
}
if (shape * 3 == fwrite(start, sizeof(unsigned char*), shape * 3, rgb))
printf("success");
else printf("failed to write");
free(start);
free(y - shape);
free(u - shape / 4);
free(v - shape / 4);
}
void Init()
{
int i = 0;
for (i; i < 256; i++)
{
YUVRGB1403[i] = 1.403 * (i - 128);
YUVRGB0343[i] = 0.343 * (i - 128);
YUVRGB0714[i] = 0.714 * (i - 128);
YUVRGB1770[i] = 1.770 * (i - 128);
}
}
Resultado experimental
imagen rgb después de la conversión de la imagen rgb original
Resultados experimentales
Después de la comparación visual,
se descubre que el color está ligeramente desviado. Esto se debe a que la frecuencia de muestreo del croma de la imagen causada por el formato yuv4: 2: 0 es baja, la gradación de la señal de croma se pierde y la transición de color es no lo suficientemente "redondo".