1.1 顔色空間說明
由于TI提供的H264編碼器隻支援YUV420PSEMI顔色空間的視訊圖像格式,而OV5642不支援輸出這個格式,是以選用了與之比較接近的YUYV422格式,然後由ARM進行轉換。
YUV420PSEMI的格式如下圖所示。UV分量是交錯的,與Y分量分開而單獨存儲在Y分量後面。整幅圖像Y分量占2/3,UV分量占1/3。

YUYV422格式如下圖所示。YUV三個分量是交錯存儲的。
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格式的圖像來進行處理,其原始圖像如下所示。
經過Matlab轉換之後的圖像效果如下所示。
可以看出,經過該算法轉換過後,圖像品質變化不大,證明該算法是可行的,可以将其用到視訊編碼程式中。
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顔色空間的轉換,經過測試表明圖像效果良好。