Conversión de imágenes entre el formato YUV4: 2: 0 y el formato RGB

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.Inserte la descripción de la imagen aquí

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
Inserte la descripción de la imagen aquí
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 Inserte la descripción de la imagen aquídespués de la conversión de la imagen rgb originalInserte la descripción de la imagen aquí

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".

Supongo que te gusta

Origin blog.csdn.net/weixin_44218153/article/details/114947643
Recomendado
Clasificación