カメラキャリブレーションについて簡単なまとめ
[History] [Last Modified] (2019/08/14 16:32:28)
ここは
趣味のプログラミングを楽しむための情報共有サービス。記事の一部は有料設定にして公開できます。 詳しくはこちらをクリック📝
Recent posts
Popular pages

概要

カメラキャリブレーション (Camera Calibration, Camera Resectioning) を行うと、レンズの歪みを表現するパラメータや、カメラのワールド座標系での位置姿勢を推定できます。

チェスボードのようなキャリブレーション専用のボードが利用されます。

Uploaded Image

キャリブレーションで得られたパラメータを用いると、例えば歪みを補正することができます。

Uploaded Image

カメラキャリブレーションのおおまかな流れは以下のようになります。

キャリブレーションボードの画像をカメラで撮影

キャリブレーションで利用するのは距離センサで取得した情報ではなく、カメラで取得した平面画像です。カメラの位置を固定したまま、キャリブレーションボードを様々な位置に移動させて画像を撮影します。

キャリブレーションボードの各点の座標を取得

画像処理を行い、キャリブレーションボードの各点の、平面画像内での座標を取得します。

Uploaded Image

連立方程式を立てる

画像処理で取得したキャリブレーションボードの各点の座標 $(u, v)$ と、ある座標系におけるキャリブレーションボードの各点の座標 $(x, y, z)$ は既知です。例えばローカル座標系におけるキャリブレーションボードの各点の座標は (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0) のようになります。

変換行列 T とカメラモデルを表現する行列 K を用いると以下のような連立方程式が立てられます。キャリブレーションにおいて、KT をそれぞれ内部パラメータ (Intrinsics) および外部パラメータ (Extrinsics) とよびます。

$$s \begin{pmatrix} u \\ v \\ 1 \end{pmatrix} = K T \begin{pmatrix} x \\ y \\ z \\ 1 \end{pmatrix} $$

$$T = \begin{pmatrix} r_{11} & r_{12} & r_{13} & t_1 \\ r_{21} & r_{22} & r_{23} & t_2 \\ r_{31} & r_{32} & r_{33} & t_3 \end{pmatrix} $$

K はカメラの種類に応じて異なりますが、ピンホールカメラの場合は以下のようになることが知られています。

$$K = \begin{pmatrix} f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \end{pmatrix} $$

Camera Calibration and 3D Reconstruction

Uploaded Image

OpenCV で連立方程式を解く

OpenCV にはカメラキャリブレーションのための機能が実装されています。キャリブレーションで利用する画像も OpenCV に含まれています。

$ ls samples/data/left*.jpg | head -2
samples/data/left01.jpg
samples/data/left02.jpg

sample.py

#!/usr/bin/python
# -*- coding: utf-8 -*-
import numpy as np
import cv2 as cv
import glob

# ワールド座標系におけるキャリブレーションボードの各点の座標
# (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
objp = np.zeros((6*7,3), np.float32)
objp[:,:2] = np.mgrid[0:7,0:6].T.reshape(-1,2)

# キャリブレーションで利用する座標
objpoints = [] # 3d point in real world space
imgpoints = [] # 2d points in image plane.

# cornerSubPix の閾値
criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 30, 0.001)

images = glob.glob('*.jpg')
for fname in images:
    img = cv.imread(fname)

    # グレースケールで利用
    gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)

    # キャリブレーションボード内の点の座標を取得
    ret, corners = cv.findChessboardCorners(gray, (7,6), None)

    # キャリブレーションのために結果を保存
    if ret == True:
        objpoints.append(objp)

        # 座標の精度を上げる
        corners2 = cv.cornerSubPix(gray, corners, (11,11), (-1,-1), criteria)
        imgpoints.append(corners2)

        # 確認のため画像を表示
        cv.drawChessboardCorners(img, (7,6), corners2, ret)
        cv.imshow('img', img)
        cv.waitKey(500)
cv.destroyAllWindows()
import IPython
IPython.embed()

キャリブレーションは以下の関数で行います。環境におけるカメラの位置姿勢の推定結果は rvecs 回転ベクトルtvecs です。

ret, mtx, dist, rvecs, tvecs = cv.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)

In [2]: ret
Out[2]: 0.15449477637996084

In [3]: mtx
Out[3]: 
array([[533.92783938,   0.        , 342.3194436 ],
       [  0.        , 533.91472948, 233.46358895],
       [  0.        ,   0.        ,   1.        ]])

In [4]: dist
Out[4]: 
array([[-2.94630718e-01,  1.11686190e-01,  1.55379072e-03,
        -4.36278865e-05,  4.09936920e-02]])

In [5]: rvecs[0]
Out[5]: 
array([[-0.37676179],
       [-0.17860025],
       [-3.11646085]])

In [6]: tvecs[0]
Out[6]: 
array([[ 2.80671185],
       [ 2.21295225],
       [10.95796313]])

得られたパラメータで歪み補正などを行います。

img = cv.imread('left12.jpg')
h,w = img.shape[:2]
newcameramtx, roi = cv.getOptimalNewCameraMatrix(mtx, dist, (w,h), 1, (w,h))
dst = cv.undistort(img, mtx, dist, None, newcameramtx)
x, y, w, h = roi
dst = dst[y:y+h, x:x+w]
cv.imwrite('calibresult.png', dst)

calibresult.png

Uploaded Image

Related pages