蟹者

@kanimono

python+OpenCVでステレオマッチングするんだけど、キャリブレーション結果どうやって反映させるねん

python+OpenCVでステレオマッチング(左右カメラ画像の対応点探索)して、対象の3次元座標を計測する、というのを一応ゴールにやってきたんだけど

本家pythonチュートリアルDepth Map from Stereo Images — OpenCV-Python Tutorials 1 documentationは、今までの話(キャリブレーション、姿勢推定…云々)をすっとばして、いきなり「奥行マップをつくろう(唐突)」となるわけです。


視差disparity = B f / Z
となるわけだから、
奥行きZは = B f / disparityとなり、求められるのはわかる。

じゃあ基線長Bってどんな値なのか?単純にカメラ間の距離を定規ではかるだけでいいのだろうか?
そしてこの式が使えるのは平行ステレオの場合のみのはず(教科書((Amazon.co.jp: ディジタル画像処理: 本)))



今のところ僕の理解ではこんな流れのはず。
・内部パラメータをそれぞれのカメラごとに求める
・外部パラメータを左右のカメラ同時に求める
 ・solvePnP関数なるものによって、それぞれのカメラに対しての外部パラメータを求める方法は記載してある。これをどう合わせるのか目下謎。
 ・同時に求める(2枚の画像を読み込ませ)関数も存在するはず・・・。どこかに。
・わかった内部パラメータ、外部パラメータから、三次元座標への変換パラメータを導出する。
(あるいは、内部パラメーター、外部パラメーターを利用して歪み補正や平行化を行い、平行ステレオと同じ条件で得られた理想画像(っぽいの)に補正する)


よくわかんねーなーと思って調べてたら奥行きマップから3次元モデルを生成という記事があった。python-gazo.blog.jp


最終的にやりたいゴールをこれなので、とりあえずコードをパクリ、色々動かして見ながら調べてみることにした。コードはこれ、例によってmain関数は外す。視差画像を求めるまで。

# -*- coding: utf-8 -*-

import cv2

# 画像取得
gray_l = cv2.imread("left.png",0)
gray_r = cv2.imread("right.png",0)
# 画像のヒストグラム平坦化・平滑化
gray_l = cv2.GaussianBlur( cv2.equalizeHist(gray_l),(5,5), 0)
gray_r = cv2.GaussianBlur( cv2.equalizeHist(gray_r),(5,5), 0)
# BM法でステレオ対応点探索
stereo = cv2.StereoBM(cv2.STEREO_BM_BASIC_PRESET,ndisparities=32, SADWindowSize=21)
disp = stereo.compute(gray_l,gray_r)    # 視差を計算
# 視差データを8bitデータに変換(imshowで表示させるため)
disp = cv2.normalize(disp, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)
cv2.imshow("disp",disp)                 # 視差画像の表示
cv2.waitKey(0)
cv2.destroyAllWindows()


パクリ元python-gazo.blog.jp

・とりあえず動く。
ヒストグラム平坦化をなぜやるのかは不明。