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]|

<br />
cinfo.in_color_space = JCS_YCbCr;<br />

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

以下、ソース

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

</p>
<p>#define	WIDTH	640<br />
#define	HEIGHT	480<br />
#define	QUALITY	90</p>
<p>int grey_to_jpeg(FILE *fp, unsigned char *image)<br />
{<br />
	int y, x, b;<br />
	unsigned char *newimage = NULL;<br />
	JSAMPROW row_ptr[1];<br />
	struct jpeg_compress_struct cinfo;<br />
	struct jpeg_error_mgr jerr;</p>
<p>	cinfo.err = jpeg_std_error(&amp;amp;jerr);  // errors get written to stderr<br />
	jpeg_create_compress (&amp;amp;cinfo);<br />
	cinfo.image_width = WIDTH;<br />
	cinfo.image_height = HEIGHT;<br />
	cinfo.input_components = 1;</p>
<p>	jpeg_set_defaults (&amp;amp;cinfo);<br />
	cinfo.in_color_space = JCS_GRAYSCALE;<br />
	jpeg_set_colorspace(&amp;amp;cinfo, JCS_GRAYSCALE);<br />
	jpeg_set_quality (&amp;amp;cinfo, QUALITY, TRUE);<br />
	cinfo.dct_method = JDCT_FLOAT;<br />
	jpeg_stdio_dest (&amp;amp;cinfo, fp);     // data written to file<br />
	jpeg_start_compress (&amp;amp;cinfo, TRUE);</p>
<p>	newimage = (unsigned char *)malloc( WIDTH * HEIGHT);<br />
	memset( newimage, 0x00, WIDTH * HEIGHT);</p>
<p>	for( y = 0, x = 0; y &amp;lt; HEIGHT; y++, x += WIDTH)<br />
		memcpy( &amp;amp;newimage[x], image + (WIDTH * (fmt.ystart + y) + fmt.xstart), WIDTH);</p>
<p>	row_ptr[0] = newimage;<br />
	for( y = 0, b = 0; y &amp;lt; HEIGHT; y++)<br />
	{<br />
		jpeg_write_scanlines( &amp;amp;cinfo, row_ptr, 1);<br />
		row_ptr[0] += WIDTH;<br />
	}</p>
<p>	jpeg_finish_compress (&amp;amp;cinfo);<br />
	jpeg_destroy_compress (&amp;amp;cinfo);<br />
	free( newimage);</p>
<p>	return 0;<br />
}</p>
<p>int yuv422_to_jpeg(FILE *fp, unsigned char *image)<br />
{<br />
	unsigned long int i, j, k, x, y;<br />
	unsigned char *line = NULL, *newimage = NULL;<br />
	struct jpeg_compress_struct cinfo;<br />
	struct jpeg_error_mgr jerr;</p>
<p>	cinfo.err = jpeg_std_error(&amp;amp;jerr);  // errors get written to stderr<br />
	jpeg_create_compress (&amp;amp;cinfo);<br />
	cinfo.image_width = WIDTH;<br />
	cinfo.image_height = HEIGHT;<br />
	cinfo.input_components = 3;<br />
	cinfo.in_color_space = JCS_YCbCr;</p>
<p>	jpeg_set_defaults (&amp;amp;cinfo);<br />
	jpeg_set_quality (&amp;amp;cinfo, QUALITY, TRUE);<br />
	cinfo.dct_method = JDCT_FLOAT;<br />
	jpeg_suppress_tables(&amp;amp;cinfo, TRUE);<br />
	jpeg_stdio_dest (&amp;amp;cinfo, fp);     // data written to file<br />
	jpeg_start_compress (&amp;amp;cinfo, TRUE);</p>
<p>	newimage = (unsigned char *)malloc(WIDTH * HEIGHT * 3);<br />
	for (j=0; j &amp;lt; HEIGHT; j++)<br />
	{<br />
		for( i = 0, k = 0; i &amp;lt; (WIDTH * 2); i += 4, k += 6)<br />
		{<br />
			newimage[j * WIDTH * 3 + k + 0] = image[j * WIDTH * 2 + i + 0];<br />
			newimage[j * WIDTH * 3 + k + 1] = image[j * WIDTH * 2 + i + 3];<br />
			newimage[j * WIDTH * 3 + k + 2] = image[j * WIDTH * 2 + i + 1];<br />
			newimage[j * WIDTH * 3 + k + 3] = image[j * WIDTH * 2 + i + 2];<br />
			newimage[j * WIDTH * 3 + k + 4] = image[j * WIDTH * 2 + i + 3];<br />
			newimage[j * WIDTH * 3 + k + 5] = image[j * WIDTH * 2 + i + 1];<br />
		}<br />
	}</p>
<p>	newimage = (unsigned char *)malloc( HEIGHT * WIDTH * 3);<br />
	memset( newimage, 0x00, HEIGHT * WIDTH * 3);</p>
<p>	for (j=0, line = newimage; j &amp;lt; HEIGHT; j++,line += 3 * WIDTH)<br />
		jpeg_write_scanlines(&amp;amp;cinfo, &amp;amp;line, 1);</p>
<p>	free( newimage);</p>
<p>	jpeg_finish_compress (&amp;amp;cinfo);<br />
	jpeg_destroy_compress (&amp;amp;cinfo);<br />
}</p>
<p>int yuv420p_to_jpeg(FILE *fp, unsigned char *image, CIMG_FMT fmt)<br />
{<br />
	int i,j;<br />
	JSAMPROW y[16],cb[16],cr[16]; // y[2][5] = color sample of row 2 and pixel column 5; (one plane)<br />
	JSAMPARRAY data[3]; // t[0][2][5] = color sample 0 of row 2 and column 5<br />
	struct jpeg_compress_struct cinfo;<br />
	struct jpeg_error_mgr jerr;<br />
	data[0] = y;<br />
	data[1] = cb;<br />
	data[2] = cr;</p>
<p>	cinfo.err = jpeg_std_error(&amp;amp;jerr);  // errors get written to stderr<br />
	jpeg_create_compress (&amp;amp;cinfo);<br />
	cinfo.image_width = WIDTH;<br />
	cinfo.image_height = HEIGHT;<br />
	cinfo.input_components = 3;<br />
	jpeg_set_defaults (&amp;amp;cinfo);<br />
	jpeg_set_colorspace(&amp;amp;cinfo, JCS_YCbCr);<br />
	cinfo.raw_data_in = TRUE; // supply downsampled data<br />
	cinfo.comp_info[0].h_samp_factor = 2;<br />
	cinfo.comp_info[0].v_samp_factor = 2;<br />
	cinfo.comp_info[1].h_samp_factor = 1;<br />
	cinfo.comp_info[1].v_samp_factor = 1;<br />
	cinfo.comp_info[2].h_samp_factor = 1;<br />
	cinfo.comp_info[2].v_samp_factor = 1;</p>
<p>	jpeg_set_quality (&amp;amp;cinfo, QUALITY, TRUE);<br />
	cinfo.dct_method = JDCT_FLOAT;<br />
	jpeg_stdio_dest (&amp;amp;cinfo, fp);     // data written to file<br />
	jpeg_start_compress (&amp;amp;cinfo, TRUE);</p>
<p>	for (j=0;j &amp;lt; HEIGHT;j+=16)<br />
	{<br />
		for (i=0;i &amp;lt; 16;i++)<br />
		{<br />
			y[i] = image + WIDTH*(i+j);<br />
			if (i%2 == 0)<br />
			{<br />
				cb[i/2] = image + WIDTH * HEIGHT + WIDTH/2*((i+j)/2);<br />
				cr[i/2] = image + WIDTH * HEIGHT + WIDTH * HEIGHT/4 + WIDTH/2*((i+j)/2);<br />
			}<br />
		}<br />
		jpeg_write_raw_data (&amp;amp;cinfo, data, 16);<br />
	}</p>
<p>	jpeg_finish_compress (&amp;amp;cinfo);<br />
	jpeg_destroy_compress (&amp;amp;cinfo);</p>
<p>	return 0;<br />
}<br />

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. ありがとうございました。
    すっきりしました。

コメントを残す