toruのブログ

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

DaVinci Resolve を使って Apple Log の特性を調べてみた

1. 背景

  • 筆者は iPhone 15 Pro MAX を購入した
  • iPhone 15 では Blackmagic Cam App を使うことで Apple Log を使った HDR撮影が可能である
  • 筆者はウキウキでテスト撮影をしたのだが、撮影中のモニター表示は Log のままであり露出調整が困難だった
  • そこで EL Zone System [1] を参考に露出調整用の View LUT を作成しようと考えた
  • しかし残念なことに Apple Log の特性は一般公開されていないため View LUT が作成できない状況にあった
  • View LUT を作らずに撮影を行うことは困難だったため DaVinci Resolve を使って Apple Log の特性を調査することにした

2. 目的

  • Apple Log の Encode/Decode の特性を調べる
  • Apple Log の色域を調べる
  • 得られた特性を利用して撮影時の露出調整用の View LUT を作成する

3. 結論

Apple Log の Encode/Decode の特性

DaVinci Resolve を使うことで Apple Log の特性を得ることに成功した。 Apple Log 単体の Encoding Function (OETF) の特性を図1に、他の Encoding Function との比較を図2に示す。

図1. Apple Log の特性 図2. 様々な Log Encoding との比較
Apple Log の色域

DaVinci Resolve を使うことで Apple Log の色域が Rec.2020 であることが分かった。

撮影時の露出調整用の View LUT の作成

得られた Apple Log の特性を利用して露出調整用の View LUT を作成することに成功した。撮影に使用した様子を動画1 に示す。


動画1. 撮影用に EL Zone System を用いた Apple Log 用の View LUT を適用した様子

4. 結論に至るまでの経緯

4.1. 作業環境

今回、筆者が作業を行った環境は以下の通りである。

名称 Version
Python 関連 リンク先pip listの結果参照 ()
iPhone iPhone 15 Pro Max
iOS 17.0.3
Blackmagic Cam 1.1.00029

ちゃんと確認したら自前でコンパイルしたライブラリはリストに表示されてなかったですね…

4.2. Apple Log の Encoding Function の調査

実は筆者は Resolve を利用した Cmera Log の特性調査を 4年前に一度行ったことがあった。そのため今回も同様の考え方を用いて調査を行った。

trev16.hatenablog.com

おおまかな確認手順は以下の通りである。

  1. Resolve に読み込むテストパターン画像の作成
  2. Resolve を使いテストパターンに対して Apple Log の Encoding Function を適用し EXR形式で保存
  3. EXRファイルから Apple Log の Encoding Function を実現する 1DLUT を作成
  4. 1DLUT を使い Apple Log の特性をプロット
4.2.1. Resolve に読み込むテストパターン画像の作成

まず Resolve への入力となる Log2 スケールの Ramp パターン画像を作成した。 ここで Log2 スケールとは水平方向に Log2 の空間で等間隔になるスケールを意味する。

例として 0~16 までを Log2 で刻んだ結果を以下に示す(比較対象として Linearスケールも併記した)。

# Log2 Scale
[ 0.0625, 0.125, 0.25, 0.5, 1, 2, 4, 8, 16 ]

# Linear Scale
[ 0, 2, 4, 6, 8, 10, 12, 14, 16 ]

画像の作成には以下のようなコードを使用した(別途 OpenImageIO が必要かも?)。

import numpy as np
from colour.io import write_image

def create_test_pattern_for_apple_log_encoding_analysis():
    width = 1920
    height = 1080
    ref_val = 0.18
    exp_range = 12

    def create_log2_x_scale(
            sample_num=32, ref_val=1.0, min_exposure=-6.5, max_exposure=6.5):
        x_min = np.log2(ref_val * (2 ** min_exposure))
        x_max = np.log2(ref_val * (2 ** max_exposure))
        x = np.linspace(x_min, x_max, sample_num)
        return 2.0 ** x

    def h_mono_line_to_img(line, height):
        return line.reshape(1, -1, 1).repeat(3, axis=2).repeat(height, axis=0)

    x = create_log2_x_scale(
        sample_num=width, ref_val=ref_val,
        min_exposure=-exp_range, max_exposure=exp_range)
    img = h_mono_line_to_img(x, height)
    fname = f"./img/src_log2_-{exp_range}_to_{exp_range}_stops.exr"
    print(fname)
    write_image(img, fname)
4.2.2. Resolve を使いテストパターンに対して Apple Log の Encoding Function を適用し EXR形式で保存

生成した画像は前述のコードを見ればわかるように Linear データである。これを Resolve を使って Apple Log に変換した。 Resolve の Color Management 設定を図3 の通りに設定し、Apple Log に変換して EXR 形式で出力した (図4)。

図3. Color Management の設定 図4. 出力設定
4.2.3. EXRファイルから Apple Log の Encoding Function を実現する 1DLUT を作成

Resolve から出力された画像は Log2 スケール上の Linear データを Apple Log で Encode したデータ列 である。 そのため、このデータ列は Shaper を適用済みの 1DLUT とみなすことができる。

ということで、今回は このデータ列を Apple Log の Encoding function を得るための 1DLUT として利用した。 具体的には以下のようなコードを準備して Apple Log の Encoding function を実現した。

import numpy as np
from colour.utilities import tstack
from colour.io import read_image

def save_apple_log_as_1dlut():
    resolve_out_exr= "./secret/apple_log_encode_out.exr"
    img = read_image(resolve_out_exr)
    width = img.shape[1]
    ref_val = 0.18
    exp_range = 12

    x = create_log2_x_scale(
        sample_num=width, ref_val=ref_val,
        min_exposure=-exp_range, max_exposure=exp_range)
    y = img[0, ..., 1]  # extract horizontal green line data 
    lut = tstack([x, y])
    np.save("./secret/apple_log_encode_lut.npy", lut)

def log_encoding_apple_log(x):
    """
    Scence linear to Apple Log.

    Parameters
    ----------
    x : ndarray
        Scene linear light (1.0 is SDR diffuse white)

    Examples
    --------
    >>> log_encoding_apple_log(0.18)
    0.488271418052

    Note
    ----
    Valid range of `x` is from 2^-12 to 2^12
    """
    lut_1d = np.load("./secret/apple_log_encode_lut.npy")
    y = np.interp(x, xp=lut_1d[..., 0], fp=lut_1d[..., 1])

    return y

簡単に説明すると log_encoding_apple_log をコールすると save_apple_log_as_1dlut にて作成した 1DLUT を参照し、 np.interp を使って LUT から Apple Log の値を得る仕組みになっている。

以上により Apple Log の Encoding Function を得ることができた。

4.2.4. 1DLUT を使い Apple Log の特性をプロット

作成した log_encoding_apple_log を使い、以下のようなコードを用いて特性をプロットした。 結果は冒頭の図1、図2 を参照…なのだが見やすいように以下にも再掲しておく。

import matplotlib.pyplot as plt

def plot_apple_log_for_blog():
    x = create_log2_x_scale(
            sample_num=32, ref_val=0.18,
            min_exposure=-12, max_exposure=12)
    apple_log = log_encoding_apple_log(x)
    x_plot = x / 0.18  # To set 18% grey to 0.0 on a Log2 scale
    fig = plt.figure(figsize=(10, 6))
    ax = fig.add_subplot(111)
    ax.set_xscale('log', base=2)
    ax.plot(x_plot, apple_log, '-o')
    plt.show()


図1 (再掲) Apple Log の特性 図2 (再掲) 様々な Log Encoding との比較

図を見ると、Apple Log は S-Log3 や LogC4 などのシネマカメラで使用される Camera Log と比較すると 収録可能なダイナミックレンジが狭いことがわかる (携帯用デバイスの Log なので実運用上は全く問題はないだろうが)。

4.3. Apple Log の Decoding Function の調査

Encoding Function の逆の作業を行っただけなので省略。

4.4. Apple Log の色域の調査

Apple Log の色域に関しても Resolve を使うことで簡単に調べることができた。 色々とやり方はあるのだが、ここでは Video Scope にある CIE Chromaticity を使った確認方法を紹介する。

やり方は非常に簡単で、Color Management 設定で Output color space に Apple Log を指定した状態で Video Scope を CIE Chromaticity に変更するだけである。すると現在の Output color space の色域が右上に表示される (図5 の② を参照)

図5. CIE Chromaticity を使って色域を確認している様子

ということで Apple Log の色域は Rec.2020 であることが分かった。

4.5. Apple Log 用の撮影補助用 View LUT の作成

ここまでの内容により Apple Log の特性を理解することができた。ここから Apple Log 用の View LUT 作成の話をしていく。

4.5.1. そもそも View LUT が必要になった理由について

初めに View LUT が必要となった理由を簡単に述べておく。

iPhone 15 Pro で動作する Blackmagic Cam App は Color Space に「Apple Log - HDR」を指定した場合、以下の図6 のような表示となる。 これは SDRモードで表示している iPhone のディスプレイに Apple Log が表示される形となっており、 自分のような素人にとっては露出調整が極めて困難であった。

図6. Apple Log が SDRレンジにマッピングされて表示される様子

一応、Blackmagic Cam App には標準でフォルスカラー表示も用意されていたのだが、 Apple Log の Code Value の 0~100% に対して色付けをする仕様となっており、やはり自分のような素人には扱いが困難であった。

そこで今回は EL Zone System を利用した View LUT を自作して適用することにした。

4.5.2. EL Zone System の概要および本記事での実装方針

ここで EL Zone System について補足説明しておく。EL Zone System は Webページ を見ると分かるように Linear値の 18% Gray を基準したフォルスカラー表示を行う技術である。 そのため Log Encoding の特性に依らず、HLG でも S-Log3 でも LogC4 でも一貫したフォルスカラー表示が可能となる素晴らしい技術である。

当然、Apple Log に関しても Decoding Function の特性が分かっていれば利用可能である。 しかし EL Zone System は詳細仕様が公開されていないため、今回は筆者の独自解釈による実装を行うことにした (そのため作成した View LUT は非公開とする)。

4.5.3. View LUT の作成および動作確認

ということで、以下で EL Zone System を用いた View LUT の生成方法および動作確認の方法について述べていく。

View LUT は 65x65x65 の 3DLUT として作成した。アルゴリズムの説明は非常に簡単なので省略する。 生成用のサンプルコードは リンク先に掲載した。興味のある方は確認して頂きたい。

続いて作成した View LUT の動作確認を行った。 動作確認用に「水平方向に Log2 スケールで増加する Scene Linear Light」を「Apple Log で Encode」したテストパターンを作成し、 Resolve 上でテストパターンに View LUT を適用して 18% Grey基準のフォルスカラー表示となるか確認した。

テストパターンの生成コードを以下に、テストパターンの様子を図7に、Resolve上で View LUT を適用した結果を図8 に示す。

def create_tp_for_verify_el_zone_system_lut_apple_log():
    width = 1920
    height = 1080
    num_of_sample = width
    ref_val = 0.18
    exp_range = 8
    x = create_log2_x_scale(
        sample_num=num_of_sample, ref_val=ref_val,
        min_exposure=-exp_range, max_exposure=exp_range)
    y = log_encoding_apple_log(x)
    img = h_mono_line_to_img(y, height)
    fname = "./img/src_apple_log_log2_"
    fname += f"-{exp_range}_to_{exp_range}_stops.exr"
    print(fname)
    write_image(img, fname)


図7. テストパターンの見た目 図8. テストパターンに View LUT を適用した様子

今回、このテストパターンは 18% Grey 基準で -8 stops ~ +8 stops のレンジで作成した。 そのため EL Zone System の黒色~白色までの 17色が等間隔で表示されれば良い (-0.5, 0.0, +0.5 stops は 1/2 の間隔)。

右端が白色 (Over Exposed) にならずに 16色表示となってしまっているが、 これは 図1 を見ればわかるように Apple Log が +6 Stops までのレンジしかないことが原因である。よって問題ではない。

よって図8 の結果から View LUT は狙い通りに作成できたと判断した。

作成した View LUT は iPhone 15 Pro にコピーを行い、Blackmagic Cam で読み込んで View LUT として使用した。 実際に適用している様子が冒頭の動画である。こちらの動画も以下に再掲しておく。


動画1. 撮影用に EL Zone System を用いた Apple Log 用の View LUT を適用した様子

4.6. ソースコード

確認に使用したソースコード一式は以下にある。例によって筆者の環境でないと正常に動作しないと思われるが、参考データとして提供する。

github.com

5. 感想

筆者の知的好奇心は満たされた。満足した。

次は Gain Map HDR について調査してまとめる予定である(スペクトルの勉強はどうした?センサーも買ったのに全然使ってないぞ??)。

6. 参考資料

[1] Cinecam Inc. "EL Zone System", https://www.elzonesystem.com/

JPEG XL のHDR画像を作成し iPad の Safari 17 で HDR表示を試した

1. 背景

  • 2023年9月にリリース予定の Safari 17 の Beta Release Notes を確認すると「Added support for JPEG XL」の記述があった[1]
  • JPEG XL は BT.2100 PQ や BT.2100 HLG などの HDRの色空間をサポートした画像フォーマットである
  • そのため筆者は「iPhoneiPad で簡単に静止画の HDR表示が試せるのでは?」と考えた
  • そこで実際に試すことにした

2. 目的

  • HDR画像を JPEG XL形式で作成する
  • 併せて JPEG XL における色空間に関するパラメータを調査する
  • 作成した JPEG XL ファイルを使い iPadSafari 17 Beta で HDR表示を試す

3. 結論

  • BT.2100 PQ や BT.2100 HLG などの HDRの色空間の画像ファイルの生成に成功した
    • 作成したファイルは リンク先 からダウンロード可能
  • JPEG XL における色空間に関するパラメータとして以下の存在を確認した
    • color_space,white_point,primaries,rendering_intent,transfer_function
    • intensity_target,min_nits,linear_below
  • 第5世代 iPad Pro を使い Safari 17 Beta にて JPEG XL の HDR表示を試したが失敗した
    • 画像には HDR to SDR 変換が適用されてしまい SDR表示となった
    • iPadOS の Safari 17 は JPEG XLフォーマットには対応するが HDR表示は非サポートのようである (※1)

※1 筆者は macOSSafari 17 は HDR表示をサポートすると予想しているが、手元に macOS の機材が無いため未確認である

確認に使用した機材やツールのバージョンは以下の通りである。

機材 or ツール名 バージョン
iPad Pro 12.9-inch, 5th generation
iPadOS 17.0 Beta (21A5326a)
libjxl (JPEG XL のライブラリ) v0.9.0 ff8a9c1c

4. 詳細

4.1. JPEG XL フォーマットについて

全体概要に関しては libjxl の JPEG XL Format Overview を参照。

カラーマネジメントの概要に関しては libjxl の Color Management を参照。

4.2. HDR画像を JPEG XL フォーマットで保存する方法

筆者は PNG 形式の HDR画像をcjxlコマンドで JPEG XL形式に変換することで実現した。具体的な手順を以下に示す。

まず JPEG XL のリファレンス実装である libjxl をビルドした (※2)。 次にビルドで生成したcjxlを使い事前に作成した PNG画像を JPEG XL形式に変換した。その際に-x color_spaceオプションを使用して HDRに関するパラメータを指定した[2][3] (※3)。

cjxlコマンドを使った具体例を以下に示す。以下の例では BT.2100-HLG、BT.2100-PQ、P3D65-PQ の3種類の HDR画像を生成している。

# BT.2100-HLG
cjxl BT2100_HLG.png BT2100_HLG.jxl -x color_space=RGB_D65_202_Rel_HLG

# BT.2100-PQ
cjxl BT2100_PQ.png BT2100_HLG.jxl -x color_space=RGB_D65_202_Rel_PeQ

# P3D65-PQ (ST 2084)
cjxl P3D65_PQ.png P3D65_PQ.jxl -x color_space=RGB_D65_DCI_Rel_PeQ

ここで -x color_spaceオプションについて補足をする。指定するRGB_D65_202_Rel_HLGRGB_D65_202_Rel_PeQといった文字列は色空間に関するパラメータを並べたものである。 左からそれぞれcolor_space,white_point,primaries,rendering_intent,transfer_functionを意味する。これらに関しては次節で詳しく述べる。

cjxlコマンドで正しく HDR画像が生成できたかは jxlinfoコマンドで確認できる。動作例は 付録1 を参照。 また cjxlコマンドの その他のオプションに関しては 付録2 を参照して頂きたい。

※2 ビルドが面倒であれば公式がリリースしている ビルド済みバイナリ を使っても良い
※3 静止画では ICC Profile を使って色空間の指定をするのが一般的だが、現行の ICC v4 では HDR空間を正しく扱えないため CICP を使用している。CICPに関しては AVIF の過去記事 を参照

4.3. JPEG XL における色空間に関するパラメータの調査結果

調査の結果 8種類のパラメータの存在を確認した。各パラメータの意味を以下の表に示す。 加えて-x color_spaceオプションで指定可能な3文字のパラメータに関しても ソースコードを参考に 実際の値との対応関係を記載した[4]。

パラメータ名 説明 -x color_spaceオプションでの3文字表記との関係[4]
color_space 色空間。RGB, XYB など RGB: RGB
Gra: Gray
XYB: XYB
CS?: Unknown
white_point 白色点。D65, DCI-P3 など D65: D65
Cst: Custom
EER: E光源の白色点
DCI: DCI-P3
primaries 色域。sRGB, BT.2020 など SRG: sRGB
202: BT.2020
DCI: DCI-P3
Cst: Custom
transfer_function OETF。PQ, HLG など SRG: sRGB
Lin: Linear
709: BT.709
PeQ: PQ (ST 2084)
HLG: HLG
DCI: Gamma 2.6
TF?: Unknown
rendering_intent Rendering intent。
詳細は ICC の Specification 参照
Per: Perceptual
Rel: Relative
Sat: Saturation
Abs: Absolute
intensity_target 画像内の輝度レベルの上限値を
nits で示したもの[5]
-
min_nits 画像内の輝度レベルの下限値を
示したもの[5]
-
linear_below tome mapping の実行時に
変更を加えない上限の輝度レベル[5]
-

なお、2023年9月9日の時点では min_nits, linear_below の値をcjxlコマンドで設定できなかった(筆者はソースコードの初期値を変えてリビルドすることで対応した)。 また、後半の 3変数intensity_target, min_nits, linear_belowがデコード時の画面描画時に必ず参照されるのかは不明である (ISO/IEC 18181 を読めば分かるのかもしれないが筆者には購入するほどのモチベは無かった…)。

4.4. iPadSafari 17 での表示確認

作成した JPEG XLファイルを iPadOS 17 Beta の Safari 17 Beta にて表示した。確認に使用した画像の一覧を以下の表に示す。

結果は冒頭で述べた通り HDR表示はできなかった。一方で HDR to SDR 変換は働いており、画像データに埋め込んだ色情報は正しく認識されているようである(HLGの結果がかなり怪しいが…)。 なお、作成した JPEG XL データが本当に HDR表示に対応したものかは、別途 Adobe Camera Raw を使って確認済みである(詳細は省略)。

Primaries, Transfer function JPEG XL (対応ブラウザで確認下さい[6]) 参考としての PNG (カラマネ無し)
BT.709, sRGB srgb_xl srgb_png
BT.709, BT.709 (※4) 709_xl 709_png
DCI-P3, PQ p3pq_xl p32084
BT.20020, PQ 2100pq_xl 2020_pq
BT.2020, HLG (※5) hlg_xl hlg_png

※4 モニター側の EOTF が BT.1886 であると想定し画像データは Gamma 1/2.4 の OETF でエンコードした
※5 モニター側の OOTF (Gamma = 1.2) が適用された場合に適切な色となるよう事前に画像データへ Inverse OOTF を適用した

5. 感想

この記事を通じて AVIF に続き JPEG XL に関しても HDRの画像を生成できるようになった。

色々と試していて思ったが tone mapping, gamut mapping がやはり鬼門だと思う。HDR/WCG は表示デバイスごとに表示性能の差があまりにも大きくて、 一体全体どう変換するのが最適なのか未だに分からない。

様々な実装が提案されているが国際標準に至るものはなく、輝度や色度が制限されたモニターにおける「正しい HDR表示」をどう定義すれば良いのか本当に分からない。 一方で、この分野における技術的な興味は尽きてないので引き続き色々と最新情報を確認していきたい(全然確認が追いついていないが…)。

6. 付録

6.1. 付録1 jxlinfoコマンドの紹介

JPEG XL ファイルの色空間に関する情報を調べるにはjxlinfoが便利である(libjxl をビルドすると生成される)。

例として jxlinfo ./img/D65_202_PeQ.jxl を実行した際の具体的な出力を以下に示す。

JPEG XL file format container (ISO/IEC 18181-2)
JPEG XL image, 1920x1080, (possibly) lossless, 16-bit RGB
intensity_target: 10000.000000 nits
min_nits: 0.000000
relative_to_max_display: 0
linear_below: 0.000000
Color space: RGB, D65, Rec.2100 primaries, PQ transfer function, rendering intent: Relative

6.2. 付録2 cjxlコマンドの Usage

参考情報として cjxl -v コマンドの実行結果を以下に添付する。

JPEG XL encoder v0.9.0 ff8a9c1c [AVX2,SSE4,SSE2]
Usage: cjxl INPUT OUTPUT [OPTIONS...]
 INPUT
    the input can be PNG, APNG, GIF, JPEG, EXR, PPM, PFM, PAM, PGX, or JXL
 OUTPUT
    the compressed JXL output file

Basic options:
 -d DISTANCE, --distance=DISTANCE
    Target visual distance in JND units, lower = higher quality.
    0.0 = mathematically lossless. Default for already-lossy input (JPEG/GIF).
    1.0 = visually lossless. Default for other input.
    Recommended range: 0.5 .. 3.0. Allowed range: 0.0 ... 25.0. Mutually exclusive with --quality.
 -q QUALITY, --quality=QUALITY
    Quality setting, higher value = higher quality. This is internally mapped to --distance.
    100 = mathematically lossless. 90 = visually lossless.
    Quality values roughly match libjpeg quality.
    Recommended range: 68 .. 96. Allowed range: 0 .. 100. Mutually exclusive with --distance.
 -e EFFORT, --effort=EFFORT
    Encoder effort setting. Range: 1 .. 9.
    Default: 7. Higher numbers allow more computation at the expense of time.
    For lossless, generally it will produce smaller files.
    For lossy, higher effort should more accurately reach the target quality.
 -V, --version
    Print encoder library version number and exit.
 --quiet
    Be more silent
 -v, --verbose
    Verbose output; can be repeated and also applies to help (!).

Advanced options:
 -a A_DISTANCE, --alpha_distance=A_DISTANCE
    Target visual distance for the alpha channel, lower = higher quality.
    0.0 = mathematically lossless. 1.0 = visually lossless.
    Default is to use the same value as for the color image.
    Recommended range: 0.5 .. 3.0. Allowed range: 0.0 ... 25.0.
 -p, --progressive
    Enable (more) progressive/responsive decoding.
 --group_order=0|1
    Order in which 256x256 groups are stored in the codestream for progressive rendering.
    0 = scanline order, 1 = center-first order. Default: 0.
 --container=0|1
    0 = Avoid the container format unless it is needed (default)
    1 = Force using the container format even if it is not needed.
 --compress_boxes=0|1
    Disable/enable Brotli compression for metadata boxes. Default is 1 (enabled).
 --brotli_effort=B_EFFORT
    Brotli effort setting. Range: 0 .. 11.
    Default: 9. Higher number is more effort (slower).
 -m 0|1, --modular=0|1
    Use modular mode (default = encoder chooses, 0 = enforce VarDCT, 1 = enforce modular mode).
 -j 0|1, --lossless_jpeg=0|1
    If the input is JPEG, losslessly transcode JPEG, rather than using reencode pixels.
 --num_threads=N
    Number of worker threads (-1 == use machine default, 0 == do not use multithreading).
 --photon_noise_iso=ISO_FILM_SPEED
    Adds noise to the image emulating photographic film or sensor noise.
    Higher number = grainier image, e.g. 100 gives a low amount of noise,
    3200 gives a lot of noise. Default is 0.
 --intensity_target=N
    Upper bound on the intensity level present in the image, in nits.
    Default is 0, which means 'choose a sensible default value based on the color encoding.
 -x key=value, --dec-hints=key=value
    This is useful for 'raw' formats like PPM that cannot store colorspace information
    and metadata, or to strip or modify metadata in formats that do.
    The key 'color_space' indicates an enumerated ColorEncoding, for example:
      -x color_space=RGB_D65_SRG_Per_SRG is sRGB with perceptual rendering intent
      -x color_space=RGB_D65_202_Rel_PeQ is Rec.2100 PQ with relative rendering intent
    The key 'icc_pathname' refers to a binary file containing an ICC profile.
    The keys 'exif', 'xmp', and 'jumbf' refer to a binary file containing metadata;
    existing metadata of the same type will be overwritten.
    Specific metadata can be stripped using e.g. -x strip=exif

 -h, --help
    Prints this help message. Add -v (up to a total of 4 times) to see more options.

7. 参考資料

[1] Apple Developer Documentation, "Safari 17 Beta Release Notes", https://developer.apple.com/documentation/safari-release-notes/safari-17-release-notes

[2] libjxl/libjxl, "libjxl/doc/color_management.md", https://github.com/libjxl/libjxl/blob/main/doc/color_management.md

[3] libjxl/libjxl, "libjxl/tools/cjxl_main.cc", https://github.com/libjxl/libjxl/blob/ff8a9c1c/tools/cjxl_main.cc#L215-L232

[4] libjxl/libjxl, "libjxl/lib/jxl/color_encoding_internal.cc", https://github.com/libjxl/libjxl/blob/ff8a9c1c/lib/jxl/color_encoding_internal.cc

[5] libjxl/libjxl, "libjxl/lib/include/jxl/codestream_header.h" https://github.com/libjxl/libjxl/blob/ff8a9c1c/lib/include/jxl/codestream_header.h#L130-L155

[6] Can I use, "JPEG XL image format", https://caniuse.com/jpegxl

PlayStation 5 本体に HDRフォーマットで録画したプレイ動画を DaVinci Resolve で開くための手順

背景と目的

  • 1つ前の記事で筆者は PS5 本体に録画した HDRのプレイ動画の解析を行った

trev16.hatenablog.com

  • 解析は主に DaVinci Resolve を使って行ったのだが、いくつか事前準備が必要だった
  • その手順をメモとして残すことにした

結論

以下の手順で HDRフォーマットで録画したプレイ動画を DaVinci Resolve で開くことが可能となる。

PS5 側の設定

  • ① 事前に PS5 で利用可能な USBドライブを準備し、PS5背面の USBポートに挿しておく
  • ② 「設定」->「キャプチャーとブロードキャスト」->「ビデオクリップ形式」の画面を開く
  • ③ 「ファイル形式」を「効率を優先 (WebM)」に設定する (図1 参照)
    • 筆者が確認したところ MP4 形式で録画すると SDR でしか録画できなかった
    • なお録画解像度を 3840x2160 にすると自動で「効率を優先 (WebM)」になる
  • ④ PS5 でゲームを起動しコントローラーのクリエイトボタンを押して録画を行う
  • ⑤ PS5 のメディアギャラリーを開き、USBドライブにコピーする (動画1 参照)

図1. ビデオクリップ形式の画面


動画1. PS5 本体で録画したデータを USBドライブにコピーする様子

PC 側の設定

  • ① USBドライブの録画データを PC にコピーする
  • FFmpeg を使って mp4 コンテナに変換する
    • 変換しなくても DaVinci で開けるのだが、音声が消えてしまうため .webm -> .mp4 に変換する
    • 以下に示した FFmpeg パラメータのうち、大事なのは -color_range tv である。これがないとメタデータのミスマッチが発生した
ffmpeg -color_primaries bt2020 -color_trc smpte2084 -colorspace bt2020nc -color_range tv -i INPUT_FILE_NAME.webm -c:v copy -c:a copy -color_primaries bt2020 -color_trc smpte2084 -colorspace bt2020nc -color_range tv OUTPUT_FILE_NAME.mp4
  • ③ 変換した .mp4 ファイルを DaVinci で開く

注意事項

USBドライブから PC に .webm ファイルをコピーする際に、本当に HDR形式で録画できているか確認することをお勧めする。 筆者は MPC-BE という再生プレイヤーで .webm ファイルを開き、「File」-> 「Properties」を選択してメタデータを確認するようにしている。

図2 のように Color primaries と Transfer characteristics が BT.2020 と PQ となっていれば HDRフォーマットで録画できている。

図2. MPC-BE を使って .webm ファイルのメタデータを確認している様子

PS5 の「HDR調整」と「プレイ動画の録画機能」の関係を軽く調べた(FINAL FANTASY 16 を使用)

1. 背景

筆者は FINAL FANTASY 16 (以後 FF16 と略す) をプレイするために PlayStation 5 (以後 PS5 と略す) を購入した。 PS5 は HDR をサポートしたゲーム機であり、HDR に関して以下の特徴がある。

  • HDR調整という機能があり HDR対応ゲームの表示を表示デバイスに最適化できる
  • HDR のゲームプレイ動画を PS5本体に HDRフォーマットで録画できる
  • 録画した動画は YouTubeHDRフォーマットで投稿できる

筆者は個人的な興味から PS5 本体に録画したプレイ動画の解析を行っていたが、録画データを観察しているうちに HDR調整と録画データの関係が気になった。 具体的には 録画データに HDR調整の結果が反映されるのか、PS5 本体に録画したプレイ動画を YouTube にアップした際に、HDR調整の結果によって動画の見た目が変わるのか、といったことが気になった。

そうした背景があり簡単な調査を行うことにした。

2. 目的

  1. PS5の HDR調整結果が PS5本体のプレイ動画の録画データに反映されるか調べる
  2. 上記の結果を元に、録画した FF16の HDRプレイ動画を YouTube にアップロードする場合の注意点があれば記載する

3. 結論

3.1. 結論1

PS5の HDR調整結果は PS5本体のプレイ動画の録画データに反映される。

そのため、例えば複数人のプレイヤーが同じシーンを録画して YouTube にアップした場合には、 各プレイヤーの HDR調整結果によって動画の輝度レンジが異なる結果となる。

確認のために 4種類のパラメータで HDR調整を行い、同一のシーンを録画した結果を動画1 に示す。


動画1. 異なる複数のパラメータで HDR調整を行った場合の比較。動画の後半に輝度分布の分析あり。

3.2. 結論2

YouTube へ FF16 のHDRプレイ動画をアップする際、PS5 の HDR調整結果は殆ど気にする必要はないと考える。 なぜならば YouTube にアップロードした動画を各種 HDR対応デバイスで確認したところ、HDR調整の結果によらず HDR感のある動画として知覚できたからである。

一方で、データレベルでは高輝度のシーンの描画結果には差異があったため (図1参照)、気になるユーザーは録画をする時だけ HDR調整の Highlight側の Adjustment Index (※1) を 15 以上に設定することをオススメする。

※1 Adjustment Index については後述するが、一旦ここで Index とターゲット輝度の関係を図2 に示す。

図1. 異なる HDR調整結果での輝度の比較 図2. HDR調整の Adjustment Index と輝度(推測値)の関係

3.3. 使用機材、ソフトウェア

検証に使用した機材とソフトウェアは以下の通りである。

名称 バージョン
PlayStation 5 (CFI-1200B) 23.01-07.40.00.06-00.00.00.0.1
FINAL FANTASY 16 Version 1.02
Elgato 4K60 S+ (HDMI キャプチャ機材) 不明
Elgato 4K Capture Utility Version 1.7.6

4. 結論に至までの経緯

4.1. PS5 の HDR調整に関する調査

始めに PS5 の HDR調整に関する調査を行った。結果を以下に示す。

4.1.1. HDR調整の概要

HDR調整は PS5 の 「ホーム」->「設定」->「スクリーンとビデオ」にある設定項目である。

取扱説明書には テレビに合わせて明るさを構成することで、HDRを最適化してより美しい映像を体験できます との記載がある。 この「HDRを最適化して」という文言が具体的にどのような処理を意味するのかは不明だが(※2)、上記の文言から PS5 内部で HDR調整の結果に基づきゲーム映像に何らかの処理が適用されることが推測できる。

さて HDR調整の具体的な内容だが、調整は 図3~図5 に示す 3種類のパターンを使って行う。 プレイヤーは各パターンの明るさを変更して使用している表示デバイスに最適なポイントを探す。

図3. HDR調整 (1/3) 図4. HDR調整 (2/3) 図5. HDR調整 (3/3)

パターンの明るさ変更は 32段階 or 16段階で行うことができる。図3 と 図4 の調整は 32段階、図5 は 16段階の調整となっている。

4.1.2. HDR調整の用語整理

さて、突然だが本記事では 図3、図4 の調整を Highlight側の調整、図5 の調整を Shadow側の調整と呼ぶことにする。 理由は名前を付けないと記事が書きづらいからである。なお、これは筆者独自の呼び方であり一般的な呼び方ではないことに注意して頂きたい(※3)。

同様に 32段階 or 16段階の調整点を Adjustment Index と呼ぶことにする。

※2 そこそこ調べたのだが処理内容に言及している公式の文書は見つからなかった
※3 そもそも一般的な呼び方が分からなかったので筆者は独自の呼び方をすることにした、という背景がある

4.1.3. Adjustment Index と対応する輝度の関係の調査

さて、ここまで調べると Adjustment Index を変化させた際のパターンの輝度が気になってくる。 そこで筆者は自宅にある Elgato 4K60 S+ (以後はキャプチャ機材と呼ぶ) を使って調査した。

Adjustment Index を変化させた際の信号の生値をプロットした結果を図6に、それを輝度値に変換した結果を図7 に示す。

図6. 信号生値のプロット結果 図7. 輝度値に変換後のプロット結果

図6、図7 を細かく観察すると、グラフは歪んでおり また最大値も 10000 nits に達しておらず不自然なことが分かる。 筆者はこの原因はキャプチャ機材に問題があると考えた。そこで少々乱暴ではあるが上記のグラフを推測に基づき修正することにした。

修正後の値を以下のテーブルにて赤字で示す。また、グラフをプロットしなおした結果を図8、図9 に示す。

項目 生値(測定値) 生値(修正後の推測値) 輝度値(測定値) 輝度値(修正後の推測値)
Highlight 517 ~ 1006 520 ~ 1023 97 ~ 8536 100 ~ 10000
Shadow 0 ~ 144 0 ~ 152 0 ~ 0.832 0 ~ 1.00
図8. 信号生値のプロット結果 (修正後の推測値) 図9. 輝度値に変換後のプロット結果(修正後の推測値)

なお、図6~図9 は HDR調整時の Adjustment Index と輝度値の対応関係を示しただけである。 ゲームの出力輝度が Adjustment Index の輝度値に制限されるとは限らないので誤解のないようにして頂きたい (※4※5)。

※4 PS5 の説明書に書かれているのは「HDRを最適化してより美しい映像を体験できます」という点のみであり、出力輝度の範囲に関する明確な記述は無い
※5 筆者が確認したところ FF16 のゲーム画面は Adjustment Index で設定した輝度値よりも高い輝度値も出力されていた

4.2. HDR調整と PS5 の録画データの関係

さて、これまでの調査で HDR調整の概要は理解できた。続いて FF16 のゲーム画面がどのように変化するかを確認した。 まず筆者は PS5 本体にプレイ動画を録画した際に HDR調整の結果が適用されるか確認することにした。

なぜ、このような確認をしたかというと、筆者は HDR調整が適用されるのは HDMI出力のみで、内部録画データには適用されないと推測していたからである。 しかし確認したところ、HDR調整の結果は HDMI出力と内部録画データの両方に適用されていた。確認時のゲーム画面の輝度分布の比較を図10 に示す。

図10. HDMI出力結果と PS5 内部録画データの輝度比較

図10 の各ブロックの説明は以下の通り。右上と右下の輝度レンジが一致していることから、HDR調整の結果は内部録画データにも適用されることが分かる。

場所 Highlight側の Adjustment Index 対応する輝度 確認対象
左上 31 約10000 nits HDMI出力
右上 0 約100 nits HDMI出力
右下 0 約100 nits PS5 内部録画データ

4.3. PS5 の録画データの YouTube 投稿結果の目視確認

4.3.1. YouTube 投稿結果の目視確認を行う理由

ここまでの調査で PS5 の録画データに HDR調整の結果が適用されることが分かった。 最後に HDR調整が適用されたデータをそのまま YouTube にアップロードして問題がないか簡単な確認を行った。

なぜこのような確認を行ったかというと、ユーザーの使用している表示デバイスの輝度レンジの差によって以下の問題が生じることを恐れていたからである。

  • ユーザーA は ピーク輝度 400 nits の Display HDR 400 対応モニターを所有していた
    • ユーザーA は PS5 の HDR調整で Highlight側の Adjustment Index を 9 (約 400 nits) に設定した
    • ユーザーA は FF16 の HDRプレイ動画を PS5 内部に録画した
    • ユーザーA は 録画データを YouTube にアップロードして一般公開した
  • ユーザーB は ピーク輝度 1600 nitsiPad Pro を所有していた
    • ユーザーB は ユーザーA が投稿した FF16 のプレイ動画を視聴した
    • ユーザーB は「なんか高輝度が出ていなくてHDR感が少ないな~」という印象を持ってしまった
4.3.2. 確認手順

確認は以下の手順で行った。

  • ① 以下の表に示す通り Highlight側の Adjustment Index を 4種類用意した
Adjustment Index 対応する輝度 用意した理由
0 約100 nits 参考比較用に理論的な最低値を指定(目視評価のターゲットではない)
9 約400 nits 実用的な最低値を指定。Display HDR の最低グレードに合わせた
15 約1000 nits 映像制作市場における基準輝度が 1000 nits であるため指定
25 約4000 nits 個人的にありそうだと考える最大値を指定。Dolby Vision の基準輝度


  • ② それぞれのHDR調整が適用された FF16 の HDRプレイ動画を PS5にて録画した
  • ③ 比較しやすいよう DaVinci Resolve を使って 4つの録画データを結合し YouTube にアップロードした
  • ④ 輝度レンジの異なる 5種類のデバイスYouTube にアップロードした動画を視聴して問題ないか確認した

目視確認に使用したデバイスおよびスペックを以下の表に示す。

機材名 ピーク輝度 確認環境
Pixel 4 XL 約450 nits YouTube App Version 18.25.39
G3223Q 約600 nits Microsoft Edge Version 114.0.1823.67
BRAVIA 65X9500G 約1200 nits YouTube App Version 3.05.003
iPhone 13 Pro 約1200 nits YouTube App Version 18.25.1
iPad Pro 12.9-inch (第5世代) 約1600 nits YouTube App Version 18.25.1

なお、確認に使用した動画は結論欄に貼り付けた動画である。念のため以下に再掲する。


動画1 (再掲). 異なる複数のパラメータで HDR調整を行った場合の比較。動画の後半に輝度分布の分析あり。
4.3.3. 確認結果

さて、各デバイスで視聴した結果であるが、筆者が観察した限りでは Adjustment Index 9 (約400 nits) でも十分に明るさを知覚でき、特に暗いという印象は受けなかった。 もちろん、ごく一部に存在する高輝度領域では白飛びによりディテールが失われることもあったが、動画を一時停止してコマ送りしないと気づかないレベルであった。 そのため、筆者は冒頭の結論で述べた通り YouTube への動画のアップロード時に HDR調整の結果は気にする必要ないと考えている。

なお、この結果は FF16 の HDRプレイ動画の結果であり、他のゲームソフトでも同じ傾向にあるかは不明である。その点は注意して頂きたい。

5. 感想

HDR調整の内容が気になって FF16 のプレイを中断してブログを書いていたが、これでやっと FF16 のプレイを再開できるぜ。

DaVinci Color Transform Language (DCTL) を使った printf デバッグを試した

1. 背景

前回、筆者は以下の記事で DaVinci Color Transform Language (DCTL) を試し、得られた知見を記事にまとめた。

trev16.hatenablog.com

その中で筆者は「コンソール出力が無いので printf デバッグすらできない」という旨を書いた。

すると、記事を読んでくださった有識者の方から、少々トリッキーではあるが、printfデバッグの方法を教わることができた。 また非常にありがたいことに、その方からは DCTL のサンプルコードも頂いた(本当にありがとうございます🙏)。

ただ、サンプルコードの内容は難解であり、筆者は処理内容を理解することができなかった。 そこで、自己の理解を深めるためにスクラッチから printf デバッグ用の DCTL ファイルを作成することに決めた。

2. 目的

printf デバッグ用の DCTL ファイルを作成する。

3. 結論

指定した座標の RGB値を画面表示する DCTL ファイルの作成に成功した (本記事ではこの画面表示が printf デバッグを意味する)。 その様子を 図1 および 動画 1 に示す。

図1. printf デバッグ (という名の数値表示) をしている様子

動画1. printf デバッグ (という名の数値表示) をしている様子

4. やり方

やり方はシンプルである。 図1 を見れば分かるようにデバッグ情報(数値)を画面に描画することで実現している。

どのようにして図1 の描画に至ったのか、順を追って説明する。

4.1. DCTL を使った図形の描画

DCTL では画面出力の RGB データに直接アクセスできるため、任意の図形をプロットすることが可能である。 例えば以下のコードを書くと、画面左上に黄色の矩形を描画できる。

__DEVICE__ float3 transform(int p_Width, int p_Height, int p_X, int p_Y, float p_R, float p_G, float p_B)
{
    float3 out = make_float3(p_R, p_G, p_B);
    float3 rectangle_color = make_float3(1.0, 1.0, 0.0);
    float2 st_pos = make_float2(200, 100);
    float2 ed_pos = make_float2(1200, 300);
    
    if((st_pos.x <= p_X) && (p_X < ed_pos.x)){
        if((st_pos.y <= p_Y) && (p_Y < ed_pos.y)){
            out.x = rectangle_color.x;
            out.y = rectangle_color.y;
            out.z = rectangle_color.z;
        }
    }

    return out;
}

図2. 画面左上に矩形 (黄色) を描画した様子

4.2. 矩形を組み合わせた数値の描画

矩形が書けてしまえば、矩形の組み合わせで任意の数字の描画が可能である。 筆者は下図のように A~H の 8個の矩形を用いて数値と小数点を描画することにした。

図3. 8個の矩形の組み合わせで数値と小数点を表現する様子

4.3. 表示用の数値の取得および描画

DCTL では _tex2D 関数を使う事で任意の座標の RGB 値を float型で取得できる。

取得値は float 型であるため、本来であれば 1.2345E-5 のような指数表記で描画するのが好ましかったのだが、 実装が面倒だったので、今回は固定小数点ライクな表示仕様とした。

その結果、正の数は6桁、負の数は5桁での表示となった。表示の様子を図4 に示す

図4. 色々な数値を描画がしている様子

表現可能な数値の範囲は以下の通りである (0を除く)。

  • 正の数: 0.00001 ~ 999999
  • 負の数: -0.0001 ~ -99999

5. ソースコード

一応、以下に置いときます。例によってコメントを全然書いて無いですが…。

printf デバッグに必要なのは 私のリポジトリ にある以下の2ファイルです。

6. 感想

この DCTLコードの実装は想像よりずっと楽しかった。満足したので元の作業に戻る。

DaVinci Color Transform Language (DCTL) を試してみた

0. 更新履歴

日付 Revision 内容
2023/05/20 rev.1 新規作成
2023/05/24 rev.2 DCTL の Syntax Error の確認方法を追記
2023/06/02 rev.3 DCTL の printf デバッグ方法を追記

1. 背景

諸事情により DaVinci CTL (DCTL) を使って動画コンテンツの解析をしたくなった。 しかし、筆者は DCTL を全く触ったことが無かったため、まずは簡単な DCTL のコードを書いてみることにした。

2. 目的

  • DCTL をとりあえず試してみる
  • 実装で苦労した点をまとめておく

3. 結論

簡単な DCTL のコードを書き DaVinci 用のエフェクトを作成することに成功した。成果物の紹介と苦労した点を以下に示す。

3.1. 成果物の紹介

2020年に作成した HDRコンテンツ解析用 Luminance Map の生成コードを DCTL で書き、 DaVinci Resolve のエフェクトとして利用可能にした。

ソースコードは以下で公開している。動作の様子を動画1 に示す。

github.com

動画1. 作成したエフェクトが動作する様子

3.2. 実装で苦労した点

  • ①エラーログが無く Syntax Error が出ないのでコードの文法誤りの検出が困難
    • 筆者は VS Code上でソースコード 1行ずつコメントアウト して問題のあるコードを検出していた
    • 2023/05/24 追記
      • ブログ公開後、複数の方にエラーログの確認方法を教えて頂いた🙏
      • 以下のフォルダにある davinci_resolve.log を見ると Syntax Error の内容が確認できる
        • Windows: C:\Users\<user_name>\AppData\Roaming\Blackmagic Design\DaVinci Resolve\Support\logs
        • macOS: /Users/<user_name>/Library/Application Support/Blackmagic Design/DaVinci Resolve/logs
      • エラーログの例は以下
C:\ProgramData\Blackmagic Design\DaVinci Resolve\Support\LUT\TY_DCTL\show_internal_value.dctl(3106): warning: parameter "rgb" was set but never used
C:\ProgramData\Blackmagic Design\DaVinci Resolve\Support\LUT\TY_DCTL\show_internal_value.dctl(3148): error: identifier "rgb" is undefined
2 errors detected in the compilation of "C:\ProgramData\Blackmagic Design\DaVinci Resolve\Support\LUT\TY_DCTL\show_internal_value.dctl".


  • ②動作確認時のデバッグが困難
    • コンソール出力が無いので printf デバッグすらできない
    • 仕方ないので閾値で出力を2値化するデバッグ用の DCTL を用意して内部値の推測を行った (図1~図3)
図1. DCTL Off 時の様子 図2. 閾値を 1.0 に設定した場合の様子 図3. 閾値を 10.0 に設定した場合の様子

2023/06/02 追記

ややトリッキーではありますが、DCTL で printf デバッグすることに成功しました。詳細は以下の記事を参照下さい。 trev16.hatenablog.com

4. DCTL について筆者が理解した点

以下で筆者が理解した点を参考情報として残しておく。 なお、今回作成した DCTL のプラグインは EDIT ページで実行する想定で作成した。 Colorページでの運用は今のところ考えていない(Colorページでも使えるとは思うが)。

4.1. DCTL のマニュアルは README.txt のみ

DaVinci Resolve の公式マニュアルには詳細の記述がない。

詳細マニュアルは DaVinci 起動時にメニューバーから Help --> Documentation --> Developer を選択した際に 開くウィンドウの先にある DaVinciCTL/README.txt のみである。

4.2. 生成した DCTLファイルは LUT と同じフォルダに配置する

作成した DCTL のコードは .dctl の拡張子で保存して、以下のフォルダに配置する。

  • Mac OS X: Library/Application Support/Blackmagic Design/DaVinci Resolve/LUT
  • Windows: C:\ProgramData\Blackmagic Design\DaVinci Resolve\Support\LUT
  • Linux: /home/resolve/LUT

意外なことに DCTL 用のフォルダではなく、LUT用のフォルダに配置 する仕様であった。 DaVinci 的には DCTL も LUT も内部的には似たような取り扱いなのかもしれない。

4.3. DCTL の処理は Timeline color space で行われる

非常に恥ずかしい話なのだが、筆者はこれまで DaVinci の EDITページで色処理を行う経験が殆どなく、 Timeline color space が何のために存在しているのか分かっていなかった(勝手に内部処理は Linear空間で行われると考えていた)。

今回 DCTL のコードを書くことで初めて Timeline color space の意味が理解できた。 筆者の理解は次の通りである。Timeline color space は Color Grading における ACEScct のように、信号処理の内容に応じて適切な色空間を選択するために存在している。

さて、そうなると Timeline color space の値域を正しく理解しておく必要がある。 なぜならば値域を理解しないことには DCTL のコードを書けないからである(HDR の場合は 1.0 を超える値を取り扱うので)。

筆者が調査したところ、0.0 ~ 1.0 に正規化された入力データを使用した場合の Timeline color space の値域は以下の表1となることが分かった。

表1. 入力の Gamma 設定と Timeline color space の Gamma 設定の組み合わせにおける値域の例
入力の Gamma Timeline の Gamma
Linear
Timeline の Gamma
PQ
Timeline の Gamma
2.4
2.4 0.0 ~ 1.0 0.0 ~ 0.508 0.0 ~ 1.0
PQ 0.0 ~ 100.0 0.0 ~ 1.0 0.0 ~ 6.81

設定によって値域が大きく異なるため、Timeline color space で処理を行う DCTL コードを書く際は、この点に注意する必要がある。

4.4. DCTL では CTL のコードをそのまま流用できない

筆者は当初、CTL のコードも include して使い回せると考えていたのだが、そんなことは無かった。

以下は SMPTE ST 2084 の EOTF を CTL から DCTL に書き換えた際の diff である。 見て分かるように様々な変更が入るため CTL をそのまま流用するのは不可能であった。

--- st2084.ctl  2023-05-14 11:48:03.867909400 +0900
+++ st2084.dctl 2023-05-14 11:50:22.216460100 +0900
@@ -6,23 +6,23 @@
 
 const float pq_C = 10000.0;
 
-float ST2084_2_Y( float N )
+__DEVICE__ float ST2084_2_Y( float N )
 {
-  float Np = pow( N, 1.0 / pq_m2 );
+  float Np = _powf( N, 1.0 / pq_m2 );
   float L = Np - pq_c1;
   if ( L < 0.0 )
     L = 0.0;
   L = L / ( pq_c2 - pq_c3 * Np );
-  L = pow( L, 1.0 / pq_m1 );
+  L = _powf( L, 1.0 / pq_m1 );
   return L * pq_C; // returns cd/m^2
 }
 
-float[3] ST2084_2_Y_f3( float in[3])
+__DEVICE__ float3 ST2084_2_Y_f3( float3 in )
 {
-  float out[3];
-  out[0] = ST2084_2_Y( in[0]);
-  out[1] = ST2084_2_Y( in[1]);
-  out[2] = ST2084_2_Y( in[2]);
+  float3 out;
+  out.x = ST2084_2_Y( in.x );
+  out.y = ST2084_2_Y( in.y );
+  out.z = ST2084_2_Y( in.z );
 
   return out;
 }

主な変更箇所は以下の通りである。

  • 関数定義の冒頭に __DEVICE__ の接頭語がつく
  • pow_powf に変更
  • float in[3]float3 に変わる
    • それにともないメンバのアクセスに .x, .y, .z の記述が必要

5. 感想

思っていたより難易度が高かったが DCTL の基本的な書き方を理解できた。ここまで来れば応用は割と簡単なので、 今後は本来やりたかった処理を数週間かけて実装していきたい。

ocioconvert コマンドを使って画像ファイルの色変換を行う

1. 背景

  • ここ数ヶ月ほど OpenColorIO v2 (以後 OCIO v2 と略す) の configファイルを触っていた
  • これまで画像に対して OCIO v2 を使った色変換を行うには、毎回 Nuke や Affinity Photo などを起動していた
  • 流石に面倒になってきたのでコマンドラインでサクッと変換したくなった
  • ocioconvert というコマンドの存在を思い出したので試してみることにした

2. 目的

  • ocioconvert を使って画像ファイルの色変換を行う
  • その際に config.ocio のview_transformsも適用できるようにする

3. 結論

ocioconvert コマンドを使い、以下の通りにコマンドを入力すれば変換できることが分かった。

ocioconvert --view inputimage inputcolorspace outputimage displayname viewname

例として、以下の条件で ocioconvert を実行した様子を示す。

条件 項目
config ファイル OpenColorIO-Config-ACES で配布されている reference-config-v1.0.0_aces-v1.3_ocio-v2.1.ocio [1]
入力画像の colorspace ACES2065-1
出力画像の display colorspace Rec.1886 Rec.709
view_transform "ACES 1.0 - SDR Video
ocioconvert を実行した様子
export OCIO=/ocio_config_dir/reference-config-v1.0.0_aces-v1.3_ocio-v2.1.ocio  # ocio_config_dir は .ocio を保存したディレクトリ
ocioconvert --view ./src_aces2065-1.exr "ACES2065-1" ./dst_rec.1886-rec.709_aces-1.0-sdr.exr "Rec.1886 Rec.709 - Display" "ACES 1.0 - SDR Video"

4. 詳細

4.1. ocioconvert とは

ocioconvertは OCIO v2 に含まれるツールの1つである。OCIO v2 をソースコードからビルドすると自動で入る。 ocioconvert以外にもociocheckociochecklutなどのツールが存在する。詳細に関しては公式ドキュメントを参照して頂きたい [2]。

4.2. インストール

公式ドキュメントを読んで頑張ってソースコードからビルドする[3]。自分は Ubuntu 22.04 上でビルドした(業界的には RHEL だと思うが)。

4.3. ocioconvert のヘルプを読む

OCIO v2 の公式ドキュメントにはocioconvertコマンドに渡す具体的なパラメータについての記載が無かった。 そのためocioconvertコマンドのヘルプが唯一の手がかりである。

ocioconvert -h を実行した結果を以下に示す。

usage: ocioconvert [options] inputimage inputcolorspace outputimage outputcolorspace
   or: ocioconvert [options] --lut lutfile inputimage outputimage
   or: ocioconvert [options] --view inputimage inputcolorspace outputimage displayname viewname
   or: ocioconvert [options] --invertview inputimage displayname viewname outputimage outputcolorspace


Options:
    --lut                  Convert using a LUT rather than a config file
    --view                 Convert to a (display,view) pair rather than to an output color space
    --invertview           Convert from a (display,view) pair rather than from a color space
    --gpu                  Use GPU color processing instead of CPU (CPU is the default)
    --gpulegacy            Use the legacy (i.e. baked) GPU color processing instead of the CPU one (--gpu is ignored)
    --gpuinfo              Output the OCIO shader program
    --h                    Display the help and exit
    --help                 Display the help and exit
    -v                     Display general information

OpenImageIO or OpenEXR options:
    --float-attribute %L   "name=float" pair defining OIIO float attribute for outputimage
    --int-attribute %L     "name=int" pair defining an int attribute for outputimage
    --string-attribute %L  "name=string" pair defining a string attribute for outputimage

これを読むと、筆者の目的を果たすには --view オプションを使用すれば良さそうである。 また、その際はパラメータとして inputimageoutputimageinputcolorspacedisplaynameviewnameを指定すれば良いことが分かる。

4.4. inputimageoutputimageについて

基本的には OpenEXR のファイル形式を指定しておけば問題ない。 OpenImageIO がインストールされていれば、OpenImageIO がサポートしているファイル形式を扱えるようだが[2] 本記事では確認は割愛する。

4.5. inputcolorspacedisplaynameviewnameについて

inputcolorspacedisplaynameviewnameはそれぞれ config.ocio にて定義されている名称を使う。 例として reference-config-v1.0.0_aces-v1.3_ocio-v2.1.ocio にて記載されている場所のスクリーンショットを以下に示す。

inputcolorspace displayname viewname

4.6. config.ocio の指定について

ocioconvert コマンドでは config.ocio のパスを指定するオプションが存在しない。 そのため config.ocio のパスは環境変数OCIOを用意して事前に指定しておく必要がある[4]。

Linuxbash を動かしている環境であれば、以下のようにexportを使って指定すれば良い。

export OCIO=/ocio_config_dir/config.ocio  # ocio_config_dir は .ocio が存在するディレクトリ

4.7. 実行例

冒頭の結論とは条件を少し変え色変換を行った例を以下に示す。

条件 項目
config ファイル OpenColorIO-Config-ACES で配布されている reference-config-v1.0.0_aces-v1.3_ocio-v2.1.ocio [1]
入力画像の colorspace ACES2065-1
出力画像の display colorspace Rec.2100-PQ - Display
view_transform "Un-tone-mapped
ocioconvert を実行した様子
export OCIO=/ocio_config_dir/reference-config-v1.0.0_aces-v1.3_ocio-v2.1.ocio  # ocio_config_dir は .ocio を保存したディレクトリ
ocioconvert --view ./src_aces2065-1.exr "ACES2065-1" ./dst_rec.2100-pq_un-tone-mapped.exr "Rec.2100-PQ - Display" "Un-tone-mapped"

入力画像と出力画像は以下のようになり、想定通りの変換が行えていることを確認できた。

入力画像 出力画像

5. 感想

ということで ocioconvert の基本的な使い方が分かった。 本当は OpenImageIO を使った OpenEXR 以外のファイルフォーマットも試したかったが、それは別の機会に試そうと思う。

今まで ACES の Output Transform をコマンドラインで適用するには ctlrender を使ってきたが、今後は ocioconvert を積極的に使っていきたいと思う。

参考資料

[1] AcademySoftwareFoundation, "OpenColorIO-Config-ACES 1.0.0", https://github.com/AcademySoftwareFoundation/OpenColorIO-Config-ACES/releases/tag/v1.0.0

[2] OpenColorIO, "Tool overview", https://opencolorio.readthedocs.io/en/latest/guides/using_ocio/tool_overview.html#tool-overview

[3] AcademySoftwareFoundation, "OpenColorIO/installation.rst", https://github.com/AcademySoftwareFoundation/OpenColorIO/blob/main/docs/quick_start/installation.rst

[4] OpenColorIO, "Using OCIO", https://opencolorio.readthedocs.io/en/latest/guides/using_ocio/using_ocio.html