Я ищу пример того, как сохранить кадр формата YUYV в файл JPEG, используя libjpeg
библиотека.
В типичных компьютерных API «YUV» фактически означает YCbCr, а «YUYV» означает «YCbCr 4: 2: 2», сохраняемый как Y0, Cb01, Y1, Cr01, Y2 …
Таким образом, если у вас есть изображение «YUV», вы можете сохранить его в libjpeg, используя цветовое пространство JCS_YCbCr.
Если у вас есть изображение 422 (YUYV), вы должны продублировать значения Cb / Cr на два пикселя, которые им нужны, прежде чем записать строку развертки в libjpeg. Таким образом, этот цикл записи сделает это за вас:
// "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;
Используйте ваш любимый auto-ptr, чтобы избежать утечки «buf», если ваша ошибка или функция записи может генерировать / longjmp.
Предоставление YCbCr для libjpeg напрямую предпочтительнее, чем преобразование в RGB, поскольку оно будет хранить его непосредственно в этом формате, тем самым сохраняя большую часть работы по преобразованию. Когда изображение поступает с веб-камеры или другого видеоисточника, обычно также наиболее эффективно получить его в YCbCr (например, YUYV).
Наконец, «U» и «V» означают что-то немного другое в аналоговом компонентном видео, поэтому наименование YUV в компьютерных API, которое действительно означает, что YCbCr очень запутанно.
libjpeg также имеет режим необработанных данных, благодаря которому вы можете напрямую предоставлять необработанные данные с пониженной дискретизацией (что практически соответствует формату YUYV). Это более эффективно, чем дублирование значений UV только для того, чтобы libjpeg снова уменьшил их внутренне.
Для этого вы используете jpeg_write_raw_data
вместо jpeg_write_scanlines
и по умолчанию он будет обрабатывать ровно 16 строк развертки за раз. JPEG ожидает, что плоскости U и V будут в 2 раза понижены по умолчанию. Формат 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);
Благодаря этому методу мне удалось сократить время сжатия примерно на 33% по сравнению с ответом @ JonWatte. Это решение не для всех, хотя; некоторые предостережения:
Документация для libjpeg-turbo: https://raw.githubusercontent.com/libjpeg-turbo/libjpeg-turbo/master/libjpeg.txt