この記事はOpenCV Advent Calendar 2023 2ndの24日目の記事です。
他の記事は目次にまとめられています。
■ TL;DR
- OpenCVからAVIF Encoder/Decoderが使えるようになりました!
- チューニングしないデフォルトだと、かなり重い+サイズがでかい…
- 今回は、画像評価はやってないから、もしかするとサイズが大きい分綺麗かも?
- 今後の使いこなしが課題。
■ imgcodecsに新しい仲間、AVIFが追加されたよ!
2023/5 AVIF supportがOpenCV imgcodecsに追加されました、やったー!今回はこの紹介をしていく。
◯AVIFとは何ものぞ?
まずは、AVIFとは何かを簡単にまとめる。
ざっくり言うと、AVIFはAV1 Codec技術を静止画に適用した画像フォーマットである。
なお、コンテナ形式とファイル形式が若干入り組んでいる点には要注意。
- AV1のフレームを、HEIFコンテナ形式で保存している ⇒ AVIFファイル
- H.265のフレームを、HEIFコンテナ形式で保存している ⇒ HEIFファイル
静止画 | 動画 |
---|---|
AVIF | AV1 |
WebP | VP8 |
HEIF | H.265 |
AVIFは、後発の強みを生かし、機能は盛りだくさんである。
特徴 | AVIF | JPEG | PNG |
---|---|---|---|
HDR(ハイダイナミック) | Supported | N/S | 次期仕様でSupported予定1 |
色深度 | 8,10,12 | 8(12,16は一般的ではない) | 8,16 |
Lossy圧縮 | Supported | Supported | N/S |
Lossless圧縮 | Supported | 一般的ではない | Supported |
Alpha | Supported | Not Supported | Supported |
Depth | Supported | Not Supported | Supported |
ICC Profile | Supported | Supported | Supported |
Subsampling | Supported | Supported | N/S |
PNGHDRについては、こちらのコメントで教えていただきました、ありがとうございます! https://qiita.com/hon_no_mushi/items/5309a8d576e9f3cd07b1#comment-4fc4f5fc457e06a48682
■ AVIFサポートを有効にしたOpenCV のbuild
◯AVIF Libraryのインストール
Ubuntu 23.10を使っているならば、libavifというパッケージを利用できます。OpenCVのbuildに使うので、開発用の-devを入れましょう。
sudo apt install libavif-dev libavif15
◯OpenCVのbuildファイルを作成するためにcmakeコマンドを実行する
cmake
を実行するときに、-DWITH_AVIF=ON
を指定する事。明示的に指定をしないと無視されます(OFFになっていることさえも表示されない)。
cmake -S opencv -B build4-main -GNinja -DWITH_AVIF=ON
Build Configurationの結果はこんな感じになる。
-- General configuration for OpenCV 4.8.0-dev =====================================
-- Version control: 4.8.0-570-g953dddd26b
--
-- Platform:
-- Timestamp: 2023-12-23T07:08:47Z
-- Host: Linux 6.5.0-14-generic x86_64
-- CMake: 3.27.4
-- CMake generator: Ninja
-- CMake build tool: /usr/bin/ninja
-- Configuration: Release
-- Media I/O:
-- ZLib: /usr/lib/x86_64-linux-gnu/libz.so (ver 1.2.13)
-- JPEG: /usr/local/lib/libjpeg.so (ver 62)
-- WEBP: build (ver encoder: 0x020f)
-- AVIF: /usr/lib/x86_64-linux-gnu/libavif.so.15.0.1
-- PNG: /usr/lib/x86_64-linux-gnu/libpng.so (ver 1.6.40)
-- TIFF: build (ver 42 - 4.2.0)
-- JPEG 2000: build (ver 2.5.0)
-- OpenEXR: build (ver 2.3.0)
-- HDR: YES
-- SUNRASTER: YES
-- PXM: YES
-- PFM: YES
◯OpenCVをbuild
これはいつものbuildですね
cmake --build build4-main
◯性能を測定してみよう
さて、どれくらいの性能かな?ということで、測定プログラムを組み込んでみよう。
このファイルを置いて、build4-main上でcmake . ; ninja
でできる・・・はず。
kmtr@kmtr-None:~/work/build4-main$ cat ../opencv/modules/imgcodecs/perf/perf_common.cpp
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html
#include "perf_precomp.hpp"
namespace opencv_test
{
using namespace perf;
typedef TestBaseWithParam<tuple<String,ImreadModes,Size>> CodecsCommon;
PERF_TEST_P_(CodecsCommon, Decode)
{
String codecExt = get<0>(GetParam());
ImreadModes immode = get<1>(GetParam());
Size dstSize = get<2>(GetParam());
String filename = getDataPath("perf/2560x1600.png");
cv::Mat src = imread(filename, immode);
cv::Mat dst;
cv::resize(src, dst, dstSize);
vector<uchar> buf;
imencode(codecExt.c_str(), dst, buf);
declare.in(buf).out(dst);
TEST_CYCLE() imdecode(buf, immode);
SANITY_CHECK_NOTHING();
}
PERF_TEST_P_(CodecsCommon, Encode)
{
String codecExt = get<0>(GetParam());
ImreadModes immode = get<1>(GetParam());
Size dstSize = get<2>(GetParam());
String filename = getDataPath("perf/2560x1600.png");
cv::Mat src = imread(filename, immode);
cv::Mat dst;
cv::resize(src, dst, dstSize);
vector<uchar> buf;
imencode(codecExt.c_str(), dst, buf); // To recode datasize
declare.in(dst).out(buf);
TEST_CYCLE() imencode(codecExt.c_str(), dst, buf);
SANITY_CHECK_NOTHING();
}
INSTANTIATE_TEST_CASE_P(/* */,
CodecsCommon,
::testing::Combine(
::testing::Values(
".bmp"
#ifdef HAVE_JPEG
, ".jpg"
#endif
#ifdef HAVE_PNG
, ".png"
#endif
#ifdef HAVE_TIFF
// , ".tif"
#endif
#ifdef HAVE_AVIF
, ".avif"
#endif
#ifdef HAVE_WEBP
, ".webp"
#endif
),
::testing::Values(
ImreadModes(IMREAD_COLOR)
// , IMREAD_GRAYSCALE
),
::testing::Values(
Size(640,480)
, Size(1920,1080)
// , Size(2560,1600)
, Size(3840,2160)
)
)
);
} // namespace
◯テストを実行する
できた実行ファイルを起動する。この時、gtest_output指定がおすすめ。
./bin/opencv_perf_imgcodecs --gtest_filter="*Common*" --gtest_output=xml
実行するとこんな感じでダラダラーって流れて、ここから情報を抜き出すのは大変。これを出力ファイルに出すためのオプションが、gtest_outputである。
OpenCL is disabled
Note: Google Test filter = *Common*
[==========] Running 30 tests from 1 test case.
[----------] Global test environment set-up.
[----------] 30 tests from CodecsCommon
[ RUN ] CodecsCommon.Decode/0, where GetParam() = (".bmp", 1, 640x480)
[ PERFSTAT ] (samples=100 mean=0.06 median=0.06 min=0.06 stddev=0.01 (15.7%))
[ OK ] CodecsCommon.Decode/0 (62 ms)
[ RUN ] CodecsCommon.Decode/1, where GetParam() = (".bmp", 1, 1920x1080)
[ PERFSTAT ] (samples=100 mean=0.99 median=0.99 min=0.91 stddev=0.04 (3.9%))
[ OK ] CodecsCommon.Decode/1 (164 ms)
[ RUN ] CodecsCommon.Decode/2, where GetParam() = (".bmp", 1, 3840x2160)
[ PERFSTAT ] (samples=25 mean=3.36 median=3.34 min=3.26 stddev=0.08 (2.4%))
[ OK ] CodecsCommon.Decode/2 (215 ms)
[ RUN ] CodecsCommon.Decode/3, where GetParam() = (".jpg", 1, 640x480)
[ PERFSTAT ] (samples=13 mean=1.35 median=1.34 min=1.31 stddev=0.04 (2.6%))
◯実行結果をまとめてみる
では得られたxmlファイルを整理してみる…
AVIFくん、Decodeが特に遅すぎるんですけどー!ファイルサイズも大きいんですけどー という結果になった。とほほ...
(私の使う機材が古くて)まあ、HWアシストがないとこんなものですかね。
また、チューニングを何もしていないので、そのあたりやったらまた結果が変わると思います。
※ i7 4770/VMWare/ubuntu上でのざっくりした測定結果。
File | Size | Decode(ms) | Encode(ms) | File |
---|---|---|---|---|
bmp | 640x480 | 0.06 | 0.10 | 921,654 |
1920x1080 | 1.02 | 1.23 | 6,220,854 | |
3840x2160 | 3.32 | 5.23 | 24,883,254 | |
jpg | 640x480 | 1.33 | 1.27 | 50,678 |
1920x1080 | 7.24 | 7.48 | 202,354 | |
3840x2160 | 26.06 | 29.18 | 539,857 | |
png | 640x480 | 3.30 | 5.60 | 134,998 |
1920x1080 | 20.87 | 31.58 | 601,918 | |
3840x2160 | 78.12 | 112.09 | 1,689,892 | |
avif | 640x480 | 17.52 | 56.35 | 173,418 |
1920x1080 | 82.77 | 309.59 | 746,933 | |
3840x2160 | 255.88 | 1360.44 | 2,028,269 | |
webp | 640x480 | 2.42 | 141.84 | 90,704 |
1920x1080 | 12.71 | 653.10 | 391,082 | |
3840x2160 | 43.82 | 2415.63 | 1,091,642 |
生データ
kmtr@kmtr-None:~/work/build4-main$ python3 ../opencv/modules/ts/misc/report.py test_detail.xml | sort -k 1,1 -k 3n
collected samples outliers
Name of Test Number of Number of Min Median Geometric mean Mean Standard deviation
Decode::CodecsCommon::(".avif", 1, 640x480) 10 0 17.19 ms 17.52 ms 17.56 ms 17.56 ms 0.32 ms
Decode::CodecsCommon::(".avif", 1, 1920x1080) 10 0 81.89 ms 82.77 ms 83.19 ms 83.21 ms 1.49 ms
Decode::CodecsCommon::(".avif", 1, 3840x2160) 13 1 253.73 ms 255.88 ms 255.82 ms 255.82 ms 1.22 ms
Decode::CodecsCommon::(".bmp", 1, 640x480) 100 8 0.06 ms 0.06 ms 0.06 ms 0.06 ms 0.01 ms
Decode::CodecsCommon::(".bmp", 1, 1920x1080) 100 8 0.92 ms 1.02 ms 1.02 ms 1.02 ms 0.05 ms
Decode::CodecsCommon::(".bmp", 1, 3840x2160) 38 3 3.18 ms 3.32 ms 3.32 ms 3.32 ms 0.10 ms
Decode::CodecsCommon::(".jpg", 1, 640x480) 100 8 1.27 ms 1.33 ms 1.34 ms 1.34 ms 0.05 ms
Decode::CodecsCommon::(".jpg", 1, 1920x1080) 10 0 7.11 ms 7.24 ms 7.25 ms 7.25 ms 0.11 ms
Decode::CodecsCommon::(".jpg", 1, 3840x2160) 13 1 25.43 ms 26.06 ms 26.03 ms 26.04 ms 0.40 ms
Decode::CodecsCommon::(".png", 1, 640x480) 25 2 3.23 ms 3.30 ms 3.32 ms 3.32 ms 0.09 ms
Decode::CodecsCommon::(".png", 1, 1920x1080) 13 1 20.53 ms 20.87 ms 20.96 ms 20.97 ms 0.33 ms
Decode::CodecsCommon::(".png", 1, 3840x2160) 13 1 76.62 ms 78.12 ms 78.35 ms 78.36 ms 1.11 ms
Decode::CodecsCommon::(".webp", 1, 640x480) 13 1 2.34 ms 2.42 ms 2.44 ms 2.44 ms 0.06 ms
Decode::CodecsCommon::(".webp", 1, 1920x1080) 10 0 12.46 ms 12.71 ms 12.75 ms 12.75 ms 0.21 ms
Decode::CodecsCommon::(".webp", 1, 3840x2160) 25 2 43.15 ms 43.82 ms 44.10 ms 44.11 ms 0.72 ms
Encode::CodecsCommon::(".avif", 1, 640x480) 10 0 55.49 ms 56.35 ms 56.37 ms 56.37 ms 0.53 ms
Encode::CodecsCommon::(".avif", 1, 1920x1080) 10 0 305.32 ms 309.59 ms 308.87 ms 308.88 ms 2.79 ms
Encode::CodecsCommon::(".avif", 1, 3840x2160) 10 0 1338.88 ms 1360.44 ms 1360.16 ms 1360.27 ms 17.94 ms
Encode::CodecsCommon::(".bmp", 1, 640x480) 100 8 0.10 ms 0.10 ms 0.11 ms 0.11 ms 0.01 ms
Encode::CodecsCommon::(".bmp", 1, 1920x1080) 100 8 1.14 ms 1.23 ms 1.23 ms 1.24 ms 0.05 ms
Encode::CodecsCommon::(".bmp", 1, 3840x2160) 13 1 4.97 ms 5.23 ms 5.20 ms 5.20 ms 0.12 ms
Encode::CodecsCommon::(".jpg", 1, 640x480) 10 0 1.20 ms 1.27 ms 1.27 ms 1.27 ms 0.04 ms
Encode::CodecsCommon::(".jpg", 1, 1920x1080) 10 0 7.34 ms 7.48 ms 7.49 ms 7.49 ms 0.08 ms
Encode::CodecsCommon::(".jpg", 1, 3840x2160) 10 0 28.72 ms 29.18 ms 29.26 ms 29.26 ms 0.38 ms
Encode::CodecsCommon::(".png", 1, 640x480) 10 0 5.48 ms 5.60 ms 5.61 ms 5.61 ms 0.10 ms
Encode::CodecsCommon::(".png", 1, 1920x1080) 10 0 31.31 ms 31.58 ms 31.78 ms 31.78 ms 0.50 ms
Encode::CodecsCommon::(".png", 1, 3840x2160) 10 0 110.25 ms 112.09 ms 111.99 ms 112.00 ms 1.19 ms
Encode::CodecsCommon::(".webp", 1, 640x480) 10 0 141.37 ms 141.84 ms 142.21 ms 142.21 ms 1.27 ms
Encode::CodecsCommon::(".webp", 1, 1920x1080) 10 0 651.46 ms 653.10 ms 653.34 ms 653.34 ms 1.51 ms
Encode::CodecsCommon::(".webp", 1, 3840x2160) 10 0 2394.42 ms 2415.63 ms 2411.83 ms 2411.85 ms 10.99 ms
test_detail.xml
◯画像評価は?
今回は時間の都合で、画像評価は割愛です。
もしかするとこの画像サイズに見合った分、画質が綺麗なのかもしれない!
◯使いこなしが課題
AVIF対応に伴い、IMWRITEのオプションが増えました。
(んんんん?最高速設定がデフォルト仕様に見えるでござる、、、)
■ まとめ
- OpenCVからAVIF Encoder/Decoderが使えるようになりました!
- チューニングしないデフォルトだと、かなり重い+サイズがでかい…
- 今回は、画像評価はやってないから、もしかするとサイズが大きい分綺麗かも?
- 今後の使いこなしが課題。
それでは、ご精読ありがとうございました!!
あしたはアドベントカレンダー最終日となります!!
-
こちらのコメントで教えていただきました、ありがとうございます! https://qiita.com/hon_no_mushi/items/5309a8d576e9f3cd07b1#comment-4fc4f5fc457e06a48682 ↩