fullseye

凹みの相互反射で縞投影と ToF が外れる量を、撮る前に予測する(大域光輸送・直接と大域の分離・マイクロ位相シフト)

できること

縞投影(位相シフト)も ToF も、「画素に届く光は 1 つの経路から来た」と仮定して位相を距離に変えます。V 溝・加工ポケットの内角・はんだフィレット・部屋の隅のような凹んだ形では、片方の面で反射した光が向かいの面を照らし、画素には別の場所の位相を持った光が混ざります(相互反射 = 大域成分)。光沢も金属も要らず、白い Lambert 面でも凹んでいれば起きます。このページの op は、その光の行き来を輸送行列として明示的に解き、誤差を閉形式で予測します。

What it does

Global light transport for concave Lambertian parts and its effect on active 3-D: an explicit light-transport matrix for an extruded concave cross-section (Hottel’s crossed-strings form factors, checked against the V-groove closed form 1 − sin(θ/2) and against quadrature of the 2-D kernel to 1e-14; radiosity T = (I − diag(ρ)F)^-1 diag(ρ), or its Neumann partial sum by bounce count); shifted high-frequency patterns and the Nayar et al. (2006) L_max / L_min separation into direct and global images (general fill α, black level b, pattern-plus-complement); the fringe phase as the argument of the direct-plus-global phasor sum, predicted per pixel from the transport matrix and matching the phase decoded from rendered fringes by fringe.wrapped_phase to 1e-15 rad; a micro phase-shifting decoder (Gupta & Nayar 2012) that orders narrow-band high-frequency fringes by their beat; and AMCW time-of-flight multipath, both as a phasor sum and as complex radiosity with per-bounce path delay. On a white 1 mm, 0.5 mm deep 90° V-groove, one fringe across a 4 mm field misreads height by 282 µm RMS; the micro set brings it to 0.76 µm.

向くところ / 向かないところ

最初の 1 本

import numpy as np
import fringe
import fullseye as fs

groove = fs.ledger.groove_profile("vgroove", 120, angle_deg=90.0)         # 幅 1、深さ 0.5 の内角
T = fs.ledger.transport_matrix_radiosity(groove, 0.85)                   # 白い Lambert(反射率 0.85)
D = fs.ledger.transport_matrix_radiosity(groove, 0.85, n_bounces=0)      # 直接光だけ(真値)

stripes = fs.ledger.high_frequency_patterns((1, 240), 8)                 # 点灯率 1/2 の縞を 8 回ずらす
sep = fs.ledger.separate_direct_global(fs.ledger.render_transport(T, stripes))
truth = fs.ledger.render_transport(D, [np.ones((1, 240))])[0]
print("分離した直接光の誤差 %.1f %%" % (100 * np.abs(sep["direct"] - truth).mean() / truth.mean()))

fr = fs.ledger.high_frequency_patterns((1, 240), 240.0, kind="sinusoid")  # 視野に縞 1 本
d = fringe.wrapped_phase(fs.ledger.render_transport(T, fr)) - fringe.wrapped_phase(fs.ledger.render_transport(D, fr))
meas = np.angle(np.exp(1j * d))                                           # (-π, π] に戻す
pred = fs.ledger.predict_fringe_phase_error(T, 240.0, projector_width=240)
print("位相の誤差 最大 %.3f rad、予測との差 %.1e" % (np.abs(pred["bias"]).max(), np.abs(pred["bias"] - meas[0]).max()))

裏づけ