🔥
OpenCVのカメラ補正のremapを部分的に適用したい
opencvでそこそこの解像度の魚眼カメラの映像補正をしていたところ、やたら時間がかかることが分かりました。映像の中で補正して使いたい部分は一部だったので、局所的に適用する方法はあるのか、考えました。
そもそも
補正にはパラメータもといテンソルが必要です。これ自体は、チェス盤模様の被写体をつかって収集します。
例えばこちらの記事が勉強になります。
そのパラメータをつかって、元画像から補正後の画像への対応付けを示す行列(変換マップ)を計算し、opecvのremap関数で変換して補正後の画像を得ます。
この変換マップはx,y軸用に2つ存在し、こちらの解説にあるように
変換後の画像[i][j] = 元画像[変換マップy[i][j]][変換マップx[i][j]]
という対応付けの様です。
部分的な適用
上記の情報だけで単純にやろうとすると、変換後の画像のこの辺だけ欲しい、というのは簡単にできそうです。逆に元画像のこの辺だけ変換したい、というのは変換マップを逆にたどらないといけないのでちょっとコストがかかりそう。
上で参照している記事のサンプルコードに追加する形で書いてみます。変換後の画像で欲しい範囲をroi
で定義すると、
## 引用元: https://qiita.com/hiro_o_tama/items/cb544fe64ca373750aae
import numpy as np
import cv2
class roi:
x = 640
y = 200
width = 400
height = 200
img_path = '画像のファイルパス' #HDサイズぐらいを仮想定
## DIM, K, Dは求まっているものとします
DIM=画像サイズ
K=パラメータ
D=パラメータ
img = cv2.imread(img_path)
map1, map2 = cv2.fisheye.initUndistortRectifyMap(K, D, np.eye(3), K, DIM, cv2.CV_16SC2)
modified_map1 = map1[roi.y:roi.y+roi.height, roi.x:roi.x+roi.width, :]
modified_map2 = map2[roi.y:roi.y+roi.height, roi.x:roi.x+roi.width]
# 元画像のサイズは変えずに、変換マップだけ切り取るのがポイントか
squeezed_undistorted_img = cv2.remap(img, modified_map1, modified_map2, cv2.INTER_NEAREST)
print(np.shape(squeezed_undistorted_img))
# (200, 400, 3) になる
補正後の画像の一部分だけ切り取ったような出来になります。remapで計算する範囲も狭いので当然早いです。remapのソース(おそらくここら辺)読むと計算量わかるかも。
Discussion