天天看點

YUYV422到YUV420PSEMI格式的轉化

1.1  顔色空間說明

由于TI提供的H264編碼器隻支援YUV420PSEMI顔色空間的視訊圖像格式,而OV5642不支援輸出這個格式,是以選用了與之比較接近的YUYV422格式,然後由ARM進行轉換。

YUV420PSEMI的格式如下圖所示。UV分量是交錯的,與Y分量分開而單獨存儲在Y分量後面。整幅圖像Y分量占2/3,UV分量占1/3。

YUYV422到YUV420PSEMI格式的轉化

YUYV422格式如下圖所示。YUV三個分量是交錯存儲的。

YUYV422到YUV420PSEMI格式的轉化

1.2  Matlab代碼實作顔色空間轉換

為了實作YUYV422到YUV420PSEMI格式的轉換,首先使用Matlab進行程式設計驗證算法可行,然後再移植到視訊編碼的程式中。Matlab實作兩種格式轉換的核心代碼如下所示。

fid = fopen('test_422.264', 'r' );

if fid == -1

    error('Cannot open file.');

end

hor = 640;

ver = 480;

for i=1:ver

    picture(i,:) = fread(fid, hor * 2, 'uint16');

end

fclose(fid);

picture = picture./4;

y = uint8(zeros(ver, hor));

u = uint8(zeros(ver, hor));

v = uint8(zeros(ver, hor));

for i = 1:ver

    for j = 1:4:hor * 2

        y(i, (j + 1)/2) = picture(i, j);

        u(i, (j + 1)/2) = picture(i, j + 1);

        u(i, (j + 3)/2) = picture(i, j + 1);

        y(i, (j + 3)/2) = picture(i, j + 2);

        v(i, (j + 1)/2) = picture(i, j + 3);

        v(i, (j + 3)/2) = picture(i, j + 3);

    end

end

% figure,imshow(y, [ ]);

frame(:, :, 1) = y;

frame(:, :, 2) = u;

frame(:, :, 3) = v;

rgb = ycbcr2rgb(frame);

figure,imshow(rgb);

% write 420 file

fid = fopen('test_420.264', 'w' );

if fid == -1

    error('Cannot open file.');

end

for i = 1:ver

    fwrite(fid, y(i,:), 'uint8');

end

for i = 1:2:ver

    for j = 1:2:hor

        fwrite(fid, u(i,j), 'uint8');

        fwrite(fid, v(i,j), 'uint8');

    end

end

fclose(fid);

取一幅原始的YUYV422格式的圖像來進行處理,其原始圖像如下所示。

YUYV422到YUV420PSEMI格式的轉化

經過Matlab轉換之後的圖像效果如下所示。

YUYV422到YUV420PSEMI格式的轉化

可以看出,經過該算法轉換過後,圖像品質變化不大,證明該算法是可行的,可以将其用到視訊編碼程式中。

1.3  C語言實作顔色空間轉換

在視訊編碼程式中進行圖像格式轉換時,必須要注意OV5642傳過來的資料時10-bit,而不是像TVP5150那樣為8-bit。如果是8-bit資料,那麼處理比較友善,因為在編碼器支援的是8-bit格式,而且DMAI中的Buffer子產品也是将像素點資料定義的8-bit模式。是以,在使用C語言對視訊緩沖區資料進行格式轉換時,需要對指向這些資料的指針進行強制類型轉換,将Int8 *型轉換為Int16 *型。使用C語言進行格式轉換的代碼如下所示。

Void YUYV10_to_YUV420PSEMI8(Buffer_Handle hSrcBuf, Buffer_Handle hDstBuf)

{

    BufferGfx_Dimensions srcDim;

    BufferGfx_Dimensions dstDim;

    UInt32 srcOffset, dstOffset;

    Int8 *src, *dst_Y, *dst_UV;

Int i, j;

    BufferGfx_getDimensions(hSrcBuf, &srcDim);

    BufferGfx_getDimensions(hDstBuf, &dstDim);

    src    = Buffer_getUserPtr(hSrcBuf);

    dst_Y  = Buffer_getUserPtr(hDstBuf);

    dst_UV = Buffer_getUserPtr(hDstBuf) + srcDim.width * srcDim.height;

    if (dst_Y != src) {

        for (i = 0; i < srcDim.height; i++) {

            if (i % 2 == 1) {

                for (j = 0; j < srcDim.width * 4; j += 8) {

                    *dst_Y = ((*((Int16 *)(src + 0))) / 4) & 0xff;

                    dst_Y ++;

                    *dst_Y = ((*((Int16 *)(src + 4))) / 4) & 0xff;

                    dst_Y ++;

                    *dst_UV = ((*((Int16 *)(src + 2))) / 4) & 0xff;

                    dst_UV ++;

                    *dst_UV = ((*((Int16 *)(src + 6))) / 4) & 0xff;

                    dst_UV ++;

                    src += 8;

                }

            }

            else {

                for (j = 0; j < srcDim.width * 4; j += 8) {

                    *dst_Y = ((*((Int16 *)(src + 0))) / 4) & 0xff;

                    dst_Y ++;

                    *dst_Y = ((*((Int16 *)(src + 4))) / 4) & 0xff;

                    dst_Y ++;

                    src += 8;

                }

            }

        }

    }

    Buffer_setNumBytesUsed(hDstBuf, srcDim.width * srcDim.height * 3 / 2);

}

使用該算法進行YUYV422到YUV420PSEMI顔色空間的轉換,經過測試表明圖像效果良好。

繼續閱讀