Markdownで表示

深度推定

深度推定は1枚の画像から各ピクセルとカメラの距離を予測します。LibreYOLOではdepthタスクとして提供され、元画像のキャンバス上に密な相対逆深度マップを返します。

定義

depthタスクは1枚のRGB画像からピクセルごとに1つの値を予測します。LibreYOLOではその値を相対逆深度として定義します。値が大きいほどカメラに近く、メートルなどの単位はなく、2枚の画像間で共通するスケールもありません。同じ推論結果の2ピクセル間で深度を比較することには意味がありますが、別画像の値との比較には意味がありません。

推論結果ではresult.depth_mapに値が格納されます。これは元画像のキャンバス上にある(H, W)配列を保持するDepthMapペイロードです。.min.max.meanで有限値を読み取り、.normalized()で表示用にマップを[0, 1]へ再スケーリングできます。result.boxesは空のままなので、confioumax_detは効果がありません。save=Trueは注釈付き写真ではなく、マップにカラーマップを適用した画像を書き込みます。

モデル

depthには6つのファミリーが対応します。

Depth Anything V2はDINOv2エンコーダーとDPTデコーダーを組み合わせ、ここでの汎用的なデフォルトです。精度と同様にライセンスもサイズ選択を左右します。SmallチェックポイントはApache-2.0ですが、BaseとLargeは非商用です。選択前にモデルページのチェックポイント表を確認してください。

Depth Anything 3はDA3MONO-LARGEチェックポイントを移植したもので、深度向けにアーキテクチャを特殊化していない通常のTransformerです。

ZipDepthは小型ティアです。Depth Anything V2 Largeから蒸留した再パラメーター化可能なCNNで、gatherやunfold演算に対応しないNPUコンパイラー向けに、これらの演算をデコーダーで回避する第2のチェックポイントもあります。

MiDaSは、他のファミリーの測定にも使われるゼロショット相対深度の手法を確立した一連の研究です。LibreYOLOが再公開しない唯一の深度ファミリーで、チェックポイントを要求すると著者の公式GitHubリリースからアーティファクトをダウンロードし、固定済みのSHA-256を確認します。

LibreMODUSは専用ヘッドではなく、任意入力から任意出力へのモデルにある1つの対象として深度を生成します。modus追加パッケージと認証済みのHugging Faceアカウントが必要で、val()export()には対応しません。

SenseNova-Visionは、7つのタスクに対応する同じ7Bチェックポイントを使い、拡散デコードを通して深度マップを画像として生成します。sensenova追加パッケージが必要で、重みの利用は非商用に制限されます。ライセンスはモデルページに記載されています。

推論

前述の2ファミリーを除き、重みは初回使用時にHugging Faceからダウンロードされ、ローカルにキャッシュされます。

深度マップを推論
from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("LibreDepthAnythingV2s-depth.pt")result = model(SAMPLE_IMAGE, save=True) depth = result.depth_mapprint(depth.data.shape)              # 元キャンバス上の(H, W)print(depth.min, depth.max, depth.mean)
値を処理
from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("LibreDepthAnythingV2s-depth.pt")result = model(SAMPLE_IMAGE) depth = result.depth_mapraw = depth.data          # 大きいほど近い メートル単位もスケールもないgray = depth.normalized() # 可視化用に[0, 1]へ再スケーリングprint(raw.shape, float(gray.max()))
小型の代替モデル
from libreyolo import LibreYOLO, SAMPLE_IMAGE # 同じタスク契約でエッジランタイム向けに構築された非常に小さなネットワークmodel = LibreYOLO("LibreZipDepthb-depth.pt")result = model(SAMPLE_IMAGE) print(result.depth_map.data.shape)

入力解像度はファミリーごとに制約されます。Depth Anything V2とDepth Anything 3はDINOv2のパッチグリッドを基にするため、imgszは14で割り切れる必要があり、LibreYOLOは実行前に確認します。Results.plot()はこのタスクには対応せず、サーフェス法線とエッジだけに定義されています。入力ソース、ストリーミング、結果の処理については推論を参照してください。

データセット形式

深度の検証では、各画像を同じ解像度の密な単一チャンネル深度マップと対応付けます。画像パス内の画像ディレクトリを深度ディレクトリへ置き換えてファイルを検索します。

dataset/
  data.yaml
  images/
    val/room.jpg
  depths/
    val/room.png
yaml
path: dataset
val: images/val
depths_dir: depths
nc: 1
names: {0: depth}

マップは単一チャンネルのPNGまたはTIF、あるいは.npyです。値はデータセット内で一貫した単位の通常の深度です。0、負の値、NaN、無限大のピクセルは無効なサンプルとして指標から除外されます。整数マップはdepth_scaleで割られます。デフォルトは16ビットPNGの慣例である256.0です。floatの.npyマップはそのまま使用されます。depth_stem_suffixdepth_mask_suffixは、深度ファイルや有効性マスクに異なる命名規則を使うデータセットに対応します。完全な契約についてはデータセット形式を参照してください。

学習

LibreYOLOの深度ファミリーには学習実装がありません。6つすべてでtrain()NotImplementedErrorを送出します。各モデルページには、アップストリームで学習したチェックポイントをLibreYOLOで読み込める形式へ変換するスクリプトが記載されています。

検証

val()は共通の深度検証器を実行します。相対深度には絶対スケールがないため、まず画像ごとの最小二乗法によるスケールとシフトで各予測を正解の逆数に適合させ、次に深度へ戻します。以下の各指標は、データセットが有効と示すピクセルだけを数え、位置合わせ済みのマップに対して画像ごとに計算し、データセット全体で平均します。

検証して指標キーを確認
from libreyolo import LibreYOLO model = LibreYOLO("LibreDepthAnythingV2s-depth.pt")metrics = model.val(data="my-dataset.yaml") print(metrics["metrics/abs_rel"])print(metrics["metrics/rmse"])print(metrics["metrics/delta1"])   # fitnessprint(metrics["metrics/delta2"], metrics["metrics/delta3"])

metrics/abs_relは平均絶対相対誤差です。残差を正解深度で割った値で、小さいほど良い指標です。metrics/rmseはデータセット固有の深度単位における二乗平均平方根誤差で、これも小さいほど良い指標です。metrics/delta1metrics/delta2metrics/delta3はしきい値精度です。予測と正解の比率を大きい側で取った値が、それぞれ1.25、1.25の2乗、1.25の3乗を下回る有効ピクセルの割合で、大きいほど良い指標です。metrics/delta1は最良チェックポイントの選択で使うfitnessにもなります。

エクスポート

エクスポートした深度モデルはファイルの拡張子に基づいてLibreYOLO()で再読み込みできるため、.onnx.engineファイルもチェックポイントと同様に動作します。返されるResultsにはボックスの代わりにdepth_mapが含まれます。

エクスポート
from libreyolo import LibreYOLO model = LibreYOLO("LibreDepthAnythingV2s-depth.pt")model.export(format="onnx")
エクスポートしたファイルを実行
from libreyolo import LibreYOLO, SAMPLE_IMAGE # ファクトリはファイルの拡張子に応じて振り分けるためエクスポートした# アーティファクトもチェックポイントと同様に読み込まれ同じResultsオブジェクトを返すmodel = LibreYOLO("LibreDepthAnythingV2s-depth.onnx")result = model(SAMPLE_IMAGE) print(result.depth_map.data.shape)

対応範囲はファミリーごとに異なり、Depth Anything 3は未検証の変換を試みず、検証済みの集合にない形式を拒否します。対象を決める前にモデルページと完全なエクスポートマトリックスを確認してください。LibreMODUSとSenseNova-Visionはエクスポートできません。エクスポートには各形式で受け付ける引数が記載されています。

LibreYOLO v1.5.0で検証済みです。