OpenCVで画像をPNGファイル、すなわち可逆な形式で圧縮し、ファイルで出力することなくデータを取得したいとき、 cv::imencode というエンコード関数を使う。原理的には以下のように記述する。(そのままでは動かないよ)
vector<int> params = vector<int>(2); params[0] = CV_IMWRITE_PNG_COMPRESSION; params[1] = 3; //level std::vector<uchar> buf; cv::imencode(".png", img, buf, params);
ここで、paramsの中身について色々と調べてみた。一種の使い方でもある。以下、CV_IMWRITE_PNG_ は略す。
| params[0] | params[1] | 説明 |
|---|---|---|
| COMPRESSION=16 | 0-9 | 圧縮する。レベルは0-9まで可変 |
| STRATEGY=17 | STRATEGY_DEFAULT=0 | ノーマルデータ |
| STRATEGY_FILTERED=1 | フィルターされた? | |
| STRATEGY_HUFFMAN_ONLY=2 | ハフマン符号化 | |
| STRATEGY_RLE=3 | 一致距離を1つに制限 | |
| STRATEGY_FIXED=4 | 単純なデコーダーが可能になる? | |
| BILEVEL=18 | 0 | 2値化=Bilevelなし |
| 0以外 | 2値化=Bilevelあり |
COMPRESSION では、ストラテジーは STRATEGY_RLE が使われ、圧縮は必ず行われる。
STRATEGY か BILEVEL を使うと、圧縮レベルは内部的に-1がアサインされ、圧縮されない。
paramsを与えない場合、STRATEGYのSTRATEGY_RLEと同じになる。
画像とビデオの読み込みと書き込み — opencv v2.1 documentation
利用可能な上記のテーブルのパラメータについて、圧縮後のデータサイズと処理時間を測定してみた。圧縮レベルは0-3のみ試した。 条件は、ピクセルサイズは2048×1088で、Sizeは出力ファイルサイズ[byte]、Timeは320回の平均の処理時間[msec]である。
2値画像
輝度値、すなわち要素の値が0または1の二値画像(元は原子核乾板の顕微鏡画像)に対して行った。
| params[0] | params[1] | Size | Time |
|---|---|---|---|
| 16 | 0 | 118,938 | 26.3 |
| 16 | 1 | 49,204 | 24.5 |
| 16 | 2 | 49,204 | 23.8 |
| 16 | 3 | 49,204 | 23.6 |
| 17 | 0 | 95,730 | 8.35 |
| 17 | 1 | 95,730 | 8.77 |
| 17 | 2 | 290,162 | 18.2 |
| 17 | 3 | 61,402 | 7.43 |
| 17 | 4 | 115,524 | 8.29 |
| 18 | 0 | 61,402 | 7.72 |
| 18 | 1 | 64,694 | 6.44 |
| bmp | bmp | 2,229,302 | 1.17 |
Timeが3倍変わるのはおいしくないので、 CV_IMWRITE_PNG_STRATEGY の CV_IMWRITE_PNG_STRATEGY_RLE あたりがバランスが良いだろうか。
通常のモノクロ画像
輝度値、すなわち要素の値が0から255までの256階調のモノクロ画像(原子核乾板の顕微鏡画像)に対して行った。
| params[0] | params[1] | Size | Time |
|---|---|---|---|
| 16 | 0 | 2,233,319 | 48.8 |
| 16 | 1 | 1,141,548 | 53.0 |
| 16 | 2 | 1,141,548 | 52.4 |
| 16 | 3 | 1,141,548 | 53.4 |
| 17 | 0 | 1,371,852 | 47.2 |
| 17 | 1 | 1,371,852 | 47.5 |
| 17 | 2 | 1,212,549 | 25.1 |
| 17 | 3 | 1,212,854 | 27.8 |
| 17 | 4 | 1,925,222 | 49.6 |
| 18 | 0 | 1,212,854 | 27.2 |
| 18 | 1 | エラー | エラー |
| bmp | bmp | 2,229,302 | 1.03 |
CV_IMWRITE_PNG_STRATEGY の CV_IMWRITE_PNG_STRATEGY_HUFFMAN_ONLY あたりがバランスが良いだろうか。
カラー画像は用途外なので試していない。
乱数で生成したモノクロ画像
ピクセルサイズ2048×1088の画像に、全てのピクセルに乱数で適当な輝度値を与えた。
| params[0] | params[1] | Size | Time |
|---|---|---|---|
| 16 | 0 | 2,233,324 | 49.1 |
| 16 | 1 | 2,233,324 | 52.3 |
| 16 | 2 | 2,233,324 | 52.6 |
| 16 | 3 | 2,233,324 | 53.5 |
| 17 | 0 | 2,233,319 | 70.6 |
| 17 | 1 | 2,233,319 | 67.8 |
| 17 | 2 | 2,233,324 | 24.3 |
| 17 | 3 | 2,233,324 | 27.6 |
| 17 | 4 | 2,233,319 | 76.1 |
| 18 | 0 | 2,233,324 | 26.1 |
| 18 | 1 | エラー | エラー |
| bmp | bmp | 2,229,302 | 1.17 |
ランダムな輝度値の画像は、想像通りほぼ圧縮されていない。こういうケースでは、bmpをそのまま出力するべきだろう。
パラメータ名の変更
OpenCV3系列から、 CV_IMWRITE_PNG_STRATEGY_DEFAULT 等のグローバル変数は、名前空間 cv内の変数に変わっています。なので、以下のパラメータ名を使ってください。
cv::IMWRITE_PNG_COMPRESSION cv::IMWRITE_PNG_STRATEGY cv::IMWRITE_PNG_BILEVEL cv::IMWRITE_PNG_STRATEGY_DEFAULT cv::IMWRITE_PNG_STRATEGY_FILTERED cv::IMWRITE_PNG_STRATEGY_HUFFMAN_ONLY cv::IMWRITE_PNG_STRATEGY_RLE cv::IMWRITE_PNG_STRATEGY_FIXED