1. 程式人生 > >影象增強—限制對比度自適應直方圖均衡化(CLAHE)

影象增強—限制對比度自適應直方圖均衡化(CLAHE)

一、自適應直方圖均衡化(Adaptive histgram equalization/AHE)

      1.簡述 

      自適應直方圖均衡化(AHE)是用來提升影象的對比度的一種計算機影象處理技術。和普通的直方圖均衡演算法不同,AHE演算法通過計算影象的區域性直方圖,然後重新分佈亮度來改變影象對比度。因此,該演算法更適合於改進影象的區域性對比度以及獲得更多的影象細節。

       不過,AHE有過度放大影象中相同區域的噪音的問題,另外一種自適應的直方圖均衡演算法即限制對比度直方圖均衡(CLAHE)演算法能有限的限制這種不利的放大。

      2. 演算法的解釋

       普通的直方圖均衡演算法對於整幅影象的畫素使用相同的直方圖進行變換,對於那些畫素值分佈比較均衡的影象來說,演算法的效果很好。然後,如果影象中包括明顯比影象其它區域暗或者亮的部分,則這些部分的對比度將得不到有效的增強。

       AHE演算法通過對區域性區域執行響應的直方圖均衡來改變上述問題。該演算法首先被開發出來適用於改進航天器駕駛艙的顯示效果。其最簡單的形式,就是每個畫素通過其周邊一個矩形範圍內的畫素的直方圖進行均衡化。均衡的方式與普通的均衡化演算法相同:變換函式同畫素周邊的累積直方圖函式(CDF)成比例。

       影象邊緣的畫素需要特殊處理,因為邊緣畫素的領域不完全在影象內部,通過映象影象邊緣的行畫素或列畫素來解決。直接複製邊緣的畫素進行擴充是不合適的,因為這會導致帶有劍鋒的領域直方圖。

      3. AHE的屬性

  •  領域的大小是該演算法的一個引數。領域小,對比度得到增強,領域大,則對比度降低。      
  •  當某個區域包含的畫素值非常相似,其直方圖就會尖狀化,此時直方圖的變換函式會將一個很窄範圍內的畫素對映到整個畫素範圍。這將使得某些平坦區域中的少量噪音經AHE處理後過度放大。

 二、限制對比度自適應直方圖均衡(Contrast Limited Adaptive histgram equalization/CLAHE)

  1.簡述

     CLAHE同普通的自適應直方圖均衡不同的地方主要是其對比度限幅。這個特性也可以應用到全域性直方圖均衡化中,即構成所謂的限制對比度直方圖均衡(CLHE),但這在實際中很少使用。在CLAHE中,對於每個小區域都必須使用對比度限幅,CLAHE主要是用來克服AHE的過度放大噪音的問題。 

     這主要是通過限制AHE演算法的對比提高程度來達到的。在指定的畫素值周邊的對比度放大主要是由變換函式的斜度決定的。這個斜度和領域的累積直方圖的斜度成比例。CLAHE通過在計算CDF前用預先定義的閾值來裁剪直方圖以達到限制放大幅度的目的。這限制了CDF的斜度因此,也限制了變換函式的斜度。直方圖被裁剪的值,也就是所謂的裁剪限幅,取決於直方圖的分佈因此也取決於領域大小的取值。

     通常,直接忽略掉那些超出直方圖裁剪限幅的部分是不好的,而應該將這些裁剪掉的部分均勻的分佈到直方圖的其他部分。如下圖所示。

       Clahe-redist.svg

    這個重分佈的過程可能會導致那些倍裁剪掉的部分又重新超過了裁剪值(如上圖的綠色部分所示)。

     2. 通過插值加快計算速度

        如上所述的直接的自適應直方圖,不管是否帶有對比度限制,都需要對影象中的每個畫素計算其領域直方圖以及對應的變換函式,這使得演算法非常耗時。

        而插值使得上述演算法在效率上有極大的提升,並且質量上沒有下降。首先,將影象均勻分成等份矩形大小,如下圖的右側部分所示(8行8列64個塊是常用的選擇)。然後計算個塊的直方圖、CDF以及對應的變換函式。這個變換函式對於塊的中心畫素(下圖左側部分的黑色小方塊)是完全符合原始定義的。而其他的畫素通過那些與其臨近的四個塊的變換函式插值獲取。位於圖中藍色陰影部分的畫素採用雙線性查插值,而位於便於邊緣的(綠色陰影)部分採用線性插值,角點處(紅色陰影處)直接使用塊所在的變換函式。

       Clahe-tileinterpol.svg

     這樣的過程極大的降低了變換函式需要計算的次數,只是增加了一些雙線性插值的計算量。

import numpy as np
import cv2
 
mri_img = np.load('mri_img.npy')
 
# normalization
mri_max = np.amax(mri_img)
mri_min = np.amin(mri_img)
mri_img = ((mri_img-mri_min)/(mri_max-mri_min))*255
mri_img = mri_img.astype('uint8')
 
r, c, h = mri_img.shape
for k in range(h):
    temp = mri_img[:,:,k]
    clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
    img = clahe.apply(temp)
    cv2.imshow('mri', np.concatenate([temp,img], 1))
    cv2.waitKey(0