本文へスキップ
からだにいいもの

Rのトピックスを中心に『まだ、まだ、知らない、役に立つ情報?』を発信します。

Rで解析:カメラのボケや色調・トーンマッピングを再現できる「rayimage」パッケージ

実写に近い質感やカメラ特有の視覚効果を再現したい場面があります。しかし、被写界深度によるボケや色調補正、トーンマッピングといったカメラ由来の効果を一から実装するのは手間がかかります。

「rayimage」パッケージは、畳み込み演算を用いてこうしたカメラエフェクトを画像に付与できます。被写界深度によるボケのレンダリングのほか、ホワイトバランスや色空間の変換、画像の重ね合わせ、トーンマッピングといった処理が収録されています。また、複数の画像を格子状に並べて比較することも可能です。

本パッケージの利用で、より実在感のあるビジュアル制作ができるのではないかと考えます。

パッケージバージョンは0.26.1。Windows 11 x64 (build 26200)のR version 4.6.1で確認しています。

パッケージのインストール

下記コマンドを実行してください。

# パッケージのインストール
install.packages("rayimage")

# パッケージの読み込み
library("rayimage")
スポンサーリンク

コマンド例

詳細はコメント、パッケージのヘルプを確認してください。

RGBは、赤・緑・青の3原色を組み合わせて色を表現する色空間のモデルです。HDRは、高輝度(High Dynamic Range)の略称で、より広い範囲の明るさを表現できる画像形式を指します。

rayimageでは、画像を高さ×幅×チャンネル数の3次元配列として扱います。以下の例では、実際の写真の代わりに、支笏湖の風景に見立てた疑似画像をコード上で生成して使います。

# 疑似画像の縦横のサイズを指定する
img_h <- 120
img_w <- 160

# 上が空、下が湖面になるように、青チャンネルを縦方向のグラデーションにする
blue_ch <- matrix(seq(0.85, 0.35, length.out = img_h), nrow = img_h, ncol = img_w)

# 緑チャンネルも同様にグラデーションにする
green_ch <- matrix(seq(0.55, 0.30, length.out = img_h), nrow = img_h, ncol = img_w)

# 赤チャンネルも同様にグラデーションにする
red_ch <- matrix(seq(0.30, 0.55, length.out = img_h), nrow = img_h, ncol = img_w)

# 3チャンネルを結合し、支笏湖の風景に見立てたRGB配列を作る
shikotsuko <- array(c(red_ch, green_ch, blue_ch), dim = c(img_h, img_w, 3))

# 下(湖畔)ほど値が小さくなる深度マップを作る
shikotsuko_depth <- matrix(seq(1, 0, length.out = img_h), nrow = img_h, ncol = img_w)

ボケ効果のレンダリング:render_bokehコマンド

深度マップをもとに、ピントの合っていない領域へボケ効果を適用します。

オプション意味初期値
imageRGB/RGBA配列、rayimgクラス、または画像ファイル名なし
depthmap深度マップのファイル名、または1次元配列なし
focusぼかしの基準となる深度0.5
focallength仮想カメラの焦点距離100
fstop仮想カメラのF値4
filename保存する画像のファイル名。指定しない場合はプロットするNULL
previewFALSEの場合は画像を表示せず、RGB配列を返すTRUE
preview_focusTRUEの場合、ピントが合う位置を赤い線で示すFALSE
bokehshapeボケの形状。”circle”のほか”hex”が組み込みで用意されている。2次元行列を渡すとその形状になる“circle”
bokehintensity画素値がbokehlimitを超えたときのボケの強度1
bokehlimitbokehintensityによる強調が始まる画素値のしきい値0.8
rotation六角形のボケ形状を回転させる角度0
aberration画像に加える色収差の度合い。最大10
progressプログレスバーを表示するかどうかinteractive()
preview = TRUEのときにplot_image()へ渡す追加の引数なし
# 湖畔(深度の小さい部分)にピントを合わせてぼかす
render_bokeh(shikotsuko, shikotsuko_depth, focus = 0.15, preview = TRUE)

# ピントが合う位置を赤い線で確認する
render_bokeh(shikotsuko, shikotsuko_depth, focus = 0.15, preview_focus = TRUE)
Focal range: 0-0.991597

# 焦点距離を伸ばし、ボケを強くする
render_bokeh(shikotsuko, shikotsuko_depth, focus = 0.15, focallength = 300, preview = TRUE)

# 遠景の山並み(深度の大きい部分)にピントを合わせる
render_bokeh(shikotsuko, shikotsuko_depth, focus = 0.85, focallength = 300, preview = TRUE)

# ボケの形状を六角形にする
render_bokeh(shikotsuko, shikotsuko_depth,
  focus = 0.15, focallength = 300,
  bokehshape = "hex", preview = TRUE
)

# 六角形のボケを回転させ、強度を上げる
render_bokeh(shikotsuko, shikotsuko_depth,
  focus = 0.15, focallength = 300,
  bokehshape = "hex", rotation = 20, bokehintensity = 3, preview = TRUE
)

# 色収差を加える
render_bokeh(shikotsuko, shikotsuko_depth,
  focus = 0.15, focallength = 300,
  aberration = 0.5, preview = TRUE
)

湖畔(深度の小さい部分)にピントを合わせてぼかす

ピントが合う位置を赤い線で確認する

焦点距離を伸ばし、ボケを強くする

遠景の山並み(深度の大きい部分)にピントを合わせる

ボケの形状を六角形にする

六角形のボケを回転させ、強度を上げる

色収差を加える

ホワイトバランスの補正:render_white_balanceコマンド

画像のホワイトバランスを、指定したホワイトポイントに合わせて補正します。

オプション意味初期値
imageRGB/RGBA配列、rayimgクラス、または画像ファイル名なし
reference_white変換元のホワイトポイント。NAの場合は画像の属性から取得するNA
target_white変換先のホワイトポイント“D60”
bakeTRUEの場合、色調の変更を画像に焼き込むFALSE
filename保存先のパスNULL
previewTRUEの場合、画像を表示するFALSE
# 既定のホワイトバランスのまま表示する
render_white_balance(shikotsuko, preview = TRUE)

# ホワイトポイントを「D50」寄りに変え、温かみのある色調にする
render_white_balance(shikotsuko, preview = TRUE, target_white = "D50", bake = TRUE)

# ホワイトポイントを「D75」寄りに変え、寒色系の色調にする
render_white_balance(shikotsuko, preview = TRUE, target_white = "D75", bake = TRUE)

# 変換元のホワイトポイントを「D75」とみなし、「D50」へ変換して色調差を強調する
render_white_balance(shikotsuko,
  preview = TRUE,
  reference_white = "D75", target_white = "D50", bake = TRUE
)

既定のホワイトバランスのまま表示する

ホワイトポイントを「D50」寄りに変え、温かみのある色調にする

ホワイトポイントを「D75」寄りに変え、寒色系の色調にする

変換元のホワイトポイントを「D75」とみなし、「D50」へ変換して色調差を強調する

色空間の変換:render_convert_colorspaceコマンド

画像の色空間を、指定した色空間へ変換します。

オプション意味初期値
imageRGB/RGBA配列、rayimgクラス、または画像ファイル名なし
from_mats変換元の色空間。NAの場合は画像の属性から取得するNA
to_mats変換先の色空間CS_ACESCG
adapt_whiteTRUEの場合、ホワイトポイントの順応変換を適用するTRUE
from_white変換元のホワイトポイント。NAの場合は画像の属性から取得するNA
to_white変換先のホワイトポイント。NAの場合はto_matsの白色点を使うNA
filename保存先のパスNULL
previewTRUEの場合、画像を表示するFALSE
# 支笏湖の配列をsRGBの画像として読み込み、色空間の情報を持たせる
shikotsuko_srgb <- ray_read_image(shikotsuko,
  assume_colorspace = CS_SRGB,
  assume_white = CS_SRGB$white_xyz
)

# 色空間をACEScgに変換して表示する
shikotsuko_aces <- render_convert_colorspace(shikotsuko_srgb, to_mats = CS_ACESCG, preview = TRUE)

# 変換元の白色点をD50とみなして変換する
shikotsuko_aces_d50 <- render_convert_colorspace(shikotsuko_srgb,
  to_mats = CS_ACESCG,
  from_white = "D50", preview = TRUE
)

# ホワイトポイントの順応を行わずに変換する
shikotsuko_aces_noadapt <- render_convert_colorspace(shikotsuko_srgb,
  to_mats = CS_ACESCG,
  adapt_white = FALSE, preview = TRUE
)

色空間をACEScgに変換して表示する

変換元の白色点をD50とみなして変換する

ホワイトポイントの順応を行わずに変換する

画像の描画:plot_imageコマンド

RGBまたはRGBA配列を画像としてプロットします。

オプション意味初期値
imageRGB/RGBA配列、rayimgクラス、または画像ファイル名なし
draw_gridTRUEの場合、背景に格子を描くFALSE
ignore_alphaプロット時にアルファチャンネルを無視するかどうかFALSE
aspプロットする画素の縦横比1
new_pageプロット前に新しいページを呼び出すかどうかTRUE
return_grobgrobオブジェクトを返すかどうかFALSE
gpgrid::gpar()オブジェクトgrid::gpar()
angleプロット前に適用する反時計回りの回転角度0
show_linearTRUEの場合、表示前のガンマ補正を行わないFALSE
# 支笏湖の疑似画像をそのまま表示する
plot_image(shikotsuko)

# 縦横比を変えて、横に間延びした画像として表示する
plot_image(shikotsuko, asp = 2)

# 画像の上半分だけを切り出して表示する
plot_image(shikotsuko[1:60, , ])

# 90度回転させて表示する
plot_image(shikotsuko, angle = 90)

# 背景との境界を確認するため、格子線を重ねて表示する
plot_image(shikotsuko, draw_grid = TRUE)

支笏湖の疑似画像をそのまま表示する

縦横比を変えて、横に間延びした画像として表示する

画像の上半分だけを切り出して表示する

90度回転させて表示する

背景との境界を確認するため、格子線を重ねて表示する

画像一覧の格子状描画:plot_image_gridコマンド

複数の画像を格子状に並べてプロットします。

オプション意味初期値
input_listRGB/RGBA配列、rayimgクラス、または画像ファイル名のリストなし
dim出力する格子の幅×高さc(1, 1)
asp画素の縦横比。ベクトルにすると画像ごとに指定できる1
draw_gridTRUEの場合、背景に格子を描くFALSE
gpgrid::gpar()オブジェクトgrid::gpar()
# 支笏湖の画像と、そのネガ画像を横に並べて表示する
plot_image_grid(list(shikotsuko, 1 - shikotsuko), dim = c(1, 2))

# 同じ2枚を縦に並べて表示する
plot_image_grid(list(shikotsuko, 1 - shikotsuko), dim = c(2, 1))

# 深度マップをグレースケール画像として可視化する
depth_gray <- array(rep(shikotsuko_depth, 3), dim = c(img_h, img_w, 3))

# 画像と深度マップを2x2の格子で並べて表示する
plot_image_grid(list(shikotsuko, depth_gray, depth_gray, shikotsuko), dim = c(2, 2))

# 格子の各画像に異なる縦横比を指定する
plot_image_grid(list(shikotsuko, 1 - shikotsuko), dim = c(1, 2), asp = c(2, 1 / 2))

支笏湖の画像と、そのネガ画像を横に並べて表示する

同じ2枚を縦に並べて表示する

画像と深度マップを2×2の格子で並べて表示する

格子の各画像に異なる縦横比を指定する

画像の重ね合わせ:render_image_overlayコマンド

ベースの画像に、別の画像を重ねて合成します。

オプション意味初期値
imageRGB/RGBA配列、rayimgクラス、または画像ファイル名なし
image_overlay重ねる画像NULL
rescale_originalTRUEの場合、元の画像をオーバーレイの寸法にリサイズするFALSE
convert_overlay_colorspaceオーバーレイの色空間を元画像に合わせるかどうかTRUE
alphaNAの場合はオーバーレイのアルファチャンネルを使う。数値を指定すると透明度を掛け合わせるNA
filename保存先のパスNULL
previewTRUEの場合、画像を表示するFALSE
# 太陽をイメージした円形のマスクを作る(最大値を1にそろえる)
sun_disk <- generate_2d_disk(dim = c(img_h, img_w), radius = 0.3, rescale_unity = TRUE)

# 黄色みを帯びたRGBAのオーバーレイ画像を作る
sun_overlay <- array(0, dim = c(img_h, img_w, 4))
sun_overlay[, , 1] <- sun_disk
sun_overlay[, , 2] <- sun_disk * 0.85
sun_overlay[, , 3] <- sun_disk * 0.2
sun_overlay[, , 4] <- sun_disk

# 支笏湖の画像に太陽のオーバーレイを重ねる
render_image_overlay(shikotsuko, image_overlay = sun_overlay, preview = TRUE)

# 透明度を下げて重ねる
render_image_overlay(shikotsuko, image_overlay = sun_overlay, alpha = 0.4, preview = TRUE)

# 元画像をオーバーレイの寸法に合わせてリサイズする
render_image_overlay(shikotsuko,
  image_overlay = sun_overlay,
  rescale_original = TRUE, preview = TRUE
)

支笏湖の画像に太陽のオーバーレイを重ねる

透明度を下げて重ねる

元画像をオーバーレイの寸法に合わせてリサイズする

スプライト要素の重ね合わせ:render_sprite_overlayコマンド

ベースの画像の指定した座標に、スプライト画像を重ねて合成します。

オプション意味初期値
imageRGB/RGBA配列、rayimgクラス、または画像ファイル名なし
image_overlay重ねるスプライト画像NULL
convert_overlay_colorspaceオーバーレイの色空間を元画像に合わせるかどうかTRUE
alphaNAの場合はオーバーレイのアルファチャンネルを使う。数値を指定すると透明度を掛け合わせるNA
overlay_coordsオーバーレイを配置する画素座標c(x, y)c(1, 1)
overlay_dimsオーバーレイの寸法(画素)NULL
overlay_anchoroverlay_justがない場合に、overlay_coordsに合わせるオーバーレイの角“nw”
overlay_justオーバーレイの位置を数値で指定するc(hjust, vjust)NULL
hjust水平方向の位置指定NULL
vjust垂直方向の位置指定NULL
preserve_channelsTRUEの場合、入力と同じチャンネル構成で出力するTRUE
filename保存先のパスNULL
previewTRUEの場合、画像を表示するFALSE
# 「Lake Shikotsu」の文字を透過画像として作る
label_sprite <- render_text_image("Lake Shikotsu",
  size = 24, color = "#ffffff",
  background_alpha = 0, trim = TRUE, trim_padding = 4
)

# 画像の左上を基準に文字を重ねる
render_sprite_overlay(shikotsuko,
  image_overlay = label_sprite,
  overlay_coords = c(5, 5), preview = TRUE
)

# 画像の中央に文字を配置する
render_sprite_overlay(shikotsuko,
  image_overlay = label_sprite,
  overlay_coords = c(img_w / 2, img_h / 2),
  hjust = 0.5, vjust = 0.5, preview = TRUE
)

# アンカーを右下("se")に指定して配置する
render_sprite_overlay(shikotsuko,
  image_overlay = label_sprite,
  overlay_coords = c(img_w - 5, img_h - 5),
  overlay_anchor = "se", preview = TRUE
)

画像の左上を基準に文字を重ねる

画像の中央に文字を配置する

アンカーを右下(”se”)に指定して配置する

トーンマップの適用:render_tonemapコマンド

画像の輝度を、指定したトーンマッピング曲線で圧縮します。

オプション意味初期値
imageRGB/RGBA配列、rayimgクラス、または画像ファイル名なし
methodトーンマッピング曲線の種類。”raw”は無変換、”reinhard”はハイライトを穏やかに圧縮、”uncharted”は映画的な階調、”hbd”は高速な近似曲線c(“raw”, “reinhard”, “uncharted”, “hbd”)
exposure_bias“uncharted”のときのみ有効な、曲線適用前の露出係数2
W曲線適用後に白として扱う輝度の基準値11.2
filename保存先のパスNULL
preview結果を表示するかどうかFALSE
# 明るいハイライトを含む疑似HDR画像を作る(値が1を超える部分がある)
hdr_scene <- shikotsuko * 2

# 変換せずにそのまま表示する
render_tonemap(hdr_scene, method = "raw", preview = TRUE)

# Reinhardトーンマップでハイライトを抑える
render_tonemap(hdr_scene, method = "reinhard", preview = TRUE)

# Uncharted(Hableフィルミック)トーンマップを適用する
render_tonemap(hdr_scene, method = "uncharted", preview = TRUE)

# 白色点Wを大きくし、ハイライトの階調をより残す
render_tonemap(hdr_scene, method = "uncharted", W = 16, preview = TRUE)

# 露出係数を下げて暗めに仕上げる
render_tonemap(hdr_scene, method = "uncharted", exposure_bias = 1, preview = TRUE)

# Hejl-Burgess-Dawsonトーンマップを適用する
render_tonemap(hdr_scene, method = "hbd", preview = TRUE)

変換せずにそのまま表示する

Reinhardトーンマップでハイライトを抑える

Uncharted(Hableフィルミック)トーンマップを適用する

白色点Wを大きくし、ハイライトの階調をより残す

露出係数を下げて暗めに仕上げる

Hejl-Burgess-Dawsonトーンマップを適用する


この記事が誰かの役に立ちますように。

スポンサーリンク
価格および配送状況は変更される場合があります。購入時は商品ページをご確認ください。
当サイトに表示されている商品情報はAmazonから提供されたものであり、更新または削除される場合があります。
karada-goodはAmazonアソシエイトとして、適格販売により収入を得ています。