メモリ上での画像データの圧縮

16 10月 2010 Under: opencv2.x-samples

imencode,imdecode関数により,ファイルではなく,メモリ上で圧縮ファイルを書込,読込を行います.この関数では非可逆圧縮であるjpeg,可逆圧縮であるpngを指定可能で,それぞれ圧縮品質を指定出来ます.主に,ネットワークで画像を通信するときなどに利用します.この圧縮品質の指定方法はimwrite関数と共通です.
この関数の内部で使われているlibjpegを用いたその他の実装と符号化性能はこちら[link]

C++

#include <iostream>
#include <fstream>
#include <cv.h>
#include <highgui.h>
using namespace std;
using namespace cv;

double getPSNR(Mat& src1, Mat& src2, int bb=0);

int main(int argc, char** argv)
{
	Mat src = imread("lenna.png");

	//(1) jpeg compression
	vector<uchar> buff;//buffer for coding
	vector<int> param = vector<int>(2);
	param[0]=CV_IMWRITE_JPEG_QUALITY;
	param[1]=95;//default(95) 0-100

	imencode(".jpg",src,buff,param);
	cout<<"coded file size(jpg)"<<buff.size()<<endl;//fit buff size automatically.
	Mat jpegimage = imdecode(Mat(buff),CV_LOAD_IMAGE_COLOR);

	//(2) png compression
	param[0]=CV_IMWRITE_PNG_COMPRESSION;
	param[1]=3;//default(3)  0-9.
	imencode(".png",src,buff,param);
	cout<<"coded file size(png)"<<buff.size()<<endl;
	Mat pngimage = imdecode(Mat(buff),CV_LOAD_IMAGE_COLOR);

	//(3) intaractive jpeg compression
	char name[64];
	namedWindow("jpg");
	int q=95;
	createTrackbar("quality","jpg",&q,100);
	int key = 0;
	while(key!='q')
	{
		param[0]=CV_IMWRITE_JPEG_QUALITY;
		param[1]=q;
		imencode(".jpg",src,buff,param);
		Mat show = imdecode(Mat(buff),CV_LOAD_IMAGE_COLOR);

		double psnr = getPSNR(src,show);//get PSNR
		double bpp = 8.0*buff.size()/(show.size().area());//bit/pixe;
		sprintf(name,"quality:%03d, %.1fdB, %.2fbpp",q,psnr,bpp);
		putText(show,name,Point(15,50), FONT_HERSHEY_SIMPLEX,1,CV_RGB(255,255,255),2);
		imshow("jpg",show);
		key = waitKey(33);

		if(key =='s')
		{
			//(4) data writing 
			sprintf(name,"q%03d_%.2fbpp.png",q,bpp);
			imwrite(name,show);

			sprintf(name,"q%03d_%.2fbpp.jpg",q,bpp);
			param[0]=CV_IMWRITE_JPEG_QUALITY;
			param[1]=q;
			imwrite(name,src,param);;
		}
	}
}
double getPSNR(Mat& src1, Mat& src2, int bb)
{
	int i,j;
	double sse,mse,psnr;
	sse = 0.0;

	Mat s1,s2;
	cvtColor(src1,s1,CV_BGR2GRAY);
	cvtColor(src2,s2,CV_BGR2GRAY);

	int count=0;
	for(j=bb;j<s1.rows-bb;j++)
	{
		uchar* d=s1.ptr(j);
		uchar* s=s2.ptr(j);

		for(i=bb;i<s1.cols-bb;i++)
		{
			sse += ((d[i] - s[i])*(d[i] - s[i]));
			count++;
		}
	}
	if(sse == 0.0 || count==0)
	{
		return 0;
	}
	else
	{
		mse =sse /(double)(count);
		psnr = 10.0*log10((255*255)/mse);
		return psnr;
	}
}


(1)jpeg圧縮

encode関数の最後の引数である圧縮オプションを指定するために,CV_IMWRITE_JPEG_QUALITYとその品質(0-100,デフォルトが95)を設定します.数字が多いほど高品質です.encode関数の2番目の引数はvectorで宣言したバッファを入力し,そのサイズは,ちょうど圧縮されたデータのサイズに伸縮します.decode関数はvectorのバッファをMatでキャストして使用します.

(2)png圧縮

jpegの時とほぼ同じです.ただし,圧縮のオプションが,CV_IMWRITE_PNG_COMPRESSION,その圧縮率が, 0-9(デフォルトが3)に変わっています.pngの場合,圧縮率を変化させても画質は原画像とまったく同じままですが,圧縮時間が長くなります.

(3)インタラクティブなjpeg圧縮

jpegの圧縮品質をトラックバーで変更しながら確認します.終了のキーは’q'です.
表示されている数字は品質を指定した数字,その画像品質を表すPSNR,1ピクセル当たり何bitで表現できているかを表すbpp(bit/pixel)です.グレイスケールの時は,8bppのときカラー画像の時は24bppのときに,圧縮がされていないデータを表し,最高品質の例では約1/3に画像が圧縮されています.

(4)画像の保存

‘s’キーで,圧縮により劣化した画像をpngで可逆圧縮,また,原画像をjpegで非可逆圧縮した画像をそれぞれ保存します.
ファイルに書き出す場合は,imwriteでもこのように圧縮率を指定可能です.指定しない場合(この場合pngの圧縮)はデフォルト引数でのパラメータとなります.