💬

単眼Depth推定を試してみました。

2024/07/31に公開

はじめに

iPhoneにLiDARが搭載されているということで3Dスキャナーとして、遊べないかなと思ったのですがPROしか対応してないということで断念。。。

Apple Intelegenceの搭載もPROだけになりそうなので、次はPROに乗り換えようとも思うのですが新機種が出て買い替えのタイミングまでは大人しくしているしかなさそうですね。

ということで諦めていたのですが、単眼Depth推定とというもので通常のカメラ画像から深度(絶対値は無理ですが。。。)を推定することが出来るというので試してみました。

今回試したモデル

  • MiDaS
    MiDaSは、複数種のデータセットで学習された、Zero-shot (Fine-tuningなし) で使える単眼深度推定モデルです。MiDaS v2.1は10種類のデータセットで学習されており、様々な環境に対応できる汎用性の高いモデル

  • Marigold
    Marigoldは、安定した拡散モデル(Stable Diffusion)をベースとし、合成データセットのみを用いて訓練された単眼深度推定モデルです。画像と対応する深度マップを共有潜在空間にエンコードし、条件付きデノイザーを微調整することにより深度推定を行います

MiDaSを使った深度推定

torch.hubからモデルをダウンロードして、実行する。

import cv2
import torch
import numpy as np

# MiDaSモデルのロード
model_type = "MiDaS_small"
midas = torch.hub.load("intel-isl/MiDaS", model_type)
device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")
midas.to(device)
midas.eval()

# 入力画像の読み込みと前処理
img = cv2.imread("input_image.jpg")
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

# 深度推定の実行
with torch.no_grad():
    prediction = midas(img)

# 結果の可視化
output = prediction.cpu().numpy().squeeze()
output = cv2.normalize(output, None, 0, 1, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_32F)

# 結果の表示
cv2.imshow("Depth Map", output)
cv2.waitKey(0)

物体の3Dスキャンをしたいということで以下のようなデータを利用
元画像

推定結果

残念ながら歯ブラシのブラシ部分が認識出来ていない。。
他のデータも試してみましたが、このモデル物体感の前後関係を推定することがメインのようで、1つの物体の形状を取ることは難しいようです。

Marigoldを使った深度推定

GPUを利用しないで実行したところ、2時間ぐらいかかりました。
Google colaboratoryのGPUを利用すると数分で実行されます。
Diffusionモデルを利用しているということなので、CPUでの実行は難しそうです。

from diffusers import DiffusionPipeline
import torch
import numpy as np
from PIL import Image

# Marigoldモデルをロード
pipe = DiffusionPipeline.from_pretrained(
    "Bingxin/Marigold",
    custom_pipeline="marigold_depth_estimation"
)

# GPUを使用可能な場合は、GPUに移動
device = "cuda" if torch.cuda.is_available() else "cpu"
pipe = pipe.to(device)

# 入力画像のパス
input_image_path = "path/to/your/input/image.jpg"

# 画像を読み込む
image = Image.open(input_image_path)

# 深度推定を実行
depth = pipe(image, denoising_steps=4).images[0]

# 結果を保存
depth.save("output_depth.png")

# NumPy配列として深度マップを取得(必要な場合)
depth_np = np.array(depth)

print("深度推定が完了しました。結果は'output_depth.png'に保存されました。")

元画像

推定結果

ブラシの部分も綺麗に推定出来ています。

点群データとして、3D化

もう一つのサンプル
元画像

推定結果

3D化画像

穴の部分(凹)が凸形状で認識していますが、他は問題なさそう

まとめ

拡散モデル(Stable Diffusion)を利用したMarigoldであればカメラ画像からある程度3Dの認識は出来そうであることを確認した。

人間は複眼であるが、実際のところは片目の単眼でも深度の認識はほとんどできている。
これは、経験的に遠近法と物体の大きさを脳が学習しているからだと思われる。

つまり、学習を進めていけば人間と同様のレベルの深度推定はAIにも可能になっていくと思われます。
(人間と同様に錯覚を利用した騙し絵のようなものは、人間と同じように引っかかると思いますが。。。)

ロボットに搭載することも考えましたが、外部のGPU環境が必要なことを考えるとセンサーの方が低価格なので、距離測定はセンサーを利用した方が良さそうですね。

参考

https://weel.co.jp/media/tech/marigold-lcm/

https://qiita.com/airpocket/items/316913e7b596fa9bb1d2

Discussion