toruのブログ

月1くらいで記事書きたい。

AVIF の Gain Map HDR 画像を作り Chrome と Edge で表示してみる

背景

  • 2023年に Adobe/AppleGain Map という静止画の HDRに対する技術を提唱した[1]
    • 筆者はテクニカルペーパーを読んで 2024年冒頭に解説記事を投稿した[2]

trev16.hatenablog.com

  • 2025年になり Gain Map をサポートするアプリケーションが増えてきた
  • Chrome と Edge が AVIF の Gain Map をサポートしたので動作を確認することにした

目的

  • AVIF を使った Gain Map画像の作成手順を理解する
  • 作成した画像が正しくブラウザ上で表示されるか確認する
    • テストパターンと自然画の2種類で確認する
  • Gain Map を使う上での特記事項があれば情報として残す

おことわり

このページの画像を正しく表示するには、Webブラウザが AVIF フォーマットの Gain Map画像をサポートしつつ、HDR表示モードになっている必要がある。

以下の画像に「HDR: Supported」と青文字で表示されれば問題ないが、「HDR: Not Supported」と赤文字で表示された場合は、本ページのコンテンツを正しく表示できない。注意して頂きたい。

is_gain_map_hdr_supported
図1. お使いの環境が Gain Map画像の HDR表示をサポートしているか確認する画像

結論1: Gain Map画像の作成手順について

以下の手順で可能。

  • ①SDR画像と HDR画像 を PNG形式で作成する(筆者は DaVinci Resolve を使って作成した *1
  • ②SDR画像と HDR画像を libavif の avifenc コマンドを使って AVIF へと変換する
  • ③SDR画像と HDR画像を libavif の avifgainmaputil コマンドを使って Gain Map 画像に変換する

avifgainmaputil コマンドの詳細は記事後半の Appendix1 を参照。

結論2: Gain Map画像のブラウザ上での表示について

  • Gain Map 部分に関する挙動は仕様書どおりであり問題ない
    • テストパターンと自然画に対して Gain Map 画像を作成した結果を以下に示す。
説明 画像
図2. SDR と Gain Map HDR の比較 (テストパターン)
図3. SDR と Gain Map HDR の比較 (自然画)

ただし、図2と図3をブラウザで見るだけだと「モニターの輝度設定に応じて」画像が変化する様子を観測できない。 そこで、MHC Profile を使い モニターの輝度情報を変更して Gain Map画像が変化する様子 を配信ソフトの OBS でキャプチャして動画にしてみた。以下に動画を添付する *2

動画1. 画面の輝度情報に応じて Gain Map の画像が変わる様子を False Color表示で示したもの

動画の左画面で使用している False Color 表示に関しては筆者の過去記事を参照。

trev16.hatenablog.com

結論3: Gain Map を使う上での特記事項

①Gain Map用の SDR画像は明るさを 100/203 ≒ 0.5 倍すると輝度ズレが無くなる
  • SDR画像は Webブラウザでは 0~203 nits にマッピングされる
    • そのため、特に何もしないと SDR の 1023/1023 CV は100 nits ではなく 203 nits 扱いとなる *3
    • SDR画像の明るさを 0.5倍しておくと 203 nits にマッピングされても輝度が変わらずに済む
  • 0.5倍をした場合としなかった場合の比較を図4 と図5 に示す
説明 画像
図4. SDR を 1.0倍のままにした例。カラーチェッカーを見ると SDR の方が明るくなっている
図5. SDR を 0.5倍した例。カラーチェッカーは SDR と HDR とで同じ明るさとなっている
②テストパターン画像を作る場合、Base Rendition *4 は慎重に選ぶべき
  • 誤差なく確実に表示したい方を Base Rendition とする必要あり
  • 例として図6 (SDR)、図7 (HDR) のテスト画像から Gain Map画像を作成した際に、Base Rendition によって見え方が変わる例を示す
  • 図8 は SDR 画像から HDR 画像を作っているのだが画像中央に「SDR Alternative Image」の文字が薄く残ってしまっている
SDR_Base HDR_Base
図6. SDR のテストパターン画像 図7. HDR のテストパターン画像


SDR_Base HDR_Base
図8. Base Rendition: SDR。HDRの再現に失敗 図9. Base Rendition: HDRHDRの再現に成功


③AVIF の場合、SDR と HDR とで異なる色域を設定できる
  • Adobe/Apple のテクニカルペーパーは輝度方向の変換しか規定しておらず、SDR と HDR は同一の色域である必要があった
  • AVIF では SDR と HDR に個別の CICP を割り当てが可能となっており、異なる色域にも対応している
  • 具体例は Appendix 1 を参照 *5
Windows 環境では SDR content brightness 設定に注意が必要
  • Windows環境においては 過去記事 で書いた「SDR content brightness」の値に応じて HDR画像の輝度が変わる問題がある [3]
    • そのため SDR content brightness は 31 を設定した状態でのコンテンツ表示を推奨する

Appendix1: libavif の avifgainmaputil コマンドの使い方

2025/5/10 にリリースされた libavif v1.3.0 の avifgainmaputil について説明する。名前から分かるように AVIF の Gain Map関連処理を扱いやすくするためのツールである。

avifgainmaputil の使い方は以下の通りであり、第一引数に command を指定して使う。

avifgainmaputil <command> [options] [arguments...]

commandは7種類ある。それぞれの説明を以下に示す*6

コマンド 説明
help コマンドの使い方(Usage)を表示します。
combine base image と alternate image から gain map を含む AVIF 画像を生成します。
convert gain map 付きの JPEG 画像を AVIF 形式に変換します。
tonemap gain map 付きの AVIF 画像を、指定した HDR headroom(SDR に対するディスプレイの明るさ余裕)でトーンマップします。
swapbase base image と alternate image を入れ替えます(例:base image を SDR、alternate image を HDR → base image を HDR、alternate image を SDR に)。
extractgainmap AVIF ファイルから gain map を画像として抽出・保存します。
printmetadata AVIF ファイルの gain map に関するメタデータを表示します。

表を見れば分かると思うが、Gain Map画像の生成にはcombineコマンドを使う。例として冒頭の図3 の Gain Map画像の生成に使用したコマンドを以下に示す。

avifgainmaputil combine \
    ./src_img/kanazawa_castle_01_sRGB_2K.avif \
    ./src_img/kanazawa_castle_01_BT2100-PQ_2K.avif \
    ./gain_map_img/kanazawa_castle_01_sRGB_2K-kanazawa_castle_01_BT2100-PQ_2K.avif \
    --qgain-map 80 \
    --depth-gain-map 10 \
    --yuv-gain-map 444 \
    --cicp-base 1/13/0 \
    --cicp-alternate 9/16/0 \
    --qcolor 80 \
    --depth 10

上記の例ではavifgainmaputil combineに続いてbase_imagealternate_imageoutput_image を指定している。その他の細かいオプションの詳細は Appendix2 を参照して欲しい。

ここで base image、alternate image ついて説明しておく。それぞれ以下を意味している。

  • base image: Adobe の Gain Map仕様書の Base Rendition を意味する
  • alternate image: Base Rendition でない方の Rendition を意味する

Appendix2: libavif の avifgainmaputilcombine コマンドの help

参考情報として avifgainmaputil combine -help の内容を記載しておく。

$ avifgainmaputil combine -help

       usage: avifgainmaputil combine base_image alternate_image output_image.avif 
       [--downscaling DOWNSCALING] [--qgain-map QGAIN-MAP] 
       [--depth-gain-map {8, 10, 12}] [--yuv-gain-map {444, 422, 420, 400}] 
       [--cicp-base CICP-BASE] [--cicp-alternate CICP-ALTERNATE] [-s SPEED] 
       [-q QCOLOR] [--qalpha QALPHA] [-y {444, 422, 420, 400}] 
       [-d {0, 8, 10, 12}] [--ignore-profile] [-h]

Creates an avif image with a gain map from a base image and an alternate image.

arguments:
  base_image        The base image, that will be shown by viewers that don't 
                    support gain maps
  alternate_image   The alternate image, the result of fully applying the gain 
                    map
  output_image.avif
                    
  --downscaling DOWNSCALING
                    Downscaling factor for the gain map (Default: 1)
  --qgain-map QGAIN-MAP
                    Quality for the gain map (0-100, where 100 is lossless) (Default: 60)
  --depth-gain-map {8, 10, 12}
                    Output depth for the gain map (Default: 8)
  --yuv-gain-map {444, 422, 420, 400}
                    Output format for the gain map (Default: 444)
  --cicp-base CICP-BASE
                    Set or override the cicp values for the base image, 
                    expressed as P/T/M where P = color primaries, T = transfer 
                    characteristics, M = matrix coefficients.
  --cicp-alternate CICP-ALTERNATE
                    Set or override the cicp values for the alternate image, 
                    expressed as P/T/M  where P = color primaries, T = transfer 
                    characteristics, M = matrix coefficients.
  -s SPEED, --speed SPEED
                    Encoder speed (0-10, slowest-fastest) (Default: 6)
  -q QCOLOR, --qcolor QCOLOR
                    Quality for color (0-100, where 100 is lossless) (Default: 60)
  --qalpha QALPHA   Quality for alpha (0-100, where 100 is lossless) (Default: 100)
  -y {444, 422, 420, 400}, --yuv {444, 422, 420, 400}
                    Output YUV format for avif (default = automatic)
  -d {0, 8, 10, 12}, --depth {0, 8, 10, 12}
                    Output depth (0 = automatic)
  --ignore-profile  If the input file contains an embedded color profile, ignore 
                    it (no-op if absent) (Default: false)
  -h, --help        Shows this help message

Appendix3: libavif の avifgainmaputil を改造した記録

v1.3.0 の avifgainmaputil combine コマンドは残念なことに、Gain Map の HDR Capacity に任意の値を指定するオプションが用意されていなかった。 そこで、HDR Capacity をコマンドライン引数で設定できるように少し改造を行った。メモとして残しておく。

やったこと

avifgainmaputil combineに引数として--manual-base-hdr-headroom--manual-alternate-hdr-headroomを追加して任意の値を設定可能とした。 (死ぬほど汚い修正だが)ソースコードの変更内容を以下に示す。

github.com

上記の改造版avifgainmaputil combineは以下のテストページの画像作成で大いに役立った。

toru-ver4.github.io

感想

うーん、調査に凄く苦労した割には、読みにくい記事になってしまった。結論欄に色々と詰め込みすぎたか? 果たして何が悪かったのか、その原因を探るため、私はアマゾンの奥地へと向かうのだった…。

次は Ultra HDR について記事を書く予定。最近、Ultra HDR の方が扱いが楽な気がしてきている。この感覚が本当に正しいか確認したい。

参考資料

[1] Adobe, "Gain Map", https://helpx.adobe.com/camera-raw/using/gain-map.html
[2] toruのブログ, "Apple/Adobe の Gain Map HDR について調べて軽く実装をしてみた", https://trev16.hatenablog.com/entry/2024/01/06/093003
[3] toruのブログ, "【静止画編】Windows 11 で HDR コンテンツを「オリジナルのまま加工せずに」モニターへ出力する", https://trev16.hatenablog.com/entry/2024/07/30/195204

*1:もちろん Lightroom などの現像ツールでも作成可能だが、今回は検証のためブラックボックスな処理が入るのは避けたかった。そこで出力値を完璧にコントロールできる DaVinci Resolve を使用した

*2:正直に行ってこの動画は相当に難解である。なぜならば動画の理解には次の3点の事前知識が必要だからである。①OBSというソフトウェアを使ったウィンドウキャプチャ、②OBS上で適用した HDR解析用の False Color表示、③MHC Profile 切り替えによる輝度情報の更新。…こうなってくると筆者しか理解できない気がしている

*3:実際に 203 nits の明るさで表示されるかは別の要因も絡んでくる、というのが更にわかりづらい…

*4:SDR と HDR のどちらを基準にするか

*5:--cicp-base オプションと --cicp-alternate オプションの例を参照

*6:日本語訳は ChatGPT先生が作ってくれました。感謝