トップ 問題解決の記録

閉包面(closure-surface)問題

目的

長尺動画を複数セグメントに分割し、各セグメントを個別にCOLMAPで処理した後、結果をマージして大規模な統合メッシュを生成する。

問題

各セグメントのPoisson再構成結果をマージすると、メッシュの裏面に布状のアーチファクト(閉包面)が発生。これにより視覚品質が著しく低下した。

原因

個別セグメントのPoisson再構成が、点群の裏側(地面上)を閉包する面をそれぞれ独立に生成する。これらをマージすると2枚の閉包面が布状の膜として残存する。ポリゴン数の増加にもつながる。

Poisson Surface Reconstructionは与えられた点群から水密(watertight)な閉じたメッシュを生成するアルゴリズムである。点群の向き付き法線から内外を分ける指示関数(indicator function)を計算し、その等値面をメッシュ化する。このときドローン空撮では点群は上空側(撮影側)の表面のみを捉えており、物体の裏面や地面下には点が存在しない。Poissonはメッシュを閉じる必要があるため、点群の存在しない側(通常は地面の下方向)に人工的な蓋を張る。これが閉包面である。

ドローン空撮範囲 空撮範囲 点群(上空表面のみ) 閉包面(人工的な蓋) ← Poissonが水密メッシュを 閉じるために生成

セグメントごとに閉包面の大きさが異なる理由

要因閉包面が大きくなりやすい閉包面が小さくなりやすい
点群形状平坦な地形(地面のみ)→ 広い蓋が必要凸構造(建物・樹木)→ 点群自体が蓋を形成
境界条件セグメント端で3方向以上が開放周囲を点群で囲まれている
地面点の有無水面・樹冠など地面なし → 大きな閉包面地面まで点がある → 狭い閉包面
点群密度低密度 → 補間範囲が広がる高密度 → 境界がシャープ

例えば、橋梁だけを捉えたセグメントでは水面下に点が存在しないため、Poissonは橋の下面から水面位置まで広大な閉包面を張る。一方、建物街区のセグメントでは壁面点群が内側を閉じるため閉包面は小さくなる。また、フライト経路の端のセグメントほど開放境界が多く、中央のセグメントより閉包面が顕著になる。

平坦地形 (閉包面: 大) 閉包面 建物街区 (閉包面: 小) 壁面点群が蓋の役割 橋梁 (閉包面: 特大) 水面(点なし) 閉包面(特大)

対策

解決策の原理

全セグメントの点群をマージしてから単一のPoisson再構成を実行すると、閉包面は全体の外側境界に1回だけ張られる。各セグメント間の重複領域では実際の点群が蓋の役割を果たすため、余分な閉包面は発生しない。

個別Poisson再構成 × マージ(問題) セグメントA 点群 蓋A + セグメントB 点群 蓋B マージ結果 蓋A + 蓋B の二重膜 ✗ 閉包面が重なる 単一Poisson再構成(解決) 全セグメント点群をマージ 外側境界に1枚だけの蓋 ✓ 閉包面なし

恒久対策

上記の原理に基づき、点群マージ後に単一のPoisson再構成を実行する。

検証

0156_Dで検証: 11.4M点→voxel 0.02で6M点にダウンサンプル→Poisson depth=10→481K verts, 969K tris。閉包面は完全に消滅。

影響

ステータス

恒久対策済み

別案: 立体物単位のセグメント分割

現行の「全点群マージ→単一Poisson」はパラメータフリーで閉包面を解決したが、場合によっては別のアプローチも有効と考えられる。以下は継続検討中の方法。

現在の均等分割(等フレーム数)に代わり、立体物(建物・橋など)を上空から一括で捉えるようにセグメントを切り出す方法も考えられる。セグメント内の点群がZ方向に広がりを持つほど、Poisson再構成時の閉包面は小さくなる。

使用可能なパラメータ

フェーズ1: COLMAP実行前(動画+SRTのみ、計算コスト低)

パラメータ指標取得元判定
GPS軌道の曲率進行方位角の微分値SRT heading高曲率 → 構造物周りを旋回
対地高度変化rel_alt の分散/微分SRT rel_alt急変 → 構造物通過
ジンバルピッチgimbal_pitch 角度SRT斜め下向き → 構造物注視
画像エントロピー輝度ヒストグラムのエントロピーフレーム画像高 → テクスチャ豊富(構造物)
オプティカルフローフレーム間の平均flow magnitudeffmpeg motionフィルタ不均一 → 視差大(立体物)
平直:   ─────────────────  曲率≒0 → 平坦地形(ここでカット)
構造物: ╭───╮  曲率大 → 橋・建物
        │   │
        ╰───╯

フェーズ2: 高速sparse COLMAP後(より正確)

パラメータ指標理由
フレームあたり登録点数各カメラのobservations数多い → 立体構造が写っている
3D点Z範囲局所領域内の標高幅Z幅大 → 立体的(建物・橋)
特徴点マッチ数フレーム対のinlier数構造物境界で視差によるマッチ増

実装イメージ

def detect_structure_boundaries(srt_data, window=30):
    # 進行方位角の変化率(曲率)
    heading_delta = np.abs(np.diff(srt_data.heading))
    heading_delta = np.convolve(heading_delta, np.ones(window)/window, mode='same')

    # 高度変化率
    alt_delta = np.abs(np.diff(srt_data.rel_alt))
    alt_delta = np.convolve(alt_delta, np.ones(window)/window, mode='same')

    # 曲率+高度変化が共に低い → 平坦通過中 → ここがカット候補
    flat_mask = (heading_delta < threshold_heading) & (alt_delta < threshold_alt)
    cut_points = find_longest_flat_regions(flat_mask)
    return cut_points

課題