1. 程式人生 > >【Codecs】顏色空間轉換CSconvert:YUV420轉YUV444

【Codecs】顏色空間轉換CSconvert:YUV420轉YUV444

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; }