メトロポリスサンプリングをカラー値に適用する

2014-12-22

メトロポリスサンプリングをカラー値に適用する

メトロポリス輸送の事始めの続きで、

A Practical Introduction to Metropolis Light Transport の 2.2 Color Images の節。

2.2 Color Images

  • メトロポリスフレームワークはヒストグラムにカラー値を蓄積するよう再定義することで、簡単に カラー画像を扱うように拡張することができる
  • カラーサンプルのルミナンスから を計算し、ヒストグラムに加算するカラー値は ルミナンスが1となるようにスケールする
  • 変異戦略と各サンプルのピクセル座標はカプセル化された。MLTでは、DomainLocation構造体は ピクセル位置だけじゃなく全てのライトパスも含むことになる。
// A Practical Introduction to Metropolis Light Transport
// 2.2 Color Images
void makeHistogram(int w, int h, PVector[] F, PVector[] histogram, int mutations) {
// Create an initial sample point
DomainLocation X = new DomainLocation();
X.xloc = randomInteger(0, w - 1);
X.yloc = randomInteger(0, h - 1);
PVector colorX = new PVector(F[X.yloc * w + X.xloc].x, F[X.yloc * w + X.xloc].y, F[X.yloc * w + X.xloc].z);
float Fx = luminance(colorX);
if (Fx > 0)
colorX.mult(1.0 / Fx);

DomainLocation Y = new DomainLocation();

// Create a histogram of values using Metropolis sampling.
for (int i = 0; i < mutations; ++i) {
// choose a tentative next sample according to T.
mutateAccordingToT(w, h, X, Y);
float Tyx = T(w, h, Y, X);
float Txy = T(w, h, X, Y);

PVector colorY = F[Y.yloc * w + Y.xloc];
float Fy = luminance(colorY);
float Axy = min(1.0, (Fy * Txy) / (Fx * Tyx)); // equation 2.
if (randomReal(0.0, 1.0) < Axy) {
X.set(Y);
Fx = Fy;
colorX.set(colorY.x / Fy, colorY.y / Fy, colorY.z / Fy);
}
histogram[X.yloc * w + X.xloc].add(colorX);
}
}

void mutateAccordingToT(int w, int h, DomainLocation X, DomainLocation Y) {
Y.xloc = randomInteger(0, w - 1);
Y.yloc = randomInteger(0, h - 1);
}

float T(int w, int h, DomainLocation X, DomainLocation Y) {
return 1.0 / (w * h);
}

float luminance(PVector v) {
return 0.299 * v.x + 0.587 * v.y + 0.114 * v.z;
}

デモ

  • 内容は特に問題なし
  • ProcessingのJavaモードで動かすぶんにはそこそこ高速に動作するが、JavaScript用に エクスポートするとめちゃくちゃ処理が重い。カラー値を保持する PVector を破壊的に操作 するようにしてもそれでも重い。困ったもんだ。