C - raw파일을 yuv422와 yuv420 Format으로 변환하기

Updated:

제가 C언어를 공부하면서 배웠던 문제를 공유하겠습니다.

이번 post는 raw파일의 이미지를 읽은 후 yuv422와 yuv420 파일로 변환해 저장하는 문제입니다.

입력의 lena파일은 256*256 size의 컬러 사진파일입니다.

파일 입,출력 포스팅에 있는 주석들은 생략하였습니다.

#pragma warning(disable:4996)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define BYTE unsigned char
#define WID 256
#define HEI 256

unsigned char** Mem_Alloc(int width, int height);				// Memory Allocation
void Mem_Free(BYTE** arr, int height);							// Memory Free

void File_Read(BYTE** img_in, char* filename, int width, int height);
void File_Write_422(BYTE** Y, BYTE** Cb, BYTE** Cr, char* filename, int width, int height);	// YUV422로 저장하기
void File_Write_420(BYTE** Y, BYTE** Cb, BYTE** Cr, char* filename, int width, int height);	// YUV420으로 저장하기

void RGB_to_YUV422(BYTE** img_in, BYTE** Y, BYTE** Cb, BYTE** Cr, int width, int height);	// YUV422로 만들기 위한 Y, Cb, Cr 만들기
void RGB_to_YUV420(BYTE** img_in, BYTE** Y, BYTE** Cb, BYTE** Cr, int width, int height);	// YUV420으로 만들기 위한 Y, Cb, Cr 만들기

void main()
{
	BYTE **ori_pic = Mem_Alloc(WID * 3, HEI);	//RGB 채널이므로 *3

	BYTE** Y = Mem_Alloc(WID, HEI);
	BYTE** Cb = Mem_Alloc(WID / 2, HEI);
	BYTE** Cr = Mem_Alloc(WID / 2, HEI);

	BYTE** Y1 = Mem_Alloc(WID, HEI);
	BYTE** Cb1 = Mem_Alloc(WID / 2, HEI / 2);
	BYTE** Cr1 = Mem_Alloc(WID / 2, HEI / 2);

	File_Read(ori_pic, "Lena_Color.raw", WID * 3, HEI);			// Lena RGB 읽기
	RGB_to_YUV422(ori_pic, Y, Cb, Cr, WID, HEI);				// YUV422를 위한 Y, Cb, Cr 구하기
	File_Write_422(Y ,Cb, Cr, "Lena_YUV422.yuv", WID, HEI);		// YUV422 Format에 맞춰 write

	RGB_to_YUV420(ori_pic, Y1, Cb1, Cr1, WID, HEI);				// YUV420를 위한 Y, Cb, Cr 구하기
	File_Write_420(Y1, Cb1, Cr1, "Lena_YUV420.yuv", WID, HEI);	// YUV420 Format에 맞춰 write

	Mem_Free(Y, HEI);
	Mem_Free(Cb, HEI);
	Mem_Free(Cr, HEI);

	Mem_Free(Y1, HEI);
	Mem_Free(Cb1, HEI / 2);
	Mem_Free(Cr1, HEI / 2);
}

unsigned char** Mem_Alloc(int width, int height)
{
	BYTE **arr;

	arr = (BYTE**)malloc(sizeof(BYTE*) * height);
	for (int i = 0; i < height; i++)
	{
		arr[i] = (BYTE*)malloc(sizeof(BYTE) * width);
	}

	return arr;

}
void Mem_Free(BYTE** arr, int height)
{
	for (int i = 0; i < height; i++)
	{
		free(arr[i]);
	}
	free(arr);

}

void File_Read(BYTE** img_in, char* filename, int width, int height)
{
	FILE *fp_in;

	fp_in = fopen(filename, "rb");
	if (!fp_in)
	{
		printf("ERROR :: File Can't Read\n");
		exit(1);
	}
	for (int i = 0; i < height; i++)
	{
		fread(img_in[i], sizeof(BYTE), width, fp_in);
	}

	fclose(fp_in);

}
void File_Write_422(BYTE** Y, BYTE** Cb, BYTE** Cr, char* filename, int width, int height)
{
	FILE *fp_out;
	int i = 0;
	fp_out = fopen(filename, "wb");

	if (!fp_out)
	{
		printf("ERROR :: File Can't Save\n", filename);
		exit(1);
	}
	for (i = 0; i < height; i++)
	{
		fwrite((BYTE*)Y[i], sizeof(BYTE), width, fp_out);
	}
	for (i = 0; i < height; i++)
	{
		fwrite((BYTE*)Cb[i], sizeof(BYTE), width / 2, fp_out);
	}
	for (i = 0; i < height; i++)
	{
		fwrite((BYTE*)Cr[i], sizeof(BYTE), width / 2, fp_out);
	}
	fclose(fp_out);
}
void File_Write_420(BYTE** Y, BYTE** Cb, BYTE** Cr, char* filename, int width, int height)
{
	FILE *fp_out;
	int i = 0;
	fp_out = fopen(filename, "wb");

	if (!fp_out)
	{
		printf("ERROR :: File Can't Save\n", filename);
		exit(1);
	}
	for (i = 0; i < height; i++)
	{
		fwrite((BYTE*)Y[i], sizeof(BYTE), width, fp_out);
	}
	for (i = 0; i < height / 2; i++)
	{
		fwrite((BYTE*)Cb[i], sizeof(BYTE), width / 2, fp_out);
	}
	for (i = 0; i < height / 2; i++)
	{
		fwrite((BYTE*)Cr[i], sizeof(BYTE), width / 2, fp_out);
	}	fclose(fp_out);
}

void RGB_to_YUV422(BYTE** img_in, BYTE** Y, BYTE** Cb, BYTE** Cr, int width, int height)
{
	int i = 0, j = 0, k = 0;
	BYTE** R = Mem_Alloc(width, height);
	BYTE** G = Mem_Alloc(width, height);
	BYTE** B = Mem_Alloc(width, height);

	for (i = 0; i < height; i++)
	{
		for (j = 0, k = 0; j < width; j++, k += 3)
		{
			R[i][j] = img_in[i][k];
			G[i][j] = img_in[i][k + 1];
			B[i][j] = img_in[i][k + 2];

		}
	}

	for (i = 0; i < height; i++)
	{
		for (j = 0; j < width; j++)
		{
			Y[i][j] = ((0.257)*(double)R[i][j] + (0.504)*(double)G[i][j] + (0.098)*(double)B[i][j] + (double)16);
			if (j % 2 == 0)
			{
				Cb[i][j / 2] = ((-0.148)*(double)R[i][j] + (-0.291)*(double)G[i][j] + (0.439)*(double)B[i][j] + (double)128);
				Cr[i][j / 2] = ((0.439)*(double)R[i][j] + (-0.368)*(double)G[i][j] + (-0.071)*(double)B[i][j] + (double)128);
			}

		}
	}

	Mem_Free(R, HEI);
	Mem_Free(G, HEI);
	Mem_Free(B, HEI);
}

void RGB_to_YUV420(BYTE** img_in, BYTE** Y, BYTE** Cb, BYTE** Cr, int width, int height)
{
	int i = 0, j = 0, k = 0;
	BYTE** R = Mem_Alloc(width, height);
	BYTE** G = Mem_Alloc(width, height);
	BYTE** B = Mem_Alloc(width, height);

	for (i = 0; i < height; i++)
	{
		for (j = 0, k = 0; j < width; j++, k += 3)
		{
			R[i][j] = img_in[i][k];
			G[i][j] = img_in[i][k + 1];
			B[i][j] = img_in[i][k + 2];

		}
	}
	for (i = 0; i < HEI; i++)
	{
		for (j = 0; j < WID; j++)
		{
			Y[i][j] = ((0.257)*(double)R[i][j] + (0.504)*(double)G[i][j] + (0.098)*(double)B[i][j] + (double)16);
			if (i % 2 == 0)
			{
				if (j % 2 == 0)
				{
					Cb[i / 2][j / 2] = ((-0.148)*(double)R[i][j] + (-0.291)*(double)G[i][j] + (0.439)*(double)B[i][j] + (double)128);
					Cr[i / 2][j / 2] = ((0.439)*(double)R[i][j] + (-0.368)*(double)G[i][j] + (-0.071)*(double)B[i][j] + (double)128);
				}
			}
		}
	}

	Mem_Free(R, HEI);
	Mem_Free(G, HEI);
	Mem_Free(B, HEI);
}

Leave a comment