2016年7月17日日曜日

OpenCVを利用したステレオカメラの作り方

USBカメラ2台でステレオカメラを作り、OpenCVで処理して深度を取得してみました。
備忘録として作り方と動作結果を共有します。

使ったもの

  • USBカメラ2台
  • ダンボール
  • python-opencvをインストールしたPC

カメラの準備

ざっくりと平行になるよう、ダンボールに固定します。


動作させながら角度を調整するため、完全には固定はしません。

OpenCVのインストール

OpenCV2.7で良い場合はapt-getでインストールできます。
sudo apt install libopencv-dev python-opencv
参考: Raspberry Pi B+にOpenCV-Python環境を構築する

OpenCV3系が良い方は、ソースからコンパイルしてください。
参考: Install OpenCV 3.0 and Python 2.7+ on Ubuntu

プログラム作成

pythonで作成しました。
カメラの番号(VideoCaptureの引数)はお使いの設定環境に合わせて変更してください。
import numpy as np
import cv2
IMAGE_WIDTH = 640
IMAGE_HEIGHT = 480
capL = cv2.VideoCapture(0)
capR = cv2.VideoCapture(1)
imgL = np.zeros((480,640,3), np.uint8)
imgR = np.zeros((480,640,3), np.uint8)
stereo = None
opencv_measure_version = int(cv2.__version__.split('.')[0])
windowSize = 5
minDisp = 32
numDisp = 144 - minDisp
if (opencv_measure_version <= 2):
# for OpenCV2
stereo = cv2.StereoSGBM(
minDisparity = minDisp,
numDisparities = numDisp,
SADWindowSize = 16,
P1 = 8*3*windowSize**2,
P2 = 32*3*windowSize**2,
disp12MaxDiff = 1,
uniquenessRatio = 10,
speckleWindowSize = 100,
speckleRange = 32
)
capL.set(cv2.cv.CV_CAP_PROP_FRAME_WIDTH, IMAGE_WIDTH)
capL.set(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT, IMAGE_HEIGHT)
capR.set(cv2.cv.CV_CAP_PROP_FRAME_WIDTH, IMAGE_WIDTH)
capR.set(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT, IMAGE_HEIGHT)
else:
# for OpenCV3
stereo = cv2.StereoSGBM_create(
minDisparity = minDisp,
numDisparities = numDisp,
blockSize = 16,
P1 = 8*3*windowSize**2,
P2 = 32*3*windowSize**2,
disp12MaxDiff = 1,
uniquenessRatio = 10,
speckleWindowSize = 100,
speckleRange = 32
)
capL.set(cv2.CAP_PROP_FRAME_WIDTH, IMAGE_WIDTH)
capL.set(cv2.CAP_PROP_FRAME_HEIGHT, IMAGE_HEIGHT)
capR.set(cv2.CAP_PROP_FRAME_WIDTH, IMAGE_WIDTH)
capR.set(cv2.CAP_PROP_FRAME_HEIGHT, IMAGE_HEIGHT)
while True:
capL.read(imgL)
capR.read(imgR)
# create gray images
imgGrayL = cv2.cvtColor(imgL, cv2.COLOR_BGR2GRAY)
imgGrayR = cv2.cvtColor(imgR, cv2.COLOR_BGR2GRAY)
# calculate histogram
imtGrayL = cv2.equalizeHist(imgGrayL)
imtGrayR = cv2.equalizeHist(imgGrayR)
# through gausiann filter
imgGrayL = cv2.GaussianBlur(imgGrayL, (5,5), 0)
imgGrayR = cv2.GaussianBlur(imgGrayR, (5,5), 0)
cv2.imshow("image left", imgGrayL)
cv2.imshow("image right", imgGrayR)
# calculate disparity
disparity = stereo.compute(imgGrayL, imgGrayR).astype(np.float32)/16
disparity = (disparity - minDisp) / numDisp
cv2.imshow("disparity", disparity)
k = cv2.waitKey(33)
if k == ord('q'):
break;
view raw stereo.py hosted with ❤ by GitHub
下記のコマンドでダウンロードできます。
wget -O stereo.py https://gist.github.com/asukiaaa/1d8c9f8667c321265e83edab2bc5d4e9/raw

OpenCVのバージョンが2か3によってStereoSGBMや定数の呼び出し方法が違うので、このように対応しています。
if (opencv_measure_version <= 2):
  # for OpenCV2
  stereo = cv2.StereoSGBM(
    # ..
    SADWindowSize = 16,
    # ..
  )
  capL.set(cv2.cv.CV_CAP_PROP_FRAME_WIDTH,  IMAGE_WIDTH)
  capL.set(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT, IMAGE_HEIGHT)
  capR.set(cv2.cv.CV_CAP_PROP_FRAME_WIDTH,  IMAGE_WIDTH)
  capR.set(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT, IMAGE_HEIGHT)
else:
  # for OpenCV3
  stereo = cv2.StereoSGBM_create(
    # ..
    blockSize = 16,
    # ..
  )
  capL.set(cv2.CAP_PROP_FRAME_WIDTH,  IMAGE_WIDTH)
  capL.set(cv2.CAP_PROP_FRAME_HEIGHT, IMAGE_HEIGHT)
  capR.set(cv2.CAP_PROP_FRAME_WIDTH,  IMAGE_WIDTH)
  capR.set(cv2.CAP_PROP_FRAME_HEIGHT, IMAGE_HEIGHT)


動作させながら調整

下記のコマンドで実行します。
python stereo.py
「q」か「Ctl-c」でプログラムは止まります。

「image left」に左のカメラ、「Image right」に右のカメラの出力が表示されていることを確認します。
出力が合っていない場合は、コードの「cv.VideoCapture」に渡す番号を変えて、プログラムを再実行してみてください。


角度が悪いと認識が良くないので、左右が平行になるようにダンボールをねじったり折ったりして調整してください。
カメラによってレンズの向きに個体差があるため、平行になるとは限りません。
自分の持っているカメラの場合は、このような角度差だと良い結果を得られました。


調整がうまくいけば、画像処理から深度が算出されます。


ざっくりとした作りのカメラから、ざっくりとした深度が取れました。

以上です。
何かの参考になれば嬉しいです。

参考

Depth Map from Stereo Images
Stereo Vision Tutorial - Part I
2014-11-03 100均Webカメラ2台でステレオマッチングやってみた
Disparity of stereo images with Python and OpenCV
StereoBM in OpenCV 3 (Python) missing module

キャリブレーションを行うと、精度が上がるかもしれません。
How to calibrate a stereo setup (two DVS or DAVIS sensors)

変更履歴

2016/10/13
OpenCVの設定を追加しました。
ソースコードをgist化しました。
OpenCV2にも対応しました。

2017/11/13
apt installコマンドが冗長だったので、短縮しました。
気になる日本語の記述がいくつかあったので、修正しました。

2019/04/29
OpenCVの記述が大文字だったり小文字だったりしたので、「OpenCV」に統一しました。

0 件のコメント :