ImageMagick 範例 --
鏡頭校正

索引
ImageMagick 範例前言與索引
鏡頭校正簡介
非縮放約束
預先定義的參數集
從頭開始校準
範例
鍵盤範例(作者:El-Supremo)
 
校正鏡頭失真(PDF)
拍攝照片時,產生的影像實際上會因鏡頭效應和球面透視效應而失真。如果您打算使用照片,通常需要校正這些效應,而這正是本節將探討的內容。本頁面大部分內容由 Wolfgang Hugemann 貢獻。

鏡頭校正簡介

魚眼鏡頭和低成本廣角鏡頭(或更確切地說是設定為短焦距的變焦鏡頭)通常會產生明顯的桶形失真。然而,這種失真可以通過對數位照片應用合適的演算法轉換來進行大部分校正。Panorama Tools 引入並由 PTlens 使用的最常用的鏡頭校正演算法之一,ImageMagick 也提供了這種演算法,作為 桶形校正失真係應方法。在這種解決問題的方法中,失真由四個變換參數 a、b、c、d 控制,必須明智地選擇這些參數,以便校正特定鏡頭(或更確切地說是設定為特定焦距的變焦相機)產生的失真。很難通過反覆試驗找到這些參數的合適值。在下文中,我們將描述如何通過使用 Hugin 有效地確定該模型的鏡頭校正參數,Hugin 是一個用於 Panorama Tools 的免費圖形用戶介面,適用於各種作業系統。如果您不想處理鏡頭校正的細節,您可以跳過本頁面的其餘部分,只需購買 PTlens,它以合理的價格為大量數位相機和鏡頭提供複雜的鏡頭校正(通過使用其龐大的鏡頭資料庫)。如今,一些數位相機(例如尼康 P7000)甚至在其內部影像處理步驟中加入了鏡頭校正。對於使用不提供這種可能性的相機拍攝的照片,ImageMagick 使您能夠將鏡頭校正整合為更大影像處理腳本的一個步驟。以下文字是論文 校正鏡頭失真(PDF)(處理事故重建中的應用)的縮略版。這裡給出的解釋是一種更為實用的方法,重點是如何掌握適當的鏡頭校正參數。

非縮放約束

桶形失真 中所述,桶形失真由以下數學公式定義
  R = ( a * r^3  +  b * r^2  +  c * r  +  d ) * r
其中 r 是到數位照片幾何圖像中心的距離,R 是原始圖像中的等效半徑。與此類映射一樣,上述等式定義了一種“顏色查找函數”,即在哪裡查找半徑為 r 的像素的顏色。半徑 rR 通過較小圖像尺寸的一半(即通常是圖像的高度)進行歸一化,這樣對於圖像上下邊緣的中點,r = R = 1。在校正數位照片時,我們應該注意非縮放約束
  a + b + c + d = 1
顯然,對於 r = 1,它給出 R = 1。Panorama Tools 通過其他參數計算參數 d
  d = 1 - a - b - c
給我們留下三個自由模型參數,因此參數 d 通常被省略。如果省略,ImageMagick 將通過非縮放約束自動計算 d。因此,用於鏡頭校正的典型 ImageMagick 命令行看起來像
  magick input.jpg -distort barrel '0.06335 -0.18432 -0.13008' output.jpg
d 的計算留給 ImageMagick。我們在這裡討論的 Panorama Tools 的鏡頭校正方法假設鏡頭的光軸和圖像的中心是相同的,這在實踐中並不嚴格(由於製造公差)。此外,它還忽略了像八字鬍變形這樣的效應。然而,在實踐中它似乎工作得非常精確。[圖表]如曲線所示(a = 0.05,b = -0.25,c = 0.05),該關係通常在 0 到 1.5 的範圍內使用(縱橫比 3:2),穿過點 (0,0) 和 (1,1),並且對於 r > 1 必須遞減。

現成的參數集

PTlens 目前的鏡頭數據庫是該程序的“精髓”,它經過加密,只能由 PTlens 本身讀取。然而,直到 2006 年 2 月,PTlens 的數據庫都是用 XML 格式編碼的,即一種易於編輯的文本格式。PTlens 的 XML 數據庫的 2006 版本仍然可以在Hugin 的 SourceForge 網站上(合法地)獲得,並提供許多舊相機型號的數據。當 PTlens 的數據庫被加密後,Hugin 的作者嘗試建立一個免費的 XML 編碼鏡頭數據庫作為替代方案。這個數據庫被稱為LensFun,可以下載。它帶有一個完整的編程接口,但您基本上只需要 XML 文件中相機的信息。例如,曾經流行的尼康 Coolpix 995 的鏡頭校正參數可以在文件 compact-nikon.xml 中找到,該文件位於目錄 \data\db 中。可以使用文本編輯器或 XML 查看器檢查該文件

  <lens>
    <maker>Nikon</maker>
    <model>Standard</model>
    <mount>nikon995</mount>
    <cropfactor>4.843</cropfactor>
    <calibration>
      <distortion model="ptlens" focal="8.2" a="0" b="-0.019966" c="0" />
      <distortion model="ptlens" focal="10.1" a="0" b="-0.010931" c="0" />
      <distortion model="ptlens" focal="13.6" a="0" b="-0.002049" c="0" />
      <distortion model="ptlens" focal="18.4" a="0" b="0.003845" c="0" />
      <distortion model="ptlens" focal="23.4" a="0" b="0.006884" c="0" />
      <distortion model="ptlens" focal="28.3" a="0" b="0.008666" c="0" />
      <distortion model="ptlens" focal="31" a="0" b="0.009298" c="0" />
    </calibration>
  </lens>
從相機的技術數據表中可以看出,尼康 Coolpix 995 的變焦範圍為 8.2 – 31.0 毫米,對應於 35 毫米膠片相機的 38 – 152 毫米。這給出了 152 / 31 = 4.90 的裁剪係數,大致對應於 XML 文件中給出的 4.843。提供了六個焦距的桶形畸變校正係數,即 8.2 毫米、10.1 毫米、13.6 毫米、18.4 毫米、23.4 毫米、28.3 毫米和 31.0 毫米。對於該鏡頭,係數 ac 設置為零,即畸變僅由二階項 b 描述。請注意,許多鏡頭的 ac 參數也會有值,並且這些值也應該以類似的方式進行插值。如果我們有一張用設置為最短焦距的尼康 Coolpix 995 拍攝的照片 DSCN0001.jpg,則可以使用 ImageMagick 通過以下方式校正該照片

   magick DSCN0001.jpg -distort barrel '0.0 -0.019966 0.0' DSCN0001_pt.jpg
(檔案副檔名 _pt 是 PTlens 用來標記已校正影像的記號。)針對提供的六個焦距,校正係數 b 可以從 XML 檔案中讀取。對於其他焦距,可以透過在兩個相鄰焦距之間內插來決定適當的值。或者,b 對焦距 f 的依賴性可以透過以下多項式來近似
  b = 0.000005142 * f^3 - 0.000380839 * f^2 + 0.009606325 * f - 0.075316854
因此,第一步是使用從 EXIF 資訊中讀取的焦距來計算鏡頭校正參數 b,然後在第二步中,使用此值作為 b 參數來執行鏡頭校正(即桶狀變形)。Windows 部分顯示了一個 VBScript 範例,其中使用了上述方程式,並透過 magick identify 從 Nikon Coolpix 995 照片中提取焦距。

從頭開始校正

基本方法

在確定鏡頭參數時,所有程式都依賴於相同的範例:理想的透視映射應該將真實世界的直線映射到影像中的直線。因此,如果已知一組真實世界點 P0、P1、...、Pn 位於一條直線上,則它們的影像 p0、p1、...、pn 也必須落在同一條直線上。任何偏離此規則的情況都必須歸因於鏡頭變形。我們需要兩個點來確定定義一條直線的兩個參數(例如斜率和 y 軸上的交點)。提供的每個額外點將提供另一個方程式來確定鏡頭校正參數。因此,如果我們的函數方法只有一個自由參數 b(如上所述的 Nikon Coolpix 995),我們必須至少提供真實世界直線上的三個點及其影像,才能確定所需的鏡頭校正參數 b。更具體地說:變形模型僅使用參數 b,也就是說,校正後影像的坐標 X1, Y1 可以透過以下公式從數位照片的坐標計算得出
r = s * sqrt(x1^2 + y1^2)
X1 = [(1-b) + b r^2] * x1
Y1 = [(1-b) + b r^2] * y1
Y1 = k1 * X1 + k2
這會為同一條直線上提供的每個點產生一個方程式
[(1-b) + b r^2] * y1 = k1 * [(1-b) + b r^2] * x1 + k2

with: r = s * sqrt(x1^2 + y1^2)
因此,三個真實世界點及其對應的影像點足以確定描述直線和鏡頭變形 k1、k2、b 的參數。實際上,真實世界點的坐標很少是已知的,因此需要三個以上的點來確定所需的參數。大多數校正軟體使用直線的矩形網格(通常是棋盤格)來生成一組方程式,然後透過非線性最小平方法擬合來計算映射參數。有些程式會自行生成一組控制點,通常使用預先定義的模板;其他程式則需要使用者從校正影像中選擇控制點。

使用 Hugin 確定鏡頭參數集

接下來,我們將演示如何透過使用 Hugin 來確定一組鏡頭校正參數。Hugin 的網站上也有一個現成的「簡易鏡頭校正教學」,但在撰寫本文時(2014 年),它似乎過於簡單,無法提供可靠的參數,無法在日後用於各種校正。首先,您必須取得合適的測試圖案。基本上,一個包含大約 10 × 7 個正方形的棋盤格圖案,印在 ISO 216 A3 或類似的紙張上就可以了,而且經常被使用。然而,低成本的變焦鏡頭(所謂的 變焦鏡頭)在校正過程中應設定為無限遠對焦,因為它們的實際焦距可能與嵌入在 EXIF 中的近距離對焦焦距有很大差異。對於定焦鏡頭,您也可以使用棋盤格測試圖案,這在校正魚眼鏡頭時尤其推薦使用,因為可能難以找到一個足夠大的真實世界物體來覆蓋其視野。因此,特別是在校正變焦鏡頭/變焦相機時,您應該拍攝現代建築物的照片,如 PTlens 網站 上所建議的那樣。請遵循該網站上提供的說明。照片可能會顯示透視變形
[IM Output]
透視
[IM Output]
非透視
啟動 Hugin,點擊第一個標籤上的「新增影像...」按鈕,並打開校準影像。(請參閱 hugin.sourceforge.net 以取得 Hugin 介面的螢幕截圖。)在標籤按鈕處,將「最佳化」設定為「自訂參數」(這將會新增一個名為「最佳化器」的標籤,否則您將不會看到)。在「拼接器」標籤上,將「投影」設定為「直線」。在「控制點」標籤上,您會看到您的測試照片出現兩次,您可以透過在兩個版本的照片中選取這些點群組,來定義位於同一條直線上的點集。

但請勿在兩個版本中選取完全相同的點,以免這些點在兩張影像中完全相同,因為這會誤導最佳化器採取簡單的方式,並確定一對一對應的參數。相反地,您應該在兩個版本的影像中選擇同一條直線上的不同點。為了測試目的,您可以定義幾個這樣的點集,最好靠近影像邊緣,那裡的直線扭曲較大。您會發現,在 Hugin 中定義這樣的點集是一件相當繁瑣的事情(這可能是 lensfun 資料庫如此之小的原因之一)。

然後切換到「最佳化器」標籤,並透過按住 Ctrl 鍵並用滑鼠左鍵點擊來選擇要最佳化的參數。(請參閱標籤頂部的提示。)我建議最佳化「Yaw(y)」、「Pitch (p)」和鏡頭參數「a」、「b」和「c」。水平視角「Hfov (f)」是根據測試影像中的 EXIF 資料計算出來的,使用 FocalLengthIn35mmFilm 項目 f
 Hfov = 2 × arctan (18 mm / f) 
其中 18 公釐是 35 公釐底片寬度的一半(其尺寸為 36 × 24 公釐)。然後按下「立即最佳化!」按鈕。對於廣角鏡頭,產生的參數「a」、「b」和「c」應低於 0.01,對於魚眼鏡頭,則應低於 0.1。如果數值較大,則表示最佳化可能失敗。如果是這樣,請檢查「控制點」標籤上的點集:控制點的順序可能錯誤,或者未正確與其對應的線條關聯。最佳化器似乎也對提供的起始集(數學上稱為起始向量)很敏感,也就是說,將所有參數設定為零可能是錯誤的選擇。您可以透過雙擊「最佳化器」標籤上的數值,或勾選標籤頁右下角的「在最佳化之前編輯腳本」核取方塊,來編輯起始向量。這將會在最佳化之前顯示一個文字方塊,讓您編輯 Hugin 專案檔案的相應部分。在重新啟動最佳化器之前,將起始向量 a、b、c 設定回 a0.0 b0.0 c0.0(或其他合適的數值)。經驗顯示,將「a」設定為某個正數值可能會有幫助,特別是對於魚眼鏡頭而言。對於配備定焦鏡頭的相機,只需進行一次校準即可。對於配備變焦鏡頭的相機,則必須透過校準大約五個不同的焦距,來涵蓋整個焦距範圍。在確定了這樣的參數集之後,請透過以下方式在 ImageMagick 中進行測試:

          

  magick calibration_image.jpg -distort barrel 'a b c' flat.jpg
將數值 a b c 替換為剛才確定的數值。輸出影像中的線條應該完全筆直,否則表示最佳化失敗,需要使用不同的起始向量或修正後的控制點集重新執行最佳化。

定義點集

若要進行嚴謹的校準,建議手動編輯 Hugin 專案檔案,並透過其他方式定義點座標和點集。專案檔案是一個副檔名为 PTO 的純文字檔案,您可以使用簡單的文字編輯器開啟它,並提供一個點列表。在其 # control points 部分中的一行看起來像這樣
  c n0 N0 x175.0 y87.8 X1533.3 Y62.6 t3
其中 x, y 是來源影像(標籤左側的影像)中的像素坐標,而 X, Y 是目標影像(標籤右側的影像)中的像素坐標 - 在這個特殊情況下,它們實際上是同一影像的兩個版本。(通常這些會是全景圖中並排的兩個不同影像。)開頭的 c n0 N0 是標準代碼,結尾的 t3 是關聯直線的編號,從索引 3 開始。從上面的例子可以看出,像素坐標可能會有小數部分。當然,x, yX, Y 必須位於同一條直線上。但是,它們不能相同,因為在這種情況下,優化器將無法工作(見上文)。保證這一點的最簡單方法是在兩個影像中使用相同的點,但目標坐標的順序相反,例如在左側影像中使用 p1、p2、p3、p4,在右側影像中使用 P4、P3、P2、P1。使用點選工具確定來源影像中的像素坐標。您可以使用任何可以儲存此類數據的影像檢視器來執行此操作。一個平台獨立的工具是 Fiji。我(在 Windows 下工作)使用 WinMorph 中的折線來執行此操作。選擇點時,您應該遵循預先定義的策略,例如在每條(或多或少)水平線上選擇相同數量的點,從左到右(即在整個影像中遵循鋸齒線,就像電視映像管中的陰極射線)。這樣的策略將簡化目標點坐標的排序。然後,可以手動或藉助軟體工具建立定義來源和目標點坐標的文字檔案行。(我使用 Excel VBA 子常式來執行此任務。)準備就緒後,將點列表複製到 PTO 檔案的相應部分,儲存並使用 Hugin 重新開啟它。結果應如下所示
[IM Output]
Hugin 中的控制點網格
ZIP檔案olympus_c2500l.zip中提供了一個包含校準圖像和相應Hugin專案的現成範例。

從相機建立的縮略圖進行反向工程

在幾種情況下,我們已經有一對圖像,一個是桶狀變形的,另一個是已經校正的。此校正可能是使用其他鏡頭校正軟體執行的,該軟體沒有告訴我們校正參數。此外,許多現代相機(2019年)都提供對JPEG圖像進行內部鏡頭校正的功能。但是,此功能通常不適用於RAW圖像。(嗯,它是原始的。)儘管如此,RAW圖像包含一個JPEG預覽,相機已經對其應用校正。ImageMagick可以透過使用dcraw讀取RAW圖像。因此,可以將原始圖像轉換為沒有鏡頭校正的JPEG,並將結果與內部校正的JPEG縮略圖進行比較。在這種圖像對的情況下,可以直接計算校正參數。透過在兩個圖像中選擇對應的點對,我們可以直接建立rR之間的關係。
[RAW 圖像]
原始圖像(桶狀變形) [校正後的圖像]
校正後的縮略圖(用於反向工程)
如上例所示,我們可以自由選擇要選擇的點對;這些點對既不需要遵循直線,也不需要位於幾何圖案上。我們只需要在表格中填入rR的對應值,然後計算迴歸曲線,例如透過
試算表圖表。
[Calabration]
校準點
[Regression]
迴歸(縮放)
因此,ImageMagick命令列為

  magick barrel.jpg -distort barrel '0.0099 -0.0678 0.0014 1.0511' flat.jpg
您也可以將相同的命令直接應用於DNG相機格式圖像「barrel.dng」。

鏡頭校正範例

露營車

[IM Output]
原始圖像
[IM Output]
校正後
[IM Output]
差異
左側的露營車原始照片必須在黃昏時分從相當近的距離拍攝,因為攝影師背後有一個陡峭的斜坡,空間有限。(光線不足導致照片呈現藍色調,這是後期處理過程中嚴重增亮的結果。)原始照片顯示出明顯的桶狀變形,尤其是在圖像頂部附近的水平條紋和建築物的後角處。用於拍攝此照片的尼康Coolpix 995可以在PTlens的資料庫中找到,因此可以輕鬆校正變形,如中間所示。右側的圖像顯示了兩張照片灰階版本之間的差異,透過兩者相減、取反以及極端裁剪和伽瑪校正來計算。同樣,校正的效果最好透過頂部的水平條紋來說明。白色圓圈(表示零差異)是由於非縮放限制造成的:直徑等於圖像較小尺寸的圓上的點保持不變。

GoPro 展平

GoPro相機鏡頭會產生明顯的桶狀變形,這似乎是其品牌的一部分。例如,GoPro Hero 3+銀色版配備了一個焦距為2.77毫米的魚眼鏡頭,如果使用整個感光區域,則相當於35毫米膠片中16毫米的焦距。GoPro Hero 3+有三種照片模式
  • 1000萬像素 = 3680 × 2760像素廣角(35毫米膠片中為16毫米)
  • 700萬像素 = 3072 × 2304像素廣角(35毫米膠片中為16毫米)
  • 500萬像素 = 2624 × 1968像素中焦(35毫米膠片中為23毫米)
GoPro Hero 3+ 配備了 1/2.3 吋感光元件,其裁切係數為 5.64。(這使得 35 毫米底片上的等效焦距僅為 15.62 毫米,而 EXIF 資訊提供的 16 毫米可能是由於四捨五入造成的。)前兩種模式似乎使用了整個感光區域;較低的解析度顯然是透過子採樣實現的。因此,失真係數是相同的,這在實踐中可以得到證明。500 萬像素模式顯然只使用了感光區域的一部分,因為 3680 / 2624 × 16 ≈ 23。鏡頭參數可以確定為
  • 廣角
    • a = 0.06335
    • b = -0.18432
    • c = -0.13009
  • 中焦
    • a = 0.01359
    • b = -0.06034
    • c = -0.10618
理論上,第二種模式的參數可以從第一種模式推導出來,因為半徑 riRi 由比例因子 κ = 3680 / 2624 = 1.402 耦合,這導致
  • a2 = a1 / κ³
  • b2 = b1 / κ²
  • c2 = c1 / κ
以上參數是透過獨立優化得到的,與這些理論值相差不大。相應地,各種影片模式的參數可以透過優化或從該模式使用的感光區域部分推導出來。對於影片,無法從 EXIF 資料中得出水平視角。它可以根據影片本身使用的感光區域計算得出(透過在受控條件下拍攝素材),或者與其他參數一起估計,即在優化中作為自由參數保留。HD 影片(1920 × 1080)的參數為
  • a = 0.030530
  • b = -0.124312
  • c = -0.038543
這些參數可以用於使用 ImageMagick 進行逐幀校正。或者,它們也可以用於透過 AVIsynth 外掛 DeBarrel「展平」整個影片,該外掛也使用 Panorama Tools 鏡頭校正模型。

兩把鍵盤作者:el_supremo

我拍攝的兩把鍵盤的照片有非常明顯的桶形失真,因為它是在 17 毫米的焦距下拍攝的。
[IM Output]
這種失真可以使用例如 Canon 的 Digital Photo Professional 軟體進行校正(我有一台 Canon 50D 相機)。其他單眼相機製造商通常會提供軟體來對他們的鏡頭進行這種校正,但我想看看上面的例子在這張照片上的效果如何。第一步是訪問 LensFun 網站 並下載最新版本的相機資料庫。解壓縮套件(winzip 可以在 Windows 中解壓縮 .tar.gz 文件),然後在「lensfun/data/db」目錄中查找與您的相機製造商對應的檔案。在我的例子中,我查看了「slr-canon.xml」,它可以使用任何文字編輯器進行編輯。現在我找到了我正在使用的特定鏡頭的資訊,在我的例子中是「EF-S 17-85mm」。該鏡頭的資訊如下所示
<lens>
  <maker>Canon</maker>
  <model>Canon EF-S 17-85mm f/4-5.6 IS USM</model>
  <mount>Canon EF-S</mount>
  <cropfactor>1.6</cropfactor>
  <calibration>
    <distortion model="ptlens" focal="17" a="0.021181" b="-0.055581" c="0" />
    <distortion model="ptlens" focal="20" a="0.019344" b="-0.043786" c="0" />
    <distortion model="ptlens" focal="22" a="0.015491" b="-0.026682" c="0" />
    <distortion model="ptlens" focal="28" a="0.008084" b="-0.007472" c="0" />
    <distortion model="ptlens" focal="30" a="0.005522" b="-0.001763" c="0" />
    <distortion model="ptlens" focal="35" a="0.003149" b="0.002207" c="0" />
    <distortion model="ptlens" focal="44" a="0" b="0.008269" c="0" />
    <distortion model="ptlens" focal="53" a="0" b="0.008792" c="0" />
    <distortion model="ptlens" focal="61" a="0" b="0.00738" c="0" />
    <distortion model="ptlens" focal="72" a="0" b="0.006226" c="0" />
    <distortion model="ptlens" focal="78" a="0" b="0.007095" c="0" />
    <distortion model="ptlens" focal="85" a="0" b="0.007288" c="0" />
  </calibration>
</lens>
校準條目給出了從 17 毫米到 85 毫米焦距範圍內的失真值。如果我需要的焦距介於這兩個值之間,我可以選擇最接近的值,或者我可以對這些值進行插值。由於我正在校正的照片是在 17 毫米焦距下拍攝的,因此我需要校準資訊第一行的資訊。這給了我這些值: a="0.021181"  b="-0.055581"  c="0" 這些是用於校正鏡頭失真的三個參數。但是,對於某些舊版本的 IM,桶形失真校正需要第四個參數 d。幸運的是,可以使用這個簡單的公式從其他三個參數輕鬆計算出 d 的值: d = 1-a-b-c  這意味著: d="1.0344"
如果沒有提供「d」作為變形參數,IM 會自動計算出「d」的值,但一些舊版本的 IM 不會這樣做。
這使得實際的 桶狀變形 能夠校正鏡頭變形...

    magick keyboards.jpg \
          -distort barrel "0.021181 -0.055581 0" \
          keyboards_ptlens.jpg
[IM Output]
當然,在您完全完成影像處理之前,您不應該儲存為 JPEG 格式,因為 JPEG 會進行失真壓縮。
在原始照片中,變形在譜架底部和上排琴鍵處尤其明顯。這些變形在輸出照片中幾乎完全消失了。將此結果與 Canon 軟體獲得的結果進行視覺比較,顯示出基本相同的結果。El-Supremo