libjpegを使ってYUVからjpegを作成する

Pocket

元々は、linuxでドライブレコーダーをつくる為に、
USBカメラから取り出したyuvデータをjpegにするために作成
もちろんvideo4linux2を使ってですよ

yuvそのままだと後々面倒なので、
yuvからjpegに変換するためにlibjpegを使いました。
しかし、yuv422 packedかyuv planer の関数がなかったので、
落ちていたソースを参考に作成

GRAY, YUV422Packed と YUV420Planerの関数です。
yuv422Packed は、そのままjpegにできる方法があるかわからなかったので、
YUVのデータをBGRデータをRGBデータにするがごとく、
下のようなyuyvyuyv から
[y00][u0][y01][v0]|[y10][u1][y11][v1]
yuvyuvyuvyuvを作成してます
[y00][u0][v0]|[y01][u0][v0]|

cinfo.in_color_space = JCS_YCbCr;

としている部分がキーでしょうか

以下、ソース

FILE *fp はjpegのファイルポインタ、 *image は yuv のイメージデータです。


#define	WIDTH	640
#define	HEIGHT	480
#define	QUALITY	90

int grey_to_jpeg(FILE *fp, unsigned char *image)
{
	int y, x, b;
	unsigned char *newimage = NULL;
	JSAMPROW row_ptr[1];
	struct jpeg_compress_struct cinfo;
	struct jpeg_error_mgr jerr;

	cinfo.err = jpeg_std_error(&jerr);  // errors get written to stderr
	jpeg_create_compress (&cinfo);
	cinfo.image_width = WIDTH;
	cinfo.image_height = HEIGHT;
	cinfo.input_components = 1;

	jpeg_set_defaults (&cinfo);
	cinfo.in_color_space = JCS_GRAYSCALE;
	jpeg_set_colorspace(&cinfo, JCS_GRAYSCALE);
	jpeg_set_quality (&cinfo, QUALITY, TRUE);
	cinfo.dct_method = JDCT_FLOAT;
	jpeg_stdio_dest (&cinfo, fp);     // data written to file
	jpeg_start_compress (&cinfo, TRUE);

	newimage = (unsigned char *)malloc( WIDTH * HEIGHT);
	memset( newimage, 0x00, WIDTH * HEIGHT);

	for( y = 0, x = 0; y < HEIGHT; y++, x += WIDTH)
		memcpy( &newimage[x], image + (WIDTH * (fmt.ystart + y) + fmt.xstart), WIDTH);

	row_ptr[0] = newimage;
	for( y = 0, b = 0; y < HEIGHT; y++)
	{
		jpeg_write_scanlines( &cinfo, row_ptr, 1);
		row_ptr[0] += WIDTH;
	}

	jpeg_finish_compress (&cinfo);
	jpeg_destroy_compress (&cinfo);
	free( newimage);

	return 0;
}

int yuv422_to_jpeg(FILE *fp, unsigned char *image)
{
	unsigned long int i, j, k, x, y;
	unsigned char *line = NULL, *newimage = NULL;
	struct jpeg_compress_struct cinfo;
	struct jpeg_error_mgr jerr;

	cinfo.err = jpeg_std_error(&jerr);  // errors get written to stderr
	jpeg_create_compress (&cinfo);
	cinfo.image_width = WIDTH;
	cinfo.image_height = HEIGHT;
	cinfo.input_components = 3;
	cinfo.in_color_space = JCS_YCbCr;

	jpeg_set_defaults (&cinfo);
	jpeg_set_quality (&cinfo, QUALITY, TRUE);
	cinfo.dct_method = JDCT_FLOAT;
	jpeg_suppress_tables(&cinfo, TRUE);
	jpeg_stdio_dest (&cinfo, fp);     // data written to file
	jpeg_start_compress (&cinfo, TRUE);

	newimage = (unsigned char *)malloc(WIDTH * HEIGHT * 3);
	for (j=0; j < HEIGHT; j++)
	{
		for( i = 0, k = 0; i < (WIDTH * 2); i += 4, k += 6)
		{
			newimage[j * WIDTH * 3 + k + 0] = image[j * WIDTH * 2 + i + 0];
			newimage[j * WIDTH * 3 + k + 1] = image[j * WIDTH * 2 + i + 3];
			newimage[j * WIDTH * 3 + k + 2] = image[j * WIDTH * 2 + i + 1];
			newimage[j * WIDTH * 3 + k + 3] = image[j * WIDTH * 2 + i + 2];
			newimage[j * WIDTH * 3 + k + 4] = image[j * WIDTH * 2 + i + 3];
			newimage[j * WIDTH * 3 + k + 5] = image[j * WIDTH * 2 + i + 1];
		}
	}

	newimage = (unsigned char *)malloc( HEIGHT * WIDTH * 3);
	memset( newimage, 0x00, HEIGHT * WIDTH * 3);

	for (j=0, line = newimage; j < HEIGHT; j++,line += 3 * WIDTH)
		jpeg_write_scanlines(&cinfo, &line, 1);

	free( newimage);

	jpeg_finish_compress (&cinfo);
	jpeg_destroy_compress (&cinfo);
}

int yuv420p_to_jpeg(FILE *fp, unsigned char *image, CIMG_FMT fmt)
{
	int i,j;
	JSAMPROW y[16],cb[16],cr[16]; // y[2][5] = color sample of row 2 and pixel column 5; (one plane)
	JSAMPARRAY data[3]; // t[0][2][5] = color sample 0 of row 2 and column 5
	struct jpeg_compress_struct cinfo;
	struct jpeg_error_mgr jerr;
	data[0] = y;
	data[1] = cb;
	data[2] = cr;

	cinfo.err = jpeg_std_error(&jerr);  // errors get written to stderr
	jpeg_create_compress (&cinfo);
	cinfo.image_width = WIDTH;
	cinfo.image_height = HEIGHT;
	cinfo.input_components = 3;
	jpeg_set_defaults (&cinfo);
	jpeg_set_colorspace(&cinfo, JCS_YCbCr);
	cinfo.raw_data_in = TRUE; // supply downsampled data
	cinfo.comp_info[0].h_samp_factor = 2;
	cinfo.comp_info[0].v_samp_factor = 2;
	cinfo.comp_info[1].h_samp_factor = 1;
	cinfo.comp_info[1].v_samp_factor = 1;
	cinfo.comp_info[2].h_samp_factor = 1;
	cinfo.comp_info[2].v_samp_factor = 1;

	jpeg_set_quality (&cinfo, QUALITY, TRUE);
	cinfo.dct_method = JDCT_FLOAT;
	jpeg_stdio_dest (&cinfo, fp);     // data written to file
	jpeg_start_compress (&cinfo, TRUE);

	for (j=0;j < HEIGHT;j+=16)
	{
		for (i=0;i < 16;i++)
		{
			y[i] = image + WIDTH*(i+j);
			if (i%2 == 0)
			{
				cb[i/2] = image + WIDTH * HEIGHT + WIDTH/2*((i+j)/2);
				cr[i/2] = image + WIDTH * HEIGHT + WIDTH * HEIGHT/4 + WIDTH/2*((i+j)/2);
			}
		}
		jpeg_write_raw_data (&cinfo, data, 16);
	}

	jpeg_finish_compress (&cinfo);
	jpeg_destroy_compress (&cinfo);

	return 0;
}

3件のコメント

  1. サンプルの69行目にある”yuvimage”は、いきなり出てきて1度だけ使われて
    以後は出てませんが、どういう類のものでしょうか?

  2. yuvimage でなく、newimage でした。すいません。

    RGB から jpeg を作成する場合、
     R[0]G[0]B[0]R[1]G[1]B[1]…R[HxW]G[HxW]B[HxW]
    を作りますよね。

    同じようにYCbCr でも
     Y[0]Cb[0]Cr[0]Y[1]Cb[1]Cr[1]…Y[HxW]Cb[HxW]Cr[HxW]
    を作っていけば jpeg を作れます。

    そのためのメモリが yuvimage 改 newimage になります

  3. ありがとうございました。
    すっきりしました。

コメントを残す