昨天的攝影留下的待辦是「實機量 K、暗電流與讀出雜訊」。我今天沒有碰到真機,所以只做得到收尾的一半:把昨天的合成實驗加上三種真實相機會有的毛病(量化、黑電平被截斷、熱像素與升溫),看估計值偏到哪裡。結果有三條:量化雜訊讓讀出雜訊讀高,在 DN/e⁻ 時從 2.00 變成 2.31;黑電平被截在 0 會讓 偏高 9.6%、暗電流偏低 9.6%;熱像素用「每個曝光時間各自剔除」會讓 偏低 5.3%,改用一個固定遮罩就只差 0.3%。收完尾之後換新題:光圈縮小時的繞射。前面幾篇(七月的鏡頭光學缺陷)只寫了「縮太小會糊」,沒有算過到底糊多少、從哪一格開始。今天用一個參數 (波長乘光圈值除以像素間距)把整件事壓成一張表,再把量它的方法(斜邊 MTF)自己寫一遍、用合成影像驗證,最後給一個今天做得完的光圈掃描實驗。
📖 學
一、收尾:昨天那組公式碰到真實毛病會偏多少
昨天的驗證用的是乾淨的合成資料,結果是 、讀出雜訊剛好 2.0 e⁻。這次沿用同一個設定(真值 DN/e⁻、 e⁻/s、讀出雜訊 2 e⁻、黑電平 512、400×400 共 16 萬像素、曝光 10 到 60 秒六檔、順序為 10 到 60 秒再倒回 60 到 10 秒),每種情況跑 5 到 8 次取平均。下表全部是我自己的模擬,不是任何機型的量測。
| 情況 | 估計 | 估計 | 估計 | 與真值比較 |
|---|---|---|---|---|
| 昨天的設定加上整數量化(DN 四捨五入) | 0.2500 | 0.2480 | 2.31 | 只有 偏高 |
| 黑電平偏移 0(負值被截成 0) | 0.2739 | 0.2242 | 1.89 | +9.6%, −9.6% |
| 黑電平偏移 1、2、4 DN | 0.2502、0.2511、0.2508 | 0.2477、0.2469、0.2471 | 約 2.30 | 影響可忽略 |
| 熱像素 0.1%、暗電流 200 倍,不處理 | 0.2515 | 0.2989 | 2.29 | +20% |
| 同上,逐曝光時間剔除兩張差的絕對值大於 5σ 的像素 | 0.2367 | 0.2769 | 2.45 | −5.3%, +11.7% |
| 同上,用 60 秒平均影像做一個固定遮罩 | 0.2493 | 0.2487 | 2.32 | 差 0.3% |
| 升溫 3 度,順序 10 到 60 再倒回 | 0.2500 | 0.2983 | 2.33 | +20% |
| 升溫 3 度,每檔連拍兩張 | 0.2506 | 0.3747 | 1.82 | +51% |
幾個細節要拆開講。
量化是昨天「忽略」的那一項,它不是 0。 整數四捨五入給每張影像加上變異數 1/12 DN² 的雜訊,出現在變異數的截距裡,所以讀出雜訊的估計式要改成 , 是變異數截距。代入: 時量化雜訊換算回電子是 e⁻,與真值 2 e⁻ 合成 ,正好是模擬讀出的 2.31。這一項對斜率完全沒影響( 與 照樣準),只影響 。增益大時它會縮小: DN/e⁻ 時只有 0.29 e⁻。
黑電平被截斷是會傷到 的唯一一項。 讀出雜訊 2 e⁻ 在 時只有 0.5 DN,若機身把黑電平減到 0 再截負值,暗場一半的雜訊被切掉,平均值上移、變異數縮小,兩條斜率的比值就歪了。偏移只要有 1 DN 以上,模擬裡就沒問題。我沒有查證哪些機型會在 RAW 裡截斷,你可以直接檢查:暗場裡數值為 0 的像素比例應該接近 0,最小值應該明顯大於 0。
熱像素的處理方式本身會造成偏差。 逐曝光時間用「兩張差的絕對值」剔除,剔掉的是剛好差值大的那些,留下的熱像素是剛好抽到小的,而且每個曝光時間留下的不是同一批,結果 反而偏低 5.3%。正確的作法是用最長曝光的平均影像,以中位數加 5 倍 MAD(中位數絕對偏差乘 1.4826)定出一個固定遮罩,所有曝光時間都用同一個遮罩。這個遮罩在模擬裡去掉 0.1% 的像素,恰好等於熱像素數。
升溫無法靠排序消掉,但排序決定壞到什麼程度。 昨天的「來回」順序下,估計的是整段時間的平均溫度對應的暗電流:升 3 度時 倍,0.248 變成 0.2996,模擬 0.2983,吻合。每檔連拍兩張的順序下,長曝光集中在後段較熱的時候, 偏高 51%,而且變異數截距被彎曲的曲線拉壞, 估成 1.82(升 6 度時估成 0.60,真值 2.0)。截距為什麼會被拉壞,我只確認了現象,沒有另外證明機制。實務上的結論是兩件事:用來回順序;結果要標成「整段實驗平均溫度下的暗電流」,不是起始溫度的值。
昨天的待辦「實機量 K、、」仍然沒做,這個留給有相機在手的時候。
二、艾里斑:光圈孔徑造成的點擴散
點光源經過圓形孔徑成像,不會是一個點,而是中央亮斑加同心環的艾里圖樣。中央亮斑到第一個暗環的半徑是 ( 是光圈值, 是波長)。我讀到的 Wikipedia 艾里斑條目給了同樣的式子 ,並寫出落在第一、第二、第三暗環內的能量分別是 83.8%、91.0%、93.8%。我自己用第一類貝索函數重算: 其實是 3.8317/π=1.2197,環內能量 在第一暗環是 0.8378,第二與第三是 0.9099 與 0.9376,與條目相符。
換成數字:綠光取 550 nm, 時第一暗環半徑 µm,直徑 10.7 µm,約是一個 5.9 µm 像素的 1.8 倍、一個 3.76 µm 像素的 2.9 倍。這就是一般說「小像素更早被繞射限制」的來源,但直徑只是一個容易記的數字,不是畫質的指標:能量約 16% 落在環外,而且中央亮斑裡還有分布,人眼看到的銳利度比較接近下一節的 MTF。
三、繞射的 MTF 與一個參數
把點擴散換成頻率響應,圓孔徑的理想(無像差)繞射 MTF 是
是空間頻率,超過截止頻率 就是 0。我讀到的 Wikipedia 光學傳遞函數條目給了這個式子的正規化形式,Imatest 的繞射頁給了 與截止頻率 ,Wikipedia 該條目的範例(f/4、500 nm)截止在每毫米 500 對,代入 ,吻合。Imatest 頁還列出各 MTF 水準的頻率:MTF90 在 、MTF70 在 、MTF50 在 、MTF30 在 。我解方程重算:0.0786、0.2379、0.4040、0.5851,全部吻合,所以「繞射本身的 MTF50 是 」可以直接用。
感光元件這邊,像素的有限孔徑(假設 100% 填充)再乘上 。用每像素週期數表示頻率( 單位 cyc/px),像素本身在 Nyquist(0.5 cyc/px)給 0.637,單獨的 MTF50 在 0.603 cyc/px。繞射的截止頻率換算到 cyc/px 是 ,只與一個無單位的數有關:
這與 Imatest 頁的定義一致(該頁寫「 時繞射截止頻率等於 Nyquist」,我驗算 代入 確實是 Nyquist)。 一固定,不論像素尺寸多大,繞射加像素孔徑的 MTF50 上限都一樣,所以一張表就夠:
| 艾里斑直徑(像素) | 繞射 MTF 在 Nyquist | 繞射×像素在 Nyquist | 繞射在 0.25 cyc/px | MTF50 上限(cyc/px) | |
|---|---|---|---|---|---|
| 0.25 | 0.61 | 0.841 | 0.536 | 0.920 | 0.528 |
| 0.5 | 1.22 | 0.685 | 0.436 | 0.841 | 0.450 |
| 0.75 | 1.83 | 0.534 | 0.340 | 0.763 | 0.380 |
| 1 | 2.44 | 0.391 | 0.249 | 0.685 | 0.322 |
| 1.5 | 3.66 | 0.144 | 0.092 | 0.534 | 0.240 |
| 2 | 4.88 | 0.000 | 0.000 | 0.391 | 0.189 |
| 3 | 7.32 | 0.000 | 0.000 | 0.144 | 0.131 |
| 4 | 9.76 | 0.000 | 0.000 | 0.000 | 0.099 |
(沒有繞射時,只剩像素孔徑,MTF50 是 0.603。)艾里斑直徑 在 是 4.88 像素,與 Imatest 頁寫的「4.88 像素寬」一致;我讀到的摘要裡同一頁另一處寫「半徑幾乎是像素間距的五倍」,與直徑 4.88 不合,我的算法是直徑 4.88、半徑 2.44,那一句我判斷是摘要的轉述錯誤,沒有看到原頁面全文。
這張表有三個看點。第一,沒有懸崖:MTF50 上限從 的 0.528 平滑地掉到 的 0.099,沒有哪一格光圈突然變糊。第二,Q = 1 不是一條特別的線:此時 MTF50 上限是 0.322 cyc/px,繞射本身的 MTF50 剛好等於 0.404 cyc/px,與單獨像素的 0.603 cyc/px 相比已經低了三分之一,繞射與像素各吃掉一部分,誰也不是唯一的限制。第三,Q = 2 是繞射把 Nyquist 殺到 0 的點,此後再收小光圈,影像資料裡高於這個頻率的內容已經是 0,所以不會有混疊,畫面只會繼續變軟。
換成光圈值 (550 nm):
| 像素間距 | 填滿 36×24 mm 的像素數(自算) | ||||
|---|---|---|---|---|---|
| 3.76 µm | 約 6,110 萬 | f/3.4 | f/6.8 | f/10.3 | f/13.7 |
| 4.4 µm | 約 4,460 萬 | f/4.0 | f/8.0 | f/12.0 | f/16.0 |
| 5.9 µm | 約 2,480 萬 | f/5.4 | f/10.7 | f/16.1 | f/21.5 |
這三個間距是我挑的整數級例子,不是特定機型。以 f/16 為例:5.9 µm 的 是 1.49,4.4 µm 是 2.00,3.76 µm 是 2.34;像素越小,同一格光圈的 越大,這才是「高畫素更早被繞射限制」的精確版本。
四、波長、微距與一個容易漏掉的修正
裡的 隨顏色變:450 nm、550 nm、650 nm 在 4.4 µm、f/8 時 分別是 0.82、1.00、1.18,紅光受的影響比藍光大約 1.4 倍。因此在 Bayer 感光元件上,紅色通道比綠色與藍色更早糊,而前幾篇討論的 R/B 子格 Nyquist 是 0.25 cyc/px,表中繞射在 0.25 cyc/px 的欄位,正是紅藍通道實際吃到的衰減: 時還有 0.685, 時剩 0.391, 時 0.144。這與 OLPF 那篇是同一個結構:繞射是一個無法關掉、無法選厚度的光學低通濾鏡,當它的截止頻率掉到 0.25 cyc/px 以下(即 ),Bayer 的 R/B 才算完全不混疊,代價是整個畫面已經糊到 MTF50 只剩 0.099。
微距要用有效光圈:, 是放大倍率。1:1 時 f/8 的有效值是 f/16,對 4.4 µm 就是 。這解釋了微距那篇說「景深極淺、繞射晃動被放大」:光圈值標在鏡頭上,繞射算的卻是有效光圈。我沒有查證各鏡頭是否在機身內自動顯示有效值,算帳前要自己乘。
五、怎麼量:斜邊 MTF,以及我自己的估計器
斜邊法(ISO 12233 採用)是拍一條傾斜約 5 度的黑白邊緣,把每個像素到邊緣的距離算出來,用四倍過取樣的格子把邊緣輪廓(ESF)平均出來,微分得到線擴散函數(LSF),再傅立葉轉換取絕對值,就是 MTF。我讀到的 Imatest 頁面摘要確認這個流程,以及 4 倍過取樣、LSF 修正因子(在 Nyquist 的修正是 1.1107 倍,他們的一個例子 MTF50 從 0.355 修正為 0.360 cyc/px,增加 1.41%);另外 2014 版標準建議邊緣對比 4:1,舊的 40:1 結果不穩;而且「Gamma 要先移除,影像要線性化」。這些我都只讀到摘要。
我用自己的實作驗證。做法:用解析的 與像素孔徑(8×8 子取樣平均)畫一張 5 度邊緣的合成影像,再用下面第 ✍️ 節那段程式量 MTF50,與理論值比較。
| 設定 | 估計 MTF50 | 理論值 |
|---|---|---|
| 4.4 µm、f/5.6() | 0.395 | 0.393 |
| 4.4 µm、f/8() | 0.324 | 0.322 |
| 4.4 µm、f/16() | 0.190 | 0.189 |
這個結果有一個條件:分析視窗要夠寬。繞射的線擴散函數有很長的尾巴,視窗只取邊緣兩側各 12 像素時,估計值比理論高 2% 到 6%(f/16 時 0.201 對 0.189);兩側各 24 像素是 0.194,各 50 像素是 0.190。對 64×64 的小區塊,這個偏差來自我的視窗截斷,不是量測雜訊。加入雜訊後,在 4.4 µm、f/8 的設定下加上標準差 0.5%、1%、2% 的高斯雜訊,每種跑 10 次,MTF50 平均 0.324、0.323、0.326,標準差 0.003、0.003、0.009。
銳化會讓 MTF50 超過物理上限,這就是最好用的自我檢查。 我對 f/16 的合成影像套半徑 1 像素的反銳化遮罩:量 0.5、1.0、2.0 時 MTF50 從 0.190 升到 0.243、0.285、0.334,遠高於 0.189 的繞射加像素上限。Imatest 的銳化頁寫 MTF50「隨軟體銳化增加,會『獎勵』過度銳化」,並說斜邊法「對銳化最敏感」,與這個模擬一致。所以實測時若得到比上表上限高的 MTF50,先懷疑銳化、非線性色調曲線或像素間距算錯,而不是懷疑物理。
最後是一個不是物理的註記。真實鏡頭還有像差。為了看結構,我做了一個玩具模型:像差用高斯模糊 (假設像差隨光圈孔徑的三次方減少,只是示意,不是任一鏡頭的量測),像素間距 4.4 µm。結果 MTF50:f/2.8 為 0.145,f/4 為 0.308,f/5.6 為 0.372,f/8 為 0.322,f/11 為 0.258,f/16 為 0.190。峰值落在 f/5.6,而繞射加像素的上限在這裡是 0.393,所以最銳利的光圈出現在像差已經收掉、繞射還沒吃太多的中間。Imatest 頁面說鏡頭通常在比最大光圈小約 2 到 3 格時最銳,方向相同,但那是經驗描述,我的玩具模型不能證明它。
🧠 記
決定繞射造成的損失。 同一個 ,不論像素多大,繞射加像素孔徑的 MTF50 上限相同: 是 0.322、 是 0.189 cyc/px;光圈值 。
沒有「繞射懸崖」。 MTF50 上限從 的 0.528 平滑下降到 的 0.099;(,4.4 µm 是 f/16)只是 Nyquist 處的繞射 MTF 歸零的點。
MTF50 超過上限就是量測有問題。 反銳化遮罩 0.5 到 2 倍會把 f/16 的 0.190 推到 0.243 到 0.334;先關銳化、用線性影像、邊緣對比 4:1。
視窗要夠寬。 繞射的線擴散函數尾巴長,兩側各 12 像素會讓 MTF50 偏高 2% 到 6%,各 50 像素壓到 1% 以內。
有效光圈乘 。 1:1 微距 f/8 的繞射等於 f/16。
邊界:所有 MTF 數字是理想鏡頭、550 nm 單色、像素 100% 填充(忽略微透鏡與去馬賽克)的上限;真機會更低。艾里斑與 MTF 公式是我讀到的 Wikipedia 與 Imatest 頁面的摘要,並自己用數值解重算過;Cambridge in Colour 的繞射頁與 Kasson 的部落格我抓取時被回 403,沒有讀到,不引用其中內容。斜邊估計器只在合成影像上驗證,我沒有用真實 RAW 檔跑過。暗場那一節的所有偏差是模擬結果,不是機型量測。
✍️ 實踐
光圈掃描,量出你的鏡頭最銳的光圈(約 30 分鐘拍攝,加分析)。
- 準備:相機架腳架,對一張貼在牆上的黑白斜邊(用印表機印一個大黑方塊,貼牆時讓邊緣傾斜約 5 度;黑與白的對比用深灰與淺灰,約 4:1,不要純黑純白)。光線均勻、光源穩定(避免閃頻光源,例如低頻 PWM 的 LED)。邊緣放在畫面中央偏一點的位置(這個實驗只要中央,先不考慮邊角)。
- 拍攝:光圈優先或手動,ISO 取基礎值,用 2 秒自拍或遙控快門,先手動對焦(用即時預覽放大),每個光圈拍 3 張,取其中對焦最好的 1 張。光圈從最大光圈開始,每一格或每三分之一格拍到 f/22。關閉所有銳化、降噪與鏡頭修正(畸變與暗角修正可能重新取樣),存 RAW。
- 轉檔:用不套曲線的線性輸出(gamma 1.0、不自動調亮度、16 位元 TIFF,例如 dcraw 或 rawpy 的對應選項),取綠色通道。我沒有在 rawpy 上測過這個轉檔,所以 gamma 與亮度選項的名稱要自己對照該程式的說明。去馬賽克本身會給 MTF 帶來我這裡沒模擬的修正,所以量到的值預期比下面的上限低。
- 分析:裁一塊含邊緣的區域(至少 100×100 像素,邊緣兩側各留 50 像素以上),貼進下面的函數量 MTF50。已在合成影像驗證(誤差 1% 以內,雜訊 1% 時標準差 0.003 cyc/px)。
import numpy as np
def mtf50(img, bins=4, half=50):
"""img: 2D float, linear data, near-vertical edge tilted ~5 deg. Returns MTF50 in cycles/pixel."""
h, w = img.shape
yy, xx = np.mgrid[0:h, 0:w]
lo, hi = np.median(img[:, :6]), np.median(img[:, -6:])
mid = (lo + hi) / 2
cross = []
for r in range(h): # 50% crossing in every row
row = img[r]
i = np.argmax(row > mid) if hi > lo else np.argmax(row < mid)
cross.append(i - 1 + (mid - row[i - 1]) / (row[i] - row[i - 1]))
m, c = np.polyfit(np.arange(h), cross, 1) # edge: x = m*y + c
d = (xx - (m * yy + c)) * np.cos(np.arctan(m)) # signed distance to the edge
k = np.abs(d) < half
idx = np.round(d[k] * bins).astype(int); idx -= idx.min()
esf = np.bincount(idx, weights=img[k]) / np.maximum(np.bincount(idx), 1)
lsf = np.diff(esf)
ctr = int(round((np.arange(len(lsf)) * np.abs(lsf)).sum() / np.abs(lsf).sum()))
hw = min(ctr, len(lsf) - 1 - ctr)
seg = lsf[ctr - hw:ctr + hw + 1] * np.hamming(2 * hw + 1)
sp = np.abs(np.fft.rfft(seg, n=8192)); sp /= sp[0]
f = np.fft.rfftfreq(8192, 1 / bins)
sp /= np.sinc(f / bins) ** 2 # undo binning + differencing
j = np.argmax(sp < 0.5)
return f[j - 1] + (sp[j - 1] - 0.5) / (sp[j - 1] - sp[j]) * (f[j] - f[j - 1])- 對照:像素間距 用「感光元件寬度除以像素寬度」算(例如 36 mm 除以 8,182 約 4.4 µm)。對每個光圈算 ( 用微米),查前面的表(或用 做粗估)得上限。畫出「實測 MTF50 對光圈」與上限的對照圖。
- 預測與證偽條件:(a) 小光圈端( 大於 2,例如 4.4 µm 在 f/16 以上)的實測應貼近上限,落在上限的 90% 以上(這個 90% 是我設的門檻,不是文獻值);(b) 實測最高點應落在比最大光圈小約 1 到 3 格,不會落在最大光圈;(c) 沒有任何一格光圈實測高於上限——若有,先確認銳化真的關了、轉檔是線性、 沒算錯,再往下看。小光圈端若低於上限一大截(比如 f/16 只有上限的一半),代表焦點不準、有微晃(腳架與自拍沒做好)或平面沒對齊,不是繞射。
- 加碼:用最大光圈到最銳光圈之間的差,估計鏡頭像差造成的高斯模糊 :對每個光圈用 解 (我的合成測試裡,真值 0.6 像素能還原成 0.599),看這個 隨光圈縮小是否單調下降,下降的速度是否合理(玩具模型是三次方,真鏡頭不一定)。
今天一天內可以做完的最小版本是:只量 f/4、f/8、f/16 三格,對 查表,看 f/16 是否貼近上限、f/8 是否比 f/4 高或持平。
🔗 延伸學習
- Wikipedia,〈Airy disk〉 — 今天引用的 1.22λN、第一到第三暗環內能量 83.8%、91.0%、93.8%、瑞利準則;我透過抓取工具讀到摘要,數值已自己用貝索函數重算。
- Imatest,〈Diffraction, Optimum Aperture, and Defocus〉 — 繞射 MTF 式、截止頻率 、 的定義、各 MTF 水準的頻率係數(我重算全部吻合);抓取工具讀到的是摘要,其中一句「半徑」與「直徑」敘述互相矛盾,我採用自己重算的直徑 4.88 像素。
- Imatest,〈LSF correction factor for slanted-edge MTF measurements〉 — 斜邊法 4 倍過取樣、LSF 修正因子(Nyquist 處 1.1107、一個例子 MTF50 差 1.41%);我的估計器用不同的微分核,修正式與他們的不同,只在合成資料驗證。
- Imatest,〈Sharpness〉 — MTF50 受銳化影響、建議邊緣對比 4:1、量測前先移除 gamma;我只讀到摘要。
💬 問 AI
我要用斜邊法量我的鏡頭在各光圈的 MTF50,並與繞射加像素孔徑的上限比較。我的設定:像素間距 p(微米,請問我怎麼從感光元件尺寸與 RAW 像素寬度算);波長取 550 nm;Q = λN/p;繞射 MTF = (2/π)(arccos s − s·sqrt(1−s²)),s = f·λ·N/p(f 單位 cycles/pixel);像素孔徑 sinc(f);上限 = 兩者相乘的 MTF50。
(1) 請檢查這個上限的假設:理想鏡頭、單色光、像素 100% 填充、忽略微透鏡、忽略去馬賽克。列出會讓真實量測值「高於」或「低於」上限的情況,各說明方向與大約量級。
(2) Bayer 感光元件的 R、B 通道取樣間距是 2p,G 是對角排列;請說明我取綠色通道做斜邊時,有效取樣間距與 Nyquist 該怎麼定義,以及 5 度斜邊能不能還原出超過該 Nyquist 的資訊。
(3) 請設計一個判斷「小光圈端偏低是繞射還是失焦或微晃」的實驗,至少兩個可證偽的預測。
(4) 請把回答分成三類逐條標示:「公式或標準明確寫的」「你查證到的(附出處)」「你自己的推論」;查不到就說查不到,不要補數字;不要給任何買賣器材的建議。