前回書いた補正パラメータのうち"Geometric Distortion Model for Rectilinear Lenses"の部分で、FishEye以外のレンズの歪み補正はこちらを使用することになります。
今回例として取り上げるのが陣笠歪みの激しいSamyang 14mm F2.8。補正し甲斐のある一品。
lcpファイルはおそらくCRもLRもデフォルトでインストールされないが、LensProfileはAdobe Lens Profile Downloaderを使えば見つかります。
計算式の導出に関してはlensprofile_creator_cameramodel.pdfの"Geometric Distortion Model for Rectilinear Lenses"の項に詳しく書いてあるので割愛して補足的なことを。
まず、ここの計算式をややこしくしているのが複数の座標系と複数の単位が入り混じっていること。
そこで整理を兼ねてそれぞれの変数の単位(unit)と座標系の場合その原点(origin)を羅列しておきます。
unit noneとなっているのは決まった単位ではなくF=1としてスケーリングした座標系を表しており、それ以外のものはpixelかmmのいずれかの単位を持つ。
sx,sy (unit: pixels / mm)
F (unit: mm)
fx,fy (unit: pixel)
(X,Y,F) (unit: mm, origin: center)
(x,y,1) (unit: none, origin: center)
(x,y) (unit: none, origin: center)
(xd,yd) (unit: none, origin: center)
(u,v) (unit: pixel, origin: left top)
(u0,v0) (unit: pixel, origin: left top)
(0,0,F) (unit: mm, origin: center)
xd (unit: none, origin: center)
x (unit: none, origin: center)
r (unit: none, origin: center)
原点に関しては画像左上のものと画像中心のものがあり、これを混同しないようにすることが重要。
画像中心が原点になっているものは、主に歪みの量が画像中心からの距離で決まることに由来する。
これらを踏まえれば計算式も難解ではないと思います。
ここで計算に必要な補正パラメータはu0,v0,fx,fy,k1,k2,k3,k4,k5となるが、多くの場合kの高次の項は省略されている。(つまり0として扱う)
今回題材にするSamyang 14mm F2.8のlcpファイルのrdf:liはこんな感じ。
緑で囲った部分が"stCamera:PerspectiveModel"となっていればRectilinearレンズということを示している。
複数のApertureとFocus Distanceの値に対応する補正パラメータが含まれており、そのうち撮影状況に最も近いものを選ぶ。今回はF8で撮影したので、F8のときの補正パラメータを選択。
lcpの項目と補正パラメータの関係は以下の通り。上の画像の赤で囲った部分で、いくつかのパラメータは省略されている。
stCamera:FocalLengthX : fx / Dmax. If absent, default to stCamera:FocalLength in millimeters.
stCamera:FocalLengthY : fy / Dmax. If absent, default to stCamera:FocalLength in millimeters.
stCamera:ImageXCenter : ux / Dmax. If absent, default to 0.5.
stCamera:ImageYCenter : uy / Dmax. If absent, default to 0.5.
stCamera:RadialDistortParam1 : k1
stCamera:RadialDistortParam2 : k2
stCamera:RadialDistortParam3 : k3
stCamera:TangentialDistortParam1 : k4
stCamera:TangentialDistortParam2 : k5
上4つに出てくるDmaxというのは処理する画像の縦横いずれか長い方のpixel数。要はFull RAW,MRAW,SRAWなどの設定で解像度が変わるので、すべての解像度のパラメータを用意することを省くためにこういう仕様になったと思われる。計算時は処理する画像のDmaxを掛け算して使えばよい。
一ついまだに不明なのが、ドキュメントにはstCamera:FocalLengthX,Yが存在しないときにはstCamera:FocalLengthを使えと書いてあるが、前者の単位がpixelで後者はmmなので相容れないはずなのだが…おそらくカメラのセンサーサイズを考慮して算出するのか?
実際、この値が存在していないlcpは結構多い。特にサードパーティーのレンズ。
それはさておき、OpenCVのremap関数を用いてこの機能をインプリしたものを公開しました。
https://github.com/delphinus1024/rectilinear_undistort
ビルド・使用法の詳細はreadmeをご覧頂くとして、実行結果を。
補正なし。決してロココ風の湾曲をしているわけではなく、陣笠歪みというもの。実物は直線。
補正後、直線になっている。画角を最大限にするために黒い縁があるので、必要に応じてトリミングする。
参考のために、Adobe Camera Rawで補正したもの。カメラとSPI通信できないSamyangなのでEXIFに計算に必要なF値などはないはず。おそらく適当なデフォルト値を使っている?
ちなみにOpenCV本体にもカメラキャリブレーションの機能を有しているが、チェッカボードを何枚も撮影して補正する必要があるので結構手間がかかります。
該当するレンズのlcpファイルさえあればこちらの方が楽です。