C - yuv422와 yuv420파일을 RGB Foramt으로 변환하기
Updated:
제가 C언어를 공부하면서 배웠던 문제를 공유하겠습니다.
이번 post는 yuv422와 yuv420 파일을 RGB로 변환해 저장하는 문제입니다.
입력의 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
#define CLIP(x) (x < 0 ? 0 : (x > 255 ? 255 : x))
unsigned char** Mem_Alloc(int width, int height); // Memory Allocation
void Mem_Free(BYTE** arr, int height); // Memory Free
void File_Read_YUV422(BYTE** Y, BYTE** Cb, BYTE** Cr, char* filename, int width, int height); // YUV422 파일 읽어서 Y, Cb, Cr로 분해
void File_Read_YUV420(BYTE** Y, BYTE** Cb, BYTE** Cr, char* filename, int width, int height); // YUV420 파일 읽어서 Y, Cb, Cr로 분해
void File_Write(BYTE** RGB, char* filename, int width, int height); // RGB 저장하기
void YUV422_to_RGB(BYTE** RGB, BYTE** Y, BYTE** Cb, BYTE** Cr, int width, int height); // RGB로 만들기 위한 R, G, B 만들기
void YUV420_to_RGB(BYTE** RGB, BYTE** Y, BYTE** Cb, BYTE** Cr, int width, int height);
void main()
{
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);
BYTE** RGB = Mem_Alloc(WID * 3, HEI);
File_Read_YUV422(Y, Cb, Cr, "YUV422_Lena_Color.yuv", WID, HEI); // Lena YUV422 읽고 각 채널로 받기
YUV422_to_RGB(RGB, Y, Cb, Cr, WID, HEI); // RGB로 변환
File_Write(RGB, "Lena_YUV422_to_RGB.raw", WID, HEI); // RGB file write
File_Read_YUV420(Y1, Cb1, Cr1, "YUV420_Lena_Color.yuv", WID, HEI); // Lena YUV420 읽고 각 채널로 받기
YUV420_to_RGB(RGB, Y1, Cb1, Cr1, WID, HEI); // RGB로 변환
File_Write(RGB, "Lena_YUV420_to_RGB.raw", WID, HEI); // RGB file 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);
Mem_Free(RGB, HEI);
}
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_YUV422(BYTE** Y, BYTE** Cb, BYTE** Cr, char* filename, int width, int height)
{
FILE *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(Y[i], sizeof(BYTE), width, fp_in);
}
for (int i = 0; i < height; i++)
{
fread(Cb[i], sizeof(BYTE), width / 2, fp_in);
}
for (int i = 0; i < height; i++)
{
fread(Cr[i], sizeof(BYTE), width / 2, fp_in);
}
fclose(fp_in);
}
void File_Read_YUV420(BYTE** Y, BYTE** Cb, BYTE** Cr, char* filename, int width, int height)
{
FILE *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(Y[i], sizeof(BYTE), width, fp_in);
}
for (int i = 0; i < height / 2; i++)
{
fread(Cb[i], sizeof(BYTE), width / 2, fp_in);
}
for (int i = 0; i < height / 2; i++)
{
fread(Cr[i], sizeof(BYTE), width / 2, fp_in);
}
fclose(fp_in);
}
void File_Write(BYTE** RGB, 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*)RGB[i], sizeof(BYTE), width * 3, fp_out);
}
fclose(fp_out);
}
void YUV422_to_RGB(BYTE** RGB,BYTE** Y, BYTE** Cb, BYTE** Cr, int width, int height)
{
int i = 0, j = 0, k = 0;
int R = 0, G = 0, B = 0;
BYTE** Cb_up = Mem_Alloc(width, height);
BYTE** Cr_up = Mem_Alloc(width, height);
for (i = 0; i < height; i++) // Cb 채널 Up-sampling
{
for (j = 0, k = 0; j < width; j = j + 2, k++)
{
Cb_up[i][j] = Cb[i][k];
Cb_up[i][j + 1] = Cb[i][k];
}
}
for (i = 0; i < height; i++)
{
for (j = 0, k = 0; j < width; j = j + 2, k++) // Cr 채널 Up-sampling
{
Cr_up[i][j] = Cr[i][k];
Cr_up[i][j + 1] = Cr[i][k];
}
}
for (i = 0; i < height; i++)
{
for (j = 0,k = 0; j < width; j++, k +=3)
{
R = ((1.164)*(double)(Y[i][j] - 16) + (1.596)*(double)(Cr_up[i][j] - 128));
G = ((1.164)*(double)(Y[i][j] - 16) - (0.813)*(double)(Cr_up[i][j] - 128) - (0.392)*(double)(Cb_up[i][j] - 128));
B = ((1.164)*(double)(Y[i][j] - 16) + (2.017)*(double)(Cb_up[i][j] - 128));
RGB[i][k] = CLIP(R);
RGB[i][k + 1] = CLIP(G);
RGB[i][k + 2] = CLIP(B);
}
}
Mem_Free(Cb_up, height);
Mem_Free(Cr_up, height);
}
void YUV420_to_RGB(BYTE** RGB, BYTE** Y, BYTE** Cb, BYTE** Cr, int width, int height)
{
int i = 0, j = 0, r = 0, k = 0;
int R = 0, G = 0, B = 0;
BYTE** Cb_up = Mem_Alloc(width, height);
BYTE** Cr_up = Mem_Alloc(width, height);
for (i = 0, r = 0; i < height; i += 2, k++) // Cb 채널 Up-sampling
{
for (j = 0, k = 0; j < width; j += 2, k++)
{
Cb_up[i][j] = Cb[r][k];
Cb_up[i][j + 1] = Cb[r][k];
Cb_up[i + 1][j] = Cb[r][k];
Cb_up[i + 1][j + 1] = Cb[r][k];
}
}
for (i = 0, r = 0; i < height; i += 2, r++) // Cr 채널 Up-sampling
{
for (j = 0, k = 0; j < width; j += 2, k++)
{
Cr_up[i][j] = Cr[r][k];
Cr_up[i + 1][j] = Cr[r][k];
Cr_up[i][j + 1] = Cr[r][k];
Cr_up[i + 1][j + 1] = Cr[r][k];
}
}
for (i = 0; i < height; i++)
{
for (j = 0, k = 0; j < width; j++, k += 3)
{
R = ((1.164)*(double)(Y[i][j] - 16) + (1.596)*(double)(Cr_up[i][j] - 128));
G = ((1.164)*(double)(Y[i][j] - 16) - (0.813)*(double)(Cr_up[i][j] - 128) - (0.392)*(double)(Cb_up[i][j] - 128));
B = ((1.164)*(double)(Y[i][j] - 16) + (2.017)*(double)(Cb_up[i][j] - 128));
RGB[i][k] = CLIP(R);
RGB[i][k + 1] = CLIP(G);
RGB[i][k + 2] = CLIP(B);
}
}
Mem_Free(Cb_up, height);
Mem_Free(Cr_up, height);
}
Leave a comment