LoginSignup
3
1

新しいcodecsの仲間、AVIFのご紹介

Last updated at Posted at 2023-12-23

この記事は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のオプションが増えました。

image.png

(んんんん?最高速設定がデフォルト仕様に見えるでござる、、、)

■ まとめ

  • OpenCVからAVIF Encoder/Decoderが使えるようになりました!
  • チューニングしないデフォルトだと、かなり重い+サイズがでかい…
  • 今回は、画像評価はやってないから、もしかするとサイズが大きい分綺麗かも?
  • 今後の使いこなしが課題。

それでは、ご精読ありがとうございました!!
あしたはアドベントカレンダー最終日となります!!

  1. こちらのコメントで教えていただきました、ありがとうございます! https://qiita.com/hon_no_mushi/items/5309a8d576e9f3cd07b1#comment-4fc4f5fc457e06a48682

3
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1