照度差ステレオ法


Woodham による照度差ステレオ法を用いて物体の表面の凹凸を表す画像を算出し、結果を保存するサンプルコードです。 入力画像は分割照射が可能なリング照明下で照明条件を変えながら複数枚撮像されていることを想定します。

import pyfie

# PyFIE 関数が返すエラーコードに応じて例外を発生させる機能を有効化
pyfie.ctrl.enable_f_err_exception(True)

# 入力画像ファイル
img_fnames = [
    "ps_src_01.png",
    "ps_src_02.png",
    "ps_src_03.png",
    "ps_src_04.png",
]
num_imgs = len(img_fnames)

# 前処理用パラメータ設定
min_pixel_value = 10

# リング照明パラメータ設定
light_height = 2
light_radius = 1
light_init_angle = 120
light_order = 0  # 0:時計回り、1:反時計回り

# 曲率・高さ画像計算用パラメータ設定
normal_thresh = 0.1
curvature_type = pyfie.F_CURVATURE_MEAN
horn_brooks_iter = 100

# 入力画像読み込み
himgs = [pyfie.imread(img_fname) for img_fname in img_fnames]

# 入力画像の整合性をチェック
if any(himg.f_type != himgs[0].f_type for himg in himgs):
    raise ValueError("inconsistent image type")
if any(himg.width != himgs[0].width or himg.height != himgs[0].height for himg in himgs):
    raise ValueError("inconsistent image size")
if any(himg.ch != 1 for himg in himgs):
    raise ValueError("Number of channels must be one")

# 入力画像を単一の多チャネル画像にまとめる
hsrc = pyfie.img_root_alloc(
    himgs[0].f_type, num_imgs, himgs[0].width, himgs[0].height)
for i, himg in enumerate(himgs):
    pyfie.img_copy(himg, hsrc.single_ch(i))

# 前処理
# Woodhamの手法では画素値が0に近いと精度不安定になるため、最小値を底上げする
pyfie.img_max_const(hsrc, min_pixel_value, hsrc)

# 分割照射が可能なリング照明の情報から光源ベクトルの情報を生成
slants = pyfie.DOUBLE.ARRAY(num_imgs)
tilts = pyfie.DOUBLE.ARRAY(num_imgs)
pyfie.ps_woodham_calc_light_ring(
    light_height, light_radius, light_init_angle, light_order, slants, tilts, num_imgs)

# Woodhamの手法による照度差ステレオ実行
hnormal = pyfie.img_dbl(hsrc.width, hsrc.height, ch=3)
pyfie.ps_woodham(hsrc, slants, tilts, hnormal, None)

# 曲率画像計算
hdst_curvature = pyfie.img_dbl(hsrc.width, hsrc.height, ch=1)
pyfie.ps_curvature(hnormal, hdst_curvature, normal_thresh, curvature_type)

# Frankot-Chellappa法による高さ画像計算
hdst_depth_fc = pyfie.img_dbl(hsrc.width, hsrc.height, ch=1)
pyfie.ps_frankot_chellappa(hnormal, hdst_depth_fc, normal_thresh)

# Horn-Brooks法による高さ画像計算
hdst_depth_hb = pyfie.img_dbl(hsrc.width, hsrc.height, ch=1)
pyfie.ps_horn_brooks(hnormal, hdst_depth_hb, normal_thresh, horn_brooks_iter)

# 結果画像保存
hnormal_uc8 = hnormal.empty_like(img_type=pyfie.F_IMG_UC8)
pyfie.img_copy_ex(hnormal, hnormal_uc8, 0, -1, 255.0 / 2)
pyfie.imwrite("normal.png", hnormal_uc8)


def imwrite_as_uc8(fname: str, himg_dbl: pyfie.FHANDLE):
    himg_uc8 = himg_dbl.empty_like(img_type=pyfie.F_IMG_UC8)
    pyfie.img_copy_ex(himg_dbl, himg_uc8, 1, 0, 0)
    pyfie.imwrite(fname, himg_uc8)


imwrite_as_uc8("curvature.png", hdst_curvature)
imwrite_as_uc8("depth_frankot_chellappa.png", hdst_depth_fc)
imwrite_as_uc8("depth_horn_brooks.png", hdst_depth_hb)

処理結果例

入力画像1(光源位置:左下)

../../_images/ps_src_01.png

入力画像2(光源位置:左上)

../../_images/ps_src_02.png

入力画像3(光源位置:右上)

../../_images/ps_src_03.png

入力画像4(光源位置:右下)

../../_images/ps_src_04.png

出力法線画像

../../_images/normal.png

出力曲率画像

../../_images/curvature.png

出力高さ画像(Frankot-Chellappa法)

../../_images/depth_frankot_chellappa.png

出力高さ画像(Horn-Brooks法)

../../_images/depth_horn_brooks.png

ダウンロード