1. 程式人生 > >一種消除區域性自適應對比度增強演算法方塊效應的方法

一種消除區域性自適應對比度增強演算法方塊效應的方法

在一種基於腐蝕膨脹運算實現的區域性自適應對比度增強演算法中,提出了一種可以分開自適應的調整區域性亮部和暗部對比度的方法。但是就象在評論中提到的,這種方法會產生方塊效應。特別是在對比度已經比較大的邊緣附近,這種方塊效應會比較明顯。這是因為在邊緣附近,對比度本來就是比較大的,偏均方差也就相應的比較大。那麼調整的時候給出自適應的調整量就會相應地變小。一旦離開邊緣附近,領域不包括邊緣,對比度就會相對陡然變小,那麼自適應的調整量就會相應變大。那麼在邊緣同一側就可能會比較明顯地出現不均勻的變化,也就是我們所說的方塊效應。不均勻變化的位置離邊緣的位置之間的距離就是所使用的高光半徑或者暗影半徑大小。

看一下示例。這裡為了明顯顯示方塊效應,選擇了一張前景和背景反差比較大的圖片。同時這裡我特意把高光半徑和暗影半徑選的不一樣,這樣我們就可以看到在不同半徑的地方有兩個明顯的不均勻變化。

  

                                      原始圖片(1024x701)                           高光半徑100,高光數量30,暗影半徑50,暗影數量30,產生方塊效應

消除方塊效應的辦法,一個是在做完對比度調整後,再做一個高斯模糊之類的低通濾波平滑這種不均勻。這種方法不可避免地會減小影象整體清晰度。另一個簡單的應對方法是,擴大所使用的領域。領域越大,包含畫素越多,那麼移動領域時對比度變化幅度就不會特別劇烈(即使在邊緣附近),這樣使得調整量的變化幅度也會大幅減少,極大地減少了方塊效應。但同時,領域的擴大,也使得不同畫素的領域不管是腐蝕還是膨脹結果都更加趨同,失去了所謂的區域性自適應的效果。極限情況我們想象一下,如果領域半徑接近甚至超過影象大小,那麼所有畫素的腐蝕或者膨脹結果都是一樣的了。那麼自適應調整量也就都一樣了,那就是一個全域性的調整量了。

那麼有沒有一種方法既能減小方塊效應,又避免這些副作用呢?方塊效應產生的根源是在影象邊緣附近對比度的變化過大導致的。那是否能過濾這種變化呢?這讓我想到了有保邊效果的選擇性平滑所使用的方法。比如選擇性均值平滑,不是把領域內的所有畫素一起求平均值,而是選擇領域內和中心畫素的差值小於一定閾值的所有畫素求平均值。假設在領域內有一個邊緣,如果設定合適的閾值,就能把和中心畫素在邊緣另一側的畫素都排除掉,只使用和中心畫素同側的畫素參與計算,結果既保留了邊緣,也起到了平滑效果。如果應用這種思想,在計算自適應調整量時,具體就是在計算膨脹或腐蝕結果的偏方差的時候,只選擇和膨脹或腐蝕結果畫素差值小於一定閾值的畫素參與計算偏方差,理論上應該就能消除方塊效應了。

原理上來說和原始方法沒有大的區別,就是需要多設定一個閾值

  • 膨脹腐蝕計算時也是選擇性的,選擇領域內和中心畫素差值小於閾值的所有畫素中的最大值(膨脹)和最小值(腐蝕)。
  • 計算偏方差也是選擇性的,選擇領域內和中心畫素差值小於閾值的所有畫素參與計算。公式是一樣的,只是求和不是所有畫素總數n。

剩下的其他步驟都是一樣的。

如何計算選擇性膨脹腐蝕,還有選擇性偏方差的方法也是一個問題。其中需要計算領域極值,均值和平方均值。原始演算法是用積分圖來計算領域平方和和領域和,現在選擇性求和,積分圖不再適用了。在選擇性平滑方法中經常使用的是O(1)複雜度的領域直方圖更新演算法,原始論文可以在Median Filtering in Constant Time找到。我們在這裡也可以用它,它的計算量基本和領域半徑無關。而且使用領域直方圖更新演算法,可以計算多種選擇性領域值,比如平均值,中值,極值,平方和均值,還可以應用表面模糊演算法,區域性直方圖均衡等等。領域直方圖更新演算法的主要思想是,計算領域內所有畫素直方圖。當我們從左到右,從上到下移動時,每次移動更新一次領域直方圖。更新時減去移出領域的所有畫素的直方圖,加上新進入領域的所有畫素的直方圖,這隻需要較少的計算量。具體的為加快計算,還保持更新和領域高度相同的所有列的直方圖,這樣更新領域直方圖時,只需加減相應的列直方圖即可。具體演算法這裡不多做討論了。

有了領域直方圖,就可以很簡單地計算選擇性平均值和平方和均值。如下程式碼計算選擇性均值。選擇性平方和均值,還有極值也很簡單。

{
    /* int cen: 中心畫素
    * int threshold: 閾值
    * Hist[]: 領域直方圖
    */
    int l;
    unsigned long weight = 0, sum = 0;
    int low, high;
    low = cen - threshold;
    if (low < 0) low = 0;
    high = cen + threshold;
    if (high > 255) high = 255;
    for (l = low; l <= high; l++)
    {
        sum += Hist[l] * l;
        weight += Hist[l];
    }
    return sum / weight;
}
選擇性計算領域均值

 對於高光調整計算,一次直方圖更新演算法可以得到選擇性平方和均值,均值和最小值。再做一次直方圖更新演算法可以得到暗影調整所需的值。如果高光和暗影半徑是一樣的話,只需要一次直方圖更新演算法就可以得到高光暗影調整所有需要的結果。再遍歷一次影象,應用到所有畫素即可。

看一下效果。無閾值相當於領域內所有畫素都參與計算,如前所述會產生方塊效應。保持高光和暗影半徑不變,隨著閾值減小,方塊效應也會減小,達到我們希望的結果了。

   

                                        原始圖片(1024x701)                                高光半徑100,高光數量30,暗影半徑50,暗影數量30,無閾值

  

高光半徑100,高光數量30,暗影半徑50,暗影數量30,閾值50        高光半徑100,高光數量30,暗影半徑50,暗影數量30,閾值10

分享一個測試程式https://files.cnblogs.com/files/mightycode/edcontrast.7z,需要安裝vc++ 2015-2019 redistributabl