:周期性與方向性雙維度協(xié)同方法)
1. 從雙人舞這個(gè)比喻說(shuō)起為什么閃爍修復(fù)需要兩個(gè)維度同時(shí)發(fā)力第一次看到這個(gè)標(biāo)題的時(shí)候我盯著It Takes Two愣了幾秒。做圖像修復(fù)的人都知道閃爍問題是個(gè)老難題但大多數(shù)方案要么只盯著時(shí)間軸上的周期性要么只關(guān)注空間上的方向性很少有人把這兩者當(dāng)成一對(duì)舞伴來(lái)對(duì)待。這個(gè)標(biāo)題用二重奏Duet來(lái)比喻周期性和方向性的協(xié)同關(guān)系其實(shí)點(diǎn)出了一個(gè)很本質(zhì)的問題閃爍的本質(zhì)是時(shí)空耦合的退化現(xiàn)象單獨(dú)從任何一個(gè)維度下手都只能治標(biāo)。先把這個(gè)問題的背景說(shuō)清楚。所謂burst flicker指的是在連拍或短時(shí)高頻采集場(chǎng)景下同一場(chǎng)景的多幀圖像之間出現(xiàn)的亮度、色彩或紋理的周期性跳變。這種退化在低照度環(huán)境、短曝光時(shí)間、以及某些特定傳感器工作模式下尤其明顯。你如果拍過(guò)夜景連拍或者處理過(guò)工業(yè)檢測(cè)線上的高速采集序列大概率見過(guò)那種一亮一暗、一亮一暗的規(guī)律性抖動(dòng)——這就是典型的burst flicker。為什么說(shuō)它難修因?yàn)殚W爍不是簡(jiǎn)單的噪聲疊加。它有兩個(gè)糾纏在一起的特征時(shí)間維度上的周期性以及空間維度上的方向性。周期性意味著閃爍模式會(huì)在幀序列中反復(fù)出現(xiàn)你沒法用單幀去噪的思路解決方向性意味著閃爍在圖像平面上的分布不是均勻的它往往沿著某些紋理走向或運(yùn)動(dòng)方向呈現(xiàn)出特定的梯度結(jié)構(gòu)。這兩個(gè)特征互相制約——你如果只做時(shí)間維度的周期建??臻g上的方向性結(jié)構(gòu)就會(huì)被抹平你如果只做空間維度的方向?yàn)V波時(shí)間上的周期性跳變又會(huì)殘留。這個(gè)標(biāo)題里的Duet二重奏用得很精準(zhǔn)。它不是簡(jiǎn)單的兩個(gè)模塊拼接而是強(qiáng)調(diào)兩種機(jī)制需要像雙人舞一樣互相配合、彼此校準(zhǔn)。我在實(shí)際處理類似問題時(shí)最深的一個(gè)體會(huì)是周期性和方向性不是兩個(gè)獨(dú)立的先驗(yàn)而是同一個(gè)退化過(guò)程在兩個(gè)投影面上的表現(xiàn)。理解了這一點(diǎn)整個(gè)修復(fù)框架的設(shè)計(jì)思路就清晰了。這篇文章我會(huì)圍繞這個(gè)核心思路展開把為什么需要雙維度協(xié)同周期性怎么建模方向性怎么提取兩者怎么耦合實(shí)際跑起來(lái)會(huì)遇到什么坑這幾個(gè)問題逐一拆開講。適合做圖像復(fù)原、視頻增強(qiáng)、工業(yè)視覺檢測(cè)的同行參考也適合對(duì)多幀融合感興趣的朋友。文章里涉及的具體參數(shù)和步驟我會(huì)盡量給到可復(fù)現(xiàn)的程度但涉及具體項(xiàng)目細(xì)節(jié)的地方會(huì)用虛構(gòu)代稱處理。2. 周期性建模從幀間差分到隱式周期編碼2.1 為什么幀間差分是最直覺但最不夠用的起點(diǎn)大多數(shù)人遇到閃爍問題的第一反應(yīng)是做幀間差分。把相鄰兩幀相減差值大的地方就是閃爍發(fā)生的位置。這個(gè)思路沒錯(cuò)但它有個(gè)致命缺陷幀間差分只能告訴你哪里變了不能告訴你變化的規(guī)律是什么。我早期做過(guò)一個(gè)實(shí)驗(yàn)用簡(jiǎn)單的幀間差分加閾值來(lái)定位閃爍區(qū)域結(jié)果發(fā)現(xiàn)兩個(gè)問題。第一運(yùn)動(dòng)物體也會(huì)產(chǎn)生大的幀間差分你沒法區(qū)分因?yàn)槲矬w動(dòng)了還是因?yàn)殚W爍了。第二即使定位到了閃爍區(qū)域你也不知道下一幀會(huì)怎么變——是繼續(xù)變亮還是回暗變化幅度是線性還是非線性這些信息幀間差分給不了。所以周期性建模的核心任務(wù)不是檢測(cè)變化而是從幀序列中提取出變化的周期結(jié)構(gòu)。這個(gè)周期結(jié)構(gòu)一旦建立起來(lái)你就可以預(yù)測(cè)任意時(shí)刻的閃爍狀態(tài)進(jìn)而做針對(duì)性的補(bǔ)償。2.2 用自相關(guān)函數(shù)捕捉周期一個(gè)被低估的工具說(shuō)到周期性分析自相關(guān)函數(shù)Autocorrelation Function, ACF是最經(jīng)典的工具。它的邏輯很樸素把一個(gè)信號(hào)和它自己延遲若干步后的版本做相關(guān)如果存在周期T那么在延遲為T的整數(shù)倍處會(huì)出現(xiàn)明顯的峰值。具體到閃爍修復(fù)你可以對(duì)每個(gè)空間位置或者每個(gè)局部塊的亮度時(shí)間序列做自相關(guān)分析。假設(shè)某個(gè)像素點(diǎn)在N幀中的亮度序列是 $I(t)$那么它的自相關(guān)函數(shù)定義為$$R(\tau) \frac{1}{N-\tau}\sum_{t1}^{N-\tau}(I(t)-\bar{I})(I(t\tau)-\bar{I})$$其中 $\bar{I}$ 是時(shí)間均值$\tau$ 是延遲量。如果這個(gè)序列存在周期為 $T$ 的閃爍那么 $R(\tau)$ 會(huì)在 $\tau T, 2T, 3T...$ 處出現(xiàn)峰值。這里有個(gè)實(shí)操細(xì)節(jié)值得注意不要對(duì)整幀做全局自相關(guān)。因?yàn)椴煌瑓^(qū)域的閃爍周期可能不同——比如畫面左側(cè)是50Hz光源導(dǎo)致的閃爍右側(cè)是60Hz光源導(dǎo)致的全局自相關(guān)會(huì)把兩個(gè)周期混在一起峰值變得模糊。我的做法是把圖像分成16×16或32×32的塊對(duì)每個(gè)塊單獨(dú)做自相關(guān)然后再做空間上的聚類把周期一致的塊歸為一組。提示塊的大小需要權(quán)衡。塊太小時(shí)間序列太短自相關(guān)估計(jì)不穩(wěn)定塊太大不同周期的區(qū)域會(huì)被混在一起。根據(jù)我的經(jīng)驗(yàn)在幀數(shù)超過(guò)64幀的情況下32×32的塊是個(gè)不錯(cuò)的起點(diǎn)。2.3 從顯式周期到隱式編碼為什么我最終放棄了手工周期估計(jì)自相關(guān)方法在理想情況下工作得不錯(cuò)但實(shí)際數(shù)據(jù)里有個(gè)大問題閃爍周期往往不是嚴(yán)格恒定的。光源頻率可能有微小漂移采集設(shè)備的時(shí)鐘也可能有抖動(dòng)再加上場(chǎng)景中可能存在多個(gè)閃爍源疊加導(dǎo)致周期結(jié)構(gòu)變得模糊甚至?xí)r變。我試過(guò)用峰值檢測(cè)加插值來(lái)跟蹤周期變化效果一般。后來(lái)轉(zhuǎn)向了隱式編碼的思路不顯式估計(jì)周期而是讓網(wǎng)絡(luò)自己學(xué)習(xí)一個(gè)周期感知的時(shí)序表示。具體做法是用一維時(shí)序卷積或輕量級(jí)的時(shí)序注意力模塊在時(shí)間維度上做特征提取讓模型自動(dòng)捕捉周期模式。這里的關(guān)鍵設(shè)計(jì)是時(shí)序感受野要足夠大。如果你的時(shí)序模塊只能看到前后3幀那它沒法捕捉周期為10幀的閃爍。我的經(jīng)驗(yàn)是時(shí)序感受野至少要是預(yù)期最大周期的2到3倍。比如你預(yù)期閃爍周期在5到15幀之間那感受野至少要覆蓋45幀。這可以通過(guò)堆疊多層時(shí)序卷積或者使用空洞卷積來(lái)實(shí)現(xiàn)。import torch import torch.nn as nn class TemporalPeriodEncoder(nn.Module): 時(shí)序周期編碼器用空洞卷積捕捉多尺度周期結(jié)構(gòu) def __init__(self, channels64, max_period20): super().__init__() # 空洞率設(shè)置為1,2,4,8覆蓋不同尺度的周期 self.dilated_convs nn.ModuleList([ nn.Conv1d(channels, channels, kernel_size3, padding2**i, dilation2**i) for i in range(4) ]) self.fusion nn.Conv1d(channels * 4, channels, kernel_size1) self.act nn.GELU() def forward(self, x): # x: (B, C, T) 時(shí)間維度的特征序列 outs [conv(x) for conv in self.dilated_convs] out torch.cat(outs, dim1) out self.act(self.fusion(out)) return out這段代碼的核心思想是用不同空洞率的卷積并行處理讓模型同時(shí)看到短周期和長(zhǎng)周期的模式??斩绰蕿?的卷積看局部變化空洞率為8的卷積看更長(zhǎng)范圍的周期結(jié)構(gòu)。最后用1×1卷積融合。實(shí)測(cè)下來(lái)這種設(shè)計(jì)比單一尺度的時(shí)序卷積在周期估計(jì)準(zhǔn)確率上能高出十幾個(gè)百分點(diǎn)。2.4 周期建模的邊界條件什么情況下這套方法會(huì)失效不是所有閃爍都能用周期建模解決。我踩過(guò)的坑里有兩種情況特別需要注意。第一種是非周期性閃爍。有些閃爍是由隨機(jī)因素引起的比如傳感器熱噪聲的隨機(jī)波動(dòng)、或者場(chǎng)景中隨機(jī)出現(xiàn)的反光。這類閃爍沒有穩(wěn)定的周期結(jié)構(gòu)自相關(guān)函數(shù)上找不到明顯峰值隱式編碼也很難學(xué)到規(guī)律。遇到這種情況我的建議是退回到幀間一致性約束的思路不強(qiáng)求周期建模。第二種是周期混疊。當(dāng)閃爍周期接近幀間隔的整數(shù)倍時(shí)會(huì)出現(xiàn)類似信號(hào)處理中混疊的現(xiàn)象——你采樣到的周期和真實(shí)周期不一致。比如真實(shí)閃爍周期是2.5幀但你只能按整數(shù)幀采樣就會(huì)看到周期在2幀和3幀之間跳變。這種情況下單純?cè)陔x散幀序列上做周期分析會(huì)得到錯(cuò)誤結(jié)果。解決辦法是引入亞幀級(jí)別的時(shí)序建?;蛘咴谧鲋芷诠烙?jì)前先對(duì)時(shí)間序列做上采樣。3. 方向性提取閃爍在空間上到底長(zhǎng)什么樣3.1 閃爍的空間分布不是隨機(jī)的很多人以為閃爍就是全局的亮度跳變其實(shí)不然。如果你把閃爍幀和正常幀的差值圖拿出來(lái)看會(huì)發(fā)現(xiàn)閃爍在空間上呈現(xiàn)出明顯的結(jié)構(gòu)——它往往沿著某些方向有更強(qiáng)的梯度而在垂直于這些方向上變化平緩。這個(gè)現(xiàn)象背后的物理原因是閃爍通常和場(chǎng)景中的光照條件、表面材質(zhì)、以及傳感器的空間響應(yīng)特性有關(guān)。比如一個(gè)方向性的光源照射在粗糙表面上不同區(qū)域的反射強(qiáng)度會(huì)沿著光源方向呈現(xiàn)梯度變化當(dāng)光源強(qiáng)度波動(dòng)時(shí)這種梯度結(jié)構(gòu)就會(huì)被調(diào)制形成方向性的閃爍模式。所以方向性提取的目標(biāo)是找到閃爍在空間上的主方向以及沿這個(gè)方向的梯度分布。這相當(dāng)于給閃爍場(chǎng)建立一個(gè)空間先驗(yàn)告訴修復(fù)算法這里的閃爍應(yīng)該沿著這個(gè)方向變化不要在其他方向上亂補(bǔ)。3.2 結(jié)構(gòu)張量一個(gè)被圖像修復(fù)領(lǐng)域用爛但確實(shí)好用的工具說(shuō)到方向性分析結(jié)構(gòu)張量Structure Tensor是繞不開的。它的基本構(gòu)造是對(duì)圖像求梯度然后用高斯核做局部加權(quán)平均得到一個(gè)2×2的矩陣$$J \begin{pmatrix} \sum I_x^2 \sum I_x I_y \ \sum I_x I_y \sum I_y^2 \end{pmatrix}$$這個(gè)矩陣的特征向量給出了局部的主方向特征值的差異反映了方向性的強(qiáng)弱。如果兩個(gè)特征值差不多大說(shuō)明該區(qū)域是各向同性的比如平坦區(qū)域或角點(diǎn)如果一個(gè)遠(yuǎn)大于另一個(gè)說(shuō)明有明確的方向性結(jié)構(gòu)。在閃爍修復(fù)里我對(duì)結(jié)構(gòu)張量的用法做了一點(diǎn)調(diào)整不是對(duì)原始圖像求結(jié)構(gòu)張量而是對(duì)幀間差分圖求。因?yàn)槲覀円治龅氖情W爍本身的方向性而不是場(chǎng)景內(nèi)容的方向性。具體來(lái)說(shuō)先計(jì)算相鄰幀的差分 $D_t I_{t1} - I_t$然后對(duì) $D_t$ 求結(jié)構(gòu)張量得到閃爍場(chǎng)的方向分布。注意對(duì)差分圖求結(jié)構(gòu)張量時(shí)高斯核的尺度要選得比常規(guī)圖像處理更大一些。因?yàn)殚W爍場(chǎng)的空間變化通常比場(chǎng)景紋理更平緩用小尺度核會(huì)得到噪聲很大的方向估計(jì)。我的經(jīng)驗(yàn)是核的標(biāo)準(zhǔn)差取圖像短邊的1%到2%比較合適。3.3 方向性引導(dǎo)的修復(fù)讓補(bǔ)償沿著正確的方向傳播有了方向性信息之后怎么用它來(lái)指導(dǎo)修復(fù)核心思路是讓修復(fù)過(guò)程沿著閃爍的主方向傳播而在垂直于主方向的方向上保持約束。打個(gè)比方這就像修補(bǔ)一幅有方向性裂紋的畫。如果裂紋是水平走向的你應(yīng)該沿著水平方向把顏料鋪過(guò)去而不是垂直方向亂涂。閃爍修復(fù)也是同理如果閃爍在某個(gè)區(qū)域是水平方向變化的那補(bǔ)償量也應(yīng)該沿著水平方向平滑過(guò)渡垂直方向上則要尊重原有的幀間一致性。具體實(shí)現(xiàn)上我通常用方向性加權(quán)的擴(kuò)散項(xiàng)來(lái)構(gòu)造修復(fù)的能量函數(shù)。設(shè) $u$ 是待求的補(bǔ)償場(chǎng)$D$ 是方向性張量場(chǎng)那么擴(kuò)散項(xiàng)可以寫成$$E_{smooth} \int \nabla u^T D \nabla u , dx$$這個(gè)式子的含義是在方向性強(qiáng)的區(qū)域$D$ 的特征值差異大擴(kuò)散主要沿著主方向進(jìn)行在方向性弱的區(qū)域$D$ 接近各向同性擴(kuò)散就變成普通的拉普拉斯平滑。這樣既保護(hù)了方向性結(jié)構(gòu)又不會(huì)在無(wú)方向區(qū)域引入偽影。3.4 方向性估計(jì)的常見翻車現(xiàn)場(chǎng)方向性估計(jì)聽起來(lái)簡(jiǎn)單實(shí)際做起來(lái)坑不少。我列幾個(gè)自己踩過(guò)的第一個(gè)坑是運(yùn)動(dòng)干擾。如果場(chǎng)景中有運(yùn)動(dòng)物體幀間差分里既有閃爍又有運(yùn)動(dòng)結(jié)構(gòu)張量會(huì)把運(yùn)動(dòng)方向也當(dāng)成閃爍方向。解決辦法是先做運(yùn)動(dòng)補(bǔ)償或者用光流把運(yùn)動(dòng)區(qū)域mask掉再做方向估計(jì)。我一般用簡(jiǎn)單的塊匹配做粗運(yùn)動(dòng)補(bǔ)償夠用了。第二個(gè)坑是方向翻轉(zhuǎn)。結(jié)構(gòu)張量給出的特征向量方向有180度的歧義——它只能告訴你沿著這條線不能告訴你朝哪個(gè)方向。在擴(kuò)散方程里這通常不是問題因?yàn)閿U(kuò)散是雙向的。但如果你要做方向性的預(yù)測(cè)或外推就必須解決這個(gè)歧義。我的做法是用幀間差分的符號(hào)信息來(lái)消歧如果差分值在某個(gè)方向上從正變負(fù)就說(shuō)明閃爍是朝這個(gè)方向傳播的。第三個(gè)坑是多方向疊加。有些復(fù)雜場(chǎng)景下閃爍可能同時(shí)存在多個(gè)方向的分量。單一張量只能表示一個(gè)主方向遇到這種情況就會(huì)估計(jì)不準(zhǔn)。這時(shí)候可以考慮用高階張量或者多尺度方向分解來(lái)處理但復(fù)雜度會(huì)上升不少。我的建議是先用單方向模型跑通遇到多方向場(chǎng)景再考慮升級(jí)。4. 周期與方向的耦合二重奏到底怎么奏4.1 耦合不是拼接兩種信息的交互方式?jīng)Q定了修復(fù)上限前面兩節(jié)分別講了周期性和方向性的建模方法。但真正決定修復(fù)效果的是這兩者怎么耦合。我見過(guò)不少方案是把周期模塊和方向模塊串起來(lái)或者并起來(lái)效果都不理想。原因很簡(jiǎn)單周期性和方向性不是獨(dú)立的兩個(gè)任務(wù)它們描述的是同一個(gè)退化過(guò)程的不同側(cè)面。舉個(gè)具體的例子。假設(shè)某個(gè)區(qū)域存在周期為8幀、方向?yàn)樗降拈W爍。如果你先做周期補(bǔ)償再做方向平滑周期補(bǔ)償可能會(huì)在垂直方向引入不自然的跳變而后續(xù)的方向平滑又沒法完全消除這些跳變。反過(guò)來(lái)如果先做方向平滑再做周期補(bǔ)償方向平滑可能會(huì)模糊掉周期結(jié)構(gòu)的邊界導(dǎo)致周期估計(jì)失準(zhǔn)。正確的做法是讓兩者在同一個(gè)優(yōu)化框架里互相約束。周期信息告訴方向模塊什么時(shí)候該強(qiáng)補(bǔ)償、什么時(shí)候該弱補(bǔ)償方向信息告訴周期模塊在哪些空間位置上周期結(jié)構(gòu)更可靠、哪些位置需要降權(quán)。4.2 一個(gè)可落地的耦合框架交替優(yōu)化加一致性約束我實(shí)際用過(guò)的耦合框架是交替優(yōu)化加一致性約束的結(jié)構(gòu)。具體分三步第一步固定當(dāng)前的方向估計(jì)用周期模型計(jì)算每個(gè)位置的補(bǔ)償量。這一步的輸出是一個(gè)時(shí)空補(bǔ)償場(chǎng) $C_1(t, x, y)$。第二步固定當(dāng)前的周期估計(jì)用方向性擴(kuò)散對(duì)補(bǔ)償場(chǎng)做空間正則化得到 $C_2(t, x, y)$。第三步計(jì)算 $C_1$ 和 $C_2$ 之間的一致性損失如果一致性不滿足閾值就更新方向估計(jì)和周期估計(jì)回到第一步。這個(gè)框架的好處是每一步都有明確的物理含義而且可以靈活替換具體的周期模型和方向模型。我用自相關(guān)做周期估計(jì)、結(jié)構(gòu)張量做方向估計(jì)跑三輪交替優(yōu)化通常就能收斂。def alternating_optimization(frames, max_iter5, tol1e-4): 交替優(yōu)化框架周期補(bǔ)償與方向正則化交替進(jìn)行 # 初始化 direction_field estimate_structure_tensor(frames) period_map estimate_period_autocorr(frames) prev_energy float(inf) for it in range(max_iter): # 步驟1基于周期圖做時(shí)序補(bǔ)償 comp_temporal temporal_compensation(frames, period_map) # 步驟2基于方向場(chǎng)做空間正則化 comp_spatial directional_diffusion(comp_temporal, direction_field) # 步驟3計(jì)算一致性并更新估計(jì) consistency compute_consistency(comp_temporal, comp_spatial) energy compute_total_energy(frames, comp_spatial, direction_field) if abs(prev_energy - energy) tol: break prev_energy energy # 更新方向場(chǎng)和周期圖 direction_field update_direction(frames, comp_spatial) period_map update_period(frames, comp_spatial) return comp_spatial這段偽代碼展示了交替優(yōu)化的核心邏輯。實(shí)際實(shí)現(xiàn)時(shí)每一步的具體算法可以根據(jù)數(shù)據(jù)特點(diǎn)替換。比如周期估計(jì)可以用自相關(guān)也可以用隱式網(wǎng)絡(luò)編碼方向正則化可以用各向異性擴(kuò)散也可以用方向性卷積網(wǎng)絡(luò)。4.3 耦合權(quán)重的自適應(yīng)調(diào)整一個(gè)容易被忽略的細(xì)節(jié)在耦合框架里周期項(xiàng)和方向項(xiàng)的權(quán)重怎么定是個(gè)很實(shí)際的問題。權(quán)重太大某一項(xiàng)會(huì)主導(dǎo)整個(gè)優(yōu)化權(quán)重太小那一項(xiàng)就形同虛設(shè)。我的經(jīng)驗(yàn)是不要用固定權(quán)重而是根據(jù)局部可靠性自適應(yīng)調(diào)整。具體來(lái)說(shuō)對(duì)每個(gè)空間位置計(jì)算兩個(gè)可靠性指標(biāo)周期可靠性自相關(guān)峰值的顯著程度和方向可靠性結(jié)構(gòu)張量特征值的差異程度。然后根據(jù)這兩個(gè)指標(biāo)動(dòng)態(tài)調(diào)整權(quán)重。周期可靠性方向可靠性周期權(quán)重方向權(quán)重說(shuō)明高高0.50.5兩者都可信均衡使用高低0.80.2方向不可信以周期為主低高0.20.8周期不可信以方向?yàn)橹鞯偷?.50.5兩者都不可信退回保守策略這個(gè)表格是我在實(shí)際調(diào)參中總結(jié)出來(lái)的經(jīng)驗(yàn)值不一定對(duì)所有數(shù)據(jù)都最優(yōu)但作為起點(diǎn)很實(shí)用。關(guān)鍵是要有自適應(yīng)機(jī)制而不是一組權(quán)重跑到底。4.4 耦合框架的計(jì)算開銷與加速策略交替優(yōu)化有個(gè)明顯的缺點(diǎn)計(jì)算開銷大。每輪迭代都要重新估計(jì)周期和方向如果幀數(shù)多、分辨率高跑起來(lái)會(huì)很慢。我做過(guò)一個(gè)測(cè)試在512×512分辨率、64幀的數(shù)據(jù)上跑5輪交替優(yōu)化大概需要幾十秒對(duì)于離線處理可以接受但對(duì)于實(shí)時(shí)或準(zhǔn)實(shí)時(shí)場(chǎng)景就太慢了。加速策略有幾個(gè)方向。一是降低估計(jì)頻率不需要每輪都重新估計(jì)周期和方向可以每隔兩輪更新一次。二是多尺度策略先在低分辨率上做粗估計(jì)再在高分辨率上做精修。三是并行化周期估計(jì)和方向估計(jì)可以并行執(zhí)行因?yàn)樗鼈冎g沒有嚴(yán)格的依賴關(guān)系只需要在耦合步驟同步即可。我通常用多尺度加并行化的組合能把速度提升3到5倍效果損失很小。5. 實(shí)測(cè)中的意外情況與排查鏈路5.1 修復(fù)后出現(xiàn)鬼影一次完整的排查記錄有一次處理一批工業(yè)檢測(cè)線的連拍數(shù)據(jù)修復(fù)后的圖像在物體邊緣出現(xiàn)了明顯的鬼影——就是邊緣附近有一層半透明的重影。這個(gè)問題困擾了我兩天最后排查出來(lái)的原因挺有意思。排查過(guò)程是這樣的。第一步我先確認(rèn)鬼影是不是修復(fù)引入的。對(duì)比修復(fù)前后的幀間差分發(fā)現(xiàn)鬼影在修復(fù)前不存在確認(rèn)是修復(fù)過(guò)程產(chǎn)生的。第二步我檢查了方向性估計(jì)的結(jié)果發(fā)現(xiàn)物體邊緣處的方向估計(jì)出現(xiàn)了異?!Y(jié)構(gòu)張量在邊緣處給出了和閃爍方向垂直的結(jié)果。第三步我意識(shí)到問題出在邊緣處的幀間差分同時(shí)包含了閃爍和運(yùn)動(dòng)結(jié)構(gòu)張量把運(yùn)動(dòng)邊緣的方向當(dāng)成了閃爍方向?qū)е卵a(bǔ)償量沿著錯(cuò)誤的方向傳播形成了鬼影。解決辦法是在方向估計(jì)前先做運(yùn)動(dòng)檢測(cè)把運(yùn)動(dòng)區(qū)域的方向估計(jì)降權(quán)或者用鄰域插值替代。具體來(lái)說(shuō)我用簡(jiǎn)單的三幀差分做運(yùn)動(dòng)檢測(cè)得到運(yùn)動(dòng)mask然后在結(jié)構(gòu)張量計(jì)算時(shí)對(duì)運(yùn)動(dòng)區(qū)域施加一個(gè)衰減因子。提示運(yùn)動(dòng)檢測(cè)不需要很精確粗粒度的mask就夠用。因?yàn)槲覀兊哪繕?biāo)只是避免運(yùn)動(dòng)區(qū)域污染方向估計(jì)不需要精確分割運(yùn)動(dòng)物體。5.2 周期估計(jì)在短序列上的崩潰另一個(gè)常見問題是幀數(shù)太少時(shí)周期估計(jì)不準(zhǔn)。我遇到過(guò)只有16幀的數(shù)據(jù)自相關(guān)函數(shù)上根本找不到明顯的峰值因?yàn)?6幀最多只能覆蓋兩個(gè)周期假設(shè)周期為8幀統(tǒng)計(jì)量太少峰值被噪聲淹沒。這種情況下我的處理策略是降級(jí)到非周期模型。具體來(lái)說(shuō)放棄周期建模改用幀間一致性加方向性平滑的組合。雖然效果不如完整的周期加方向模型但至少不會(huì)因?yàn)橹芷诠烙?jì)錯(cuò)誤而引入新的偽影。如果你經(jīng)常處理短序列數(shù)據(jù)建議在框架里加一個(gè)自動(dòng)判斷機(jī)制當(dāng)幀數(shù)少于某個(gè)閾值我的經(jīng)驗(yàn)值是32幀或者自相關(guān)峰值顯著性低于某個(gè)閾值時(shí)自動(dòng)切換到降級(jí)模式。5.3 色彩通道不一致導(dǎo)致的修復(fù)偏色還有一個(gè)坑是色彩通道的處理。大多數(shù)閃爍修復(fù)方法是在亮度通道上做的但實(shí)際數(shù)據(jù)里閃爍往往同時(shí)影響多個(gè)色彩通道而且不同通道的閃爍模式可能不一致。如果你只在亮度通道做修復(fù)然后把修復(fù)結(jié)果應(yīng)用到色彩通道就會(huì)出現(xiàn)偏色。我的做法是在YCbCr空間分別處理Y、Cb、Cr三個(gè)通道但共享方向性估計(jì)。因?yàn)榉较蛐灾饕蓤?chǎng)景幾何和光照方向決定三個(gè)通道應(yīng)該是一致的而周期性和幅度可以各通道獨(dú)立估計(jì)。這樣既避免了偏色又不會(huì)顯著增加計(jì)算量。5.4 參數(shù)調(diào)優(yōu)的實(shí)用建議最后分享幾個(gè)參數(shù)調(diào)優(yōu)的經(jīng)驗(yàn)。周期估計(jì)里的自相關(guān)窗口長(zhǎng)度建議取預(yù)期最大周期的3到5倍方向估計(jì)里的高斯核標(biāo)準(zhǔn)差建議取圖像短邊的1%到2%交替優(yōu)化的迭代次數(shù)3到5輪通常夠用再多收益遞減耦合權(quán)重的自適應(yīng)閾值建議根據(jù)數(shù)據(jù)的信噪比來(lái)定信噪比高就放寬閾值信噪比低就收緊。這些數(shù)值不是絕對(duì)的但作為起點(diǎn)能幫你省不少調(diào)參時(shí)間。實(shí)際使用時(shí)建議先用小規(guī)模數(shù)據(jù)快速試幾組參數(shù)找到大致范圍后再在全量數(shù)據(jù)上跑。6. 把這套思路遷移到其他場(chǎng)景這套周期性加方向性的耦合思路其實(shí)不限于burst flicker removal。我后來(lái)把它遷移到了幾個(gè)相關(guān)場(chǎng)景效果都不錯(cuò)。一個(gè)是視頻壓縮偽影去除。壓縮偽影也有周期性和方向性的特征——塊效應(yīng)有固定的周期塊大小而振鈴效應(yīng)有方向性。用類似的耦合框架處理比單純的去塊濾波效果好不少。另一個(gè)是多幀超分辨率中的運(yùn)動(dòng)模糊去除。運(yùn)動(dòng)模糊的方向性很明顯而多幀之間的模糊模式又有周期性變化。把周期和方向耦合起來(lái)建模能更好地恢復(fù)高頻細(xì)節(jié)。還有一個(gè)是醫(yī)學(xué)影像中的周期性運(yùn)動(dòng)偽影。比如心臟跳動(dòng)或呼吸引起的偽影既有時(shí)間上的周期性又有空間上的方向性。這套框架稍作調(diào)整就能用。遷移的時(shí)候需要注意一點(diǎn)不同場(chǎng)景下周期性和方向性的相對(duì)重要性不同。比如壓縮偽影里周期性更主導(dǎo)運(yùn)動(dòng)模糊里方向性更主導(dǎo)。耦合權(quán)重的自適應(yīng)策略需要根據(jù)具體場(chǎng)景重新調(diào)。我在實(shí)際使用中最大的體會(huì)是不要把這套方法當(dāng)成一個(gè)固定的算法而是當(dāng)成一個(gè)設(shè)計(jì)思路。周期性和方向性的具體建模方法可以換耦合框架可以簡(jiǎn)化或復(fù)雜化但兩個(gè)維度協(xié)同這個(gè)核心思想是通用的。理解了這一點(diǎn)你遇到新的閃爍類問題時(shí)就知道該從哪兩個(gè)角度去拆解了。最后再分享一個(gè)小技巧如果你手頭的數(shù)據(jù)量不大沒法訓(xùn)練復(fù)雜的隱式周期編碼網(wǎng)絡(luò)那就老老實(shí)實(shí)用自相關(guān)加結(jié)構(gòu)張量的經(jīng)典組合。這套組合雖然老但在數(shù)據(jù)有限的情況下反而更穩(wěn)不容易過(guò)擬合。等數(shù)據(jù)量上來(lái)了再考慮升級(jí)到學(xué)習(xí)式的方案。