OpenCVのcv2.undistort
でレンズ歪みを補正しようとすると,端っこが欠けてしまう問題がある.
import matplotlib.pyplot as plt
import cv2
img_und = cv2.undistort(img, camera_mat, dist_coef)
plt.subplot(1,2,1)
plt.imshow(img)
plt.subplot(1,2,2)
plt.imshow(img_und)
ちなみにカメラは今流行の http://panasonic.jp/wearable/a500/index.html を使った.
この画像では,チェスボード部分のレンズ歪みはとれているものの,周りの情報が失われている.どれくらいの情報が失われているのか.
import numpy as np
w,h=np.meshgrid(range(0, img.shape[1], 10), range(0, img.shape[0], 10))
pts = (np.vstack((w.flatten(), h.flatten())).T).astype('float32')
pts_new = cv2.undistortPoints(np.array([pts]), camera_mat, dist_coef, P=camera_mat)[0]
plt.scatter(pts[:,0], pts[:,1], 20, 'r', alpha=.5)
plt.scatter(pts_new[:,0], pts_new[:,1], 20, 'b', alpha=.5)
赤点が入力画像のグリッド,青点がレンズ歪みを取り除くことによって変形したグリッドを示している.cv2.undistort
ではこの青グリッドの内,赤グリッドの範囲のみが切り出されたものが出力される.これは,端っこにも重要なものが映っている場合,あまり嬉しくない.
こういう時には,cv2.initUndistortRectifyMap
とcv2.remap
を使うと良い.
new_cammat = cv2.getOptimalNewCameraMatrix(camera_mat, dist_coef, (img.shape[1], img.shape[0]), 1)[0]
map = cv2.initUndistortRectifyMap(camera_mat, dist_coef, np.eye(3), new_cammat, (img.shape[1], img.shape[0]), cv2.cv.CV_32FC1)
img_und = cv2.remap(img, map[0], map[1], cv2.cv.CV_INTER_AREA)
plt.subplot(1,2,1)
plt.imshow(img)
plt.subplot(1,2,2)
plt.imshow(img_und)
うまくいった,あと,チェスボード以外の外側部分では歪みがちゃんと補正しきれてないことも分かった.ちなみに,元画像で計測できていない部分(中央上端,中央下端)は0が埋められる.その部分が必要ない場合,
cv2.getOptimalNewCameraMatrix(camera_mat, dist_coef, (img.shape[1], img.shape[0]), 0)
とすれば良い. 詳しくは http://opencv.jp/opencv-2svn/cpp/camera_calibration_and_3d_reconstruction.html#cv-getoptimalnewcameramatrix を参照.