拉普拉斯金字塔在多圖HDR算法中的應用以及多曝光圖像的融合算法簡介。 SSE圖像算法優化系列二十六:和時間賽跑之優化高斯金字塔建立的計算過程。

      在SSE圖像算法優化系列二十九:基礎的拉普拉斯金字塔融合用於改善圖像增強中易出現的過增強問題(一) 一文中我們曾經描述過基於幾種高頻融合法則的拉普拉斯金字塔融合算法,那裏是主要針對2副圖像的。實際的應用中,我們可能會遇到多幀圖像的融合過程(圖像都是對齊後的),特別是多幀不同曝光度的圖像的融合問題,在相機的應用中較爲廣泛,我們同時也可以認爲這是另外一種的HDR算法。 

      這方面最經典的文章是2007年Tom Mertens等人發表的《Exposure Fusion》一文,用簡單的篇幅和公式描述了一個非常優異的合成過程,雖然在2019年Charles Hessel發表了一篇《Extended Exposure Fusion》的文章中,提出了比Exposure Fusion更爲優異的合成效果,但是代價是更高昂的計算成本,而Exposure Fusion也已經相當優秀了,本文主要簡單記錄下個人的Exposure Fusion優化過程。

  Exposure Fusion的思路也非常之簡單,輸入是一系列圖像對齊後的大小格式相同的圖像,輸出是一張合成的多細節圖。那麼在進行計算之前,他需要做以下的準備。 

  1、對每副圖像按照某些原則計算每融合的權重。文章裏提出了3種權重。

     (1) 對比度:

               Contrast: we apply a Laplacian filter to the grayscale version of each image, and take the absolute value of the filter response [16]. This yields a simple indicator C for contrast. It tends to assign a high weight to important elements such as edges and texture. 

  對應的matlab代碼非常簡單:

% contrast measure
function C = contrast(I)
h = [0 1 0; 1 -4 1; 0 1 0]; % laplacian filter
N = size(I,4);
C = zeros(size(I,1),size(I,2),N);
for i = 1:N
    mono = rgb2gray(I(:,:,:,i));
    C(:,:,i) = abs(imfilter(mono,h,'replicate'));
end

  我們可以認爲就是個邊緣檢測。

  (2)飽和度 

           Saturation: As a photograph undergoes a longer exposure, the resulting colors become desaturated and eventually clipped. Saturated colors are desirable and make the image look vivid. We include a saturation measure S, which is computed as the standard deviation within the R, G and B channel, at each pixel。

% saturation measure
function C = saturation(I)
N = size(I,4);
C = zeros(size(I,1),size(I,2),N);
for i = 1:N
    % saturation is computed as the standard deviation of the color channels
    R = I(:,:,1,i);
    G = I(:,:,2,i);
    B = I(:,:,3,i);
    mu = (R + G + B)/3;
    C(:,:,i) = sqrt(((R - mu).^2 + (G - mu).^2 + (B - mu).^2)/3);
end

  也是非常簡單的過程。

  (3)曝光度

   Well-exposedness: Looking at just the raw intensities within a channel, reveals how well a pixel is exposed. We want to keep intensities that are not near zero (underexposed) or one (overexposed). We weight each intensity i based on how close it is to 0.5 using a Gauss curve: exp - (i-0.5)*(i-0.5)/(2*σ *σ), where σ equals 0.2 in our implementation. To account for multiple color channels, we apply the Gauss curve to each channel separately, and multiply the results, yielding the measure E。

% well-exposedness measure
function C = well_exposedness(I)
sig = .2;
N = size(I,4);
C = zeros(size(I,1),size(I,2),N);
for i = 1:N
    R = exp(-.5*(I(:,:,1,i) - .5).^2/sig.^2);
    G = exp(-.5*(I(:,:,2,i) - .5).^2/sig.^2);
    B = exp(-.5*(I(:,:,3,i) - .5).^2/sig.^2);
    C(:,:,i) = R.*G.*B;
end

  每副圖像得到三個指標(對比度C、飽和度S以及曝光度E),將他們相乘得到這幅圖像的綜合權重W。

     2、根據每副圖像的權重,計算在序列中圖像的每副圖像的歸一化權重,原文表述如下:

          To obtain a consistent result, we normalizethe values of the N weight maps such that they sum to one at each pixel (i, j):      

            

   注意,這是單個像素進行的處理,也就是說對於一個序列的圖像,每個對應像素位置的權重先計算好後,再累加得到總權重,然後在每個對應像素的權重除以總權重得到歸一化的值。

    3、理論上講,得到了這些權重,就可以對N個圖像進行直接融合,即使用下述公式:

          

   但是如果真的這樣做,得到的結果慘不忍睹,即使我們對歸一化後的權重進行高斯模糊、保邊模糊等等也是解決不了問題的。所以這個文章的最核心的精華部分就在下面的過程中了。 

     4、我們並不是直接用這些權重進行合成,而是對原序列圖像進行高斯拉普拉斯金字塔分解(利用其中的拉普拉斯數據),對各序列對應的歸一化權重做高斯金字塔分解。 然後重構拉普拉斯金字塔,重構的規則爲:

            

    即對合成後各層拉普拉斯金字塔數據,用每個序列的權重的高斯金字塔數據乘以對應的拉普拉斯金字塔數據,然後累加。就如此簡單。

  關於這個算法的原理性說明,CSDN這個作者講的也比較好: 【HDR】曝光融合(Exposure Fusion),有興趣可以參考。

  這個算法的效果通過測試確實還是可以的,原始的作者提供了MATLAB版本的代碼,但是實際測試速度是非常慢的,這個也不怪這些論文的作者,他們的重點是實現算法本身,而不是工程化。

  爲了能提高算法的實用性,我們使用C++結合SIMD指令對該過程進行優化。優化的方式主要有以下幾個方面:

       1、通過適當的改變數據類型來提高速度。

        M版本的代碼是全程是使用的浮點類型的來計算各種數據的,爲了效率,有些過程我們可以使用整形來代替。比如獲取各個特徵的權重的時,我們可以用byte來記錄就可以了。在比如金字塔的分解和重構時,高斯金字塔我們也用byte類型記錄,拉普拉斯金字塔考慮到有負數以及數據的範圍,可以用signed short類型來記錄。 

       2、通過改變數據類型後,使用對應的SIMD指令可以起到更大的步長,浮點數一般一次性只能處理4個數,如果是signed short則可以同時處理8個數據了。 

       3、對於金字塔分解和重構,要從原理上進行優化,詳見:SSE圖像算法優化系列二十六:和時間賽跑之優化高斯金字塔建立的計算過程。

       我們以計算飽和的過程爲例,看看SSE的優化步驟: 

      

     簡簡單單的M代碼,需要大概10倍以上行數的C代碼和SIMD指令進行優化。 

  實際上,我們在優化時,歸一化的那個權重矩陣我也用byte類型來保存數據,原本以爲這樣每個圖的權重有可能會比較小,存在精度損失,不過實際測試,和M代碼的結果也沒啥特別大的視覺區別。 

  另外,還有內存方面的優化問題,如果建立所有圖像的金字塔序列,然後再計算特徵合成,這樣會佔用比較多的內存,特別是圖像序列比較多時,實際上我們可以邊分解邊進行計算,這樣帶來的好處時速度有適當加速(應該還是cache miss較小的原因),當然如果每個序列都分配金字塔的內存,有一個好處就是,可以使用omp進行並行,適當的通過佔用資源提高速度。

  原始論文的作者在獲取了各個特徵的權重後,是使用的乘法來統計特徵,我這裏也使用了加法進行測試,測試結果是加法的結果比乘法的要稍微暗一點。區別也不是很大,但是要注意如果是使用乘法,有的時候有些特徵的權重爲0,爲了不讓其他特徵的權重被淹沒掉,建議加一後再乘。 

  效果:  

         

     

  其中第一個圖是使用4副752*500的圖合成,M代碼大約耗時1600ms,我這裏優化後的速度大概是25ms,有64倍的提速。 

       第二個圖使用的是9副1024*683的圖合成,M代碼大約耗時5000ms,我這裏優化後的速度大概是80ms,也有約60倍的提速。 

      從兩幅圖的合成結果來看,至少視覺上是非常不錯的。不過在第一幅的中間靠上的部分的天空,以及第二副的右下角的檯燈的中間部分還是有過曝的現象,這兩個部分在原圖中實際上是可以找到比較好的底圖的,但是合成結果並沒有吸收他們,這個可以適當的通過改變金字塔的數量來調節,但是沒有啥理論依據去支持他,比如我們把他們的金字塔分別調整爲6和7時效果如下兩圖所示:

   

  這個現象在有些論文裏也有提到,即金字塔層數太深,可能導致結果出現out-of-range的瑕疵,金字塔太少了,會有low-frequency halos出現。

       這個算法還有一個應用場景,在2019年的另外一篇論文裏有提及: Simulated Exposure Fusion, 他的輸入只有一張圖片,然後通過某些手段生成一個序列的圖像,然後在把這序列的圖像予以使用EF算法合成,從而得到不錯的結果,這個待我有空了也來研究一下,這也是個不錯的主意。 

  這個算法也應該非常適合使用GPU進行優化,那可能會獲得更爲客觀的提速比,對於某些應用從而得到實時級別的效果。

  在SSE圖像算法優化系列二十九:基礎的拉普拉斯金字塔融合用於改善圖像增強中易出現的過增強問題(一)一文中使用的融合方法,實際上也是可以應用於多圖的融合的,只不過這個時候低頻的融合方式就不能是選擇哪一個圖了,此時可以使用平均值、最大值、最大值等策略,而高頻融合一般只能使用AbsMax策略, 那個3*3 AbsMax方法也不可以使用了(因爲一致性檢測哪裏無法實現)。

      不過這種融合對於多圖來說一般效果不是很好,但是不排除也有其應用場景,他的一個優勢就是速度能夠做到更快,通常是本文放大的1/3耗時左右,而且內存的佔用也很少。

  另外,對於這個算法,還有一個現象就是其對圖像的合成結果和用光度立體法對那些圖的合成結果似乎很像,當然,僅僅是合成結果類似,廣地立體能獲得的其他信息這個算法是無法獲取的。 

       提供一個測試DEMO供有興趣的朋友玩玩:https://files.cnblogs.com/files/Imageshop/Exposure_Fusion.rar?t=1694501148&download=true

       或者有興趣的朋友也可以在ipol網站中找到一個在線的DEMO以及代碼,詳見地址:https://ipolcore.ipol.im/demo/clientApp/demo.html?id=278

 

    

    如果想時刻關注本人的最新文章,也可關注公衆號或者添加本人微信:  laviewpbt

                             

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章