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颜色空间的转换,经过测试表明图像效果良好。