![](/img/trans.png)
[英]How to compress to memory with libjpeg-turbo using jpeg_mem_dest
[英]How to compress YUYV raw data to JPEG using libjpeg?
我正在寻找一个如何使用libjpeg
库将YUYV格式帧保存为JPEG文件的示例。
在典型的计算机API中,“YUV”实际上表示YCbCr,“YUYV”表示存储为Y0,Cb01,Y1,Cr01,Y2的“YCbCr 4:2:2”...
因此,如果您有“YUV”图像,则可以使用JCS_YCbCr颜色空间将其保存到libjpeg。
如果您有422图像(YUYV),则必须在将扫描线写入libjpeg之前将Cb / Cr值复制到需要它们的两个像素。 因此,这个写循环将为您完成:
// "base" is an unsigned char const * with the YUYV data
// jrow is a libjpeg row of samples array of 1 row pointer
cinfo.image_width = width & -1;
cinfo.image_height = height & -1;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_YCbCr;
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, 92, TRUE);
jpeg_start_compress(&cinfo, TRUE);
unsigned char *buf = new unsigned char[width * 3];
while (cinfo.next_scanline < height) {
for (int i = 0; i < cinfo.image_width; i += 2) {
buf[i*3] = base[i*2];
buf[i*3+1] = base[i*2+1];
buf[i*3+2] = base[i*2+3];
buf[i*3+3] = base[i*2+2];
buf[i*3+4] = base[i*2+1];
buf[i*3+5] = base[i*2+3];
}
jrow[0] = buf;
base += width * 2;
jpeg_write_scanlines(&cinfo, jrow, 1);
}
jpeg_finish_compress(&cinfo);
delete[] buf;
如果您的错误或写入函数可以抛出/ longjmp,请使用您喜欢的auto-ptr以避免泄漏“buf”。
直接向libjpeg提供YCbCr更适合转换为RGB,因为它将以该格式直接存储它,从而节省了大量的转换工作。 当图像来自网络摄像头或其他视频源时,在某种类型的YCbCr中获取图像通常也是最有效的(例如YUYV。)
最后,“U”和“V”在模拟分量视频中意味着略有不同,因此YUV在计算机API中的命名实际上意味着YCbCr非常混乱。
libjpeg还具有原始数据模式,您可以直接提供原始下采样数据(这几乎与YUYV格式相同)。 这比复制UV值更有效,只是让libjpeg在内部再次缩小它们。
为此,您使用jpeg_write_raw_data
而不是jpeg_write_scanlines
,默认情况下,它将一次处理16个扫描线。 JPEG期望U和V平面默认为2x下采样。 YUYV格式已经下采样水平尺寸,但不是垂直尺寸,所以我每隔一条扫描线跳过U和V.
初始化:
cinfo.image_width = /* width in pixels */;
cinfo.image_height = /* height in pixels */;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_YCbCr;
jpeg_set_defaults(&cinfo);
cinfo.raw_data_in = true;
JSAMPLE y_plane[16][cinfo.image_width];
JSAMPLE u_plane[8][cinfo.image_width / 2];
JSAMPLE v_plane[8][cinfo.image_width / 2];
JSAMPROW y_rows[16];
JSAMPROW u_rows[8];
JSAMPROW v_rows[8];
for (int i = 0; i < 16; ++i)
{
y_rows[i] = &y_plane[i][0];
}
for (int i = 0; i < 8; ++i)
{
u_rows[i] = &u_plane[i][0];
}
for (int i = 0; i < 8; ++i)
{
v_rows[i] = &v_plane[i][0];
}
JSAMPARRAY rows[] { y_rows, u_rows, v_rows };
压缩:
jpeg_start_compress(&cinfo, true);
while (cinfo.next_scanline < cinfo.image_height)
{
for (JDIMENSION i = 0; i < 16; ++i)
{
auto offset = (cinfo.next_scanline + i) * cinfo.image_width * 2;
for (JDIMENSION j = 0; j < cinfo.image_width; j += 2)
{
y_plane[i][j] = image.data[offset + j * 2 + 0];
y_plane[i][j + 1] = image.data[offset + j * 2 + 2];
if (i % 2 == 0)
{
u_plane[i / 2][j / 2] = image_data[offset + j * 2 + 1];
v_plane[i / 2][j / 2] = image_data[offset + j * 2 + 3];
}
}
}
jpeg_write_raw_data(&cinfo, rows, 16);
}
jpeg_finish_compress(&cinfo);
与@ JonWatte的回答相比,这种方法使压缩时间缩短了33%。 这个解决方案并不适合所有人; 一些警告:
libjpeg-turbo的文档: https : //raw.githubusercontent.com/libjpeg-turbo/libjpeg-turbo/master/libjpeg.txt
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.