【Codecs】顏色空間轉換CSconvert:YUV420轉YUV444
阿新 • • 發佈:2019-02-05
Date: 2018.5.31
1、YUV分三種取樣方式:
YUV444:對於每一個畫素都對應一個Y分量、一個U分量、一個V分量。
YUV422:對於一個畫素都對應一個Y分量,但是每兩個畫素(或者說Y分量)對應一個U分量和一個V分量。
YUV420:對於一個畫素都對應一個Y分量,但是每四個畫素(或者說Y分量)對應一個U分量和一個V分量。
2、YUV的儲存格式:
YUV在儲存時是以陣列的形式儲存的,可以看做連續的三個陣列。三個陣列分別單獨儲存Y、U、V分量。
同理對於YUV420和YUV422,只是U和V的陣列大小的不同而已。
總資料量來看,YUV444需要儲存1920*1080*3個值,YUV422需要儲存1920*1080*2個值,YUV420需要儲存1920*1080*3/2個值。
3、YUV420轉YUV444主要思路:
YUV420轉YUV444,實際就是對色度進行上取樣,最為簡單的實現思路是直接填充。
以U分量為例,其序列如下
對U進行插值,每個田字格四個位置使用一個U值。
在程式碼中,可以直接通過對陣列迴圈賦值即可完成。
對V分量的操作相同。
填充方式實現簡單,效果較差,可以通過插值來完成上取樣。
自己實現的C程式碼如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char** argv)
{
int i, j, width, height, frame_size;
FILE *fp_in, *fp_out;
unsigned char *y1, *u1, *v1, *y2, *u2, *v2;
int n = 0;
printf("\nUsage:YUV420toYUV444.exe inputfile outputfile width height\n\n");
for (i = 0; i < argc;i++)
{
printf("Input parameters: %s \n", argv[i]);
}
if (argc < 5)
{
return -1;
}
fp_in = fopen(argv[1], "rb");
if (NULL == fp_in)
{
printf("ERROR: open %s fail\n", argv[1]);
return -1;
}
fp_out = fopen(argv[2], "wb");
if (NULL == fp_out)
{
printf("ERROR: open %s fail\n", argv[2]);
return -1;
}
width = atoi(argv[3]);
height = atoi(argv[4]);
frame_size = width*height;
y1 = (unsigned char *)malloc(frame_size*3/2);
if ( NULL == y1 )
{
printf("malloc y1 fail\n");
return -1;
}
u1 = y1 + width*height;
v1 = u1 + width*height / 4;
y2 = (char *)malloc(frame_size*3);
if (NULL== y2 )
{
printf("malloc y2 fail\n");
return -1;
}
u2 = y2 + width*height;
v2 = u2 + width*height;
while (fread(y1,1,frame_size*3/2,fp_in) == frame_size*3/2)
{
memcpy(y2, y1, frame_size);//Y
for (j = 0; j < height; j++)//U,V
{
for (i = 0; i < width; i++)
{
u2[j*width + i] = u1[j / 2 * width / 2 + i / 2];
v2[j*width + i] = v1[j / 2 * width / 2 + i / 2];
}
}
fwrite(y2, 1, frame_size*3, fp_out);
n++;
}
printf("YUV420toYUV444 successfully!!,total frames: %d\n",n);
free(y1);
y1 = NULL;
free(y2);
y2 = NULL;
fclose(fp_in);
fclose(fp_out);
return 0;
}