【圖像增強】CLAHE 限制對比度自適應直方圖均衡化

文章目錄:

1 基本概述

CLAHE是一個比較有意思的圖像增強的方法,主要用在醫學圖像上面。之前的比賽中,用到了這個,但是對其算法原理不甚瞭解。在這裏做一個覆盤。

CLAHE起到的作用簡單來說就是增強圖像的對比度的同時可以抑制噪聲

CLAHE的英文是Contrast Limited Adaptive Histogram Equalization 限制對比度的自適應直方圖均衡。在學習這個之前,我們要先學習一下下面的前置算法:

  1. 【Contrast Stretching】:對比度拉伸;
  2. 【HE】:直方圖均衡;
  3. 【CLHE】:對比度限制的HE
  4. 【AHE】:自適應直方圖均衡化

2 競賽中的CLAHE實現

在比賽中,我們往往使用albumentations庫函數進行圖像的預處理,因爲這個預處理庫的運行速度非常的快,而且封裝了大量的圖像增強的方法。圖像任務的話這個庫函數非常滴奈斯。

本文中會介紹一下albumentations庫函數實現CLAHE的代碼,然後再用openCV實現。

import albumentations
RESIZE_SIZE = 1024 # or 768
train_transform = albumentations.Compose([
        albumentations.Resize(RESIZE_SIZE, RESIZE_SIZE),
        albumentations.OneOf([
            albumentations.RandomGamma(gamma_limit=(60, 120), p=0.9),
            albumentations.RandomBrightnessContrast(brightness_limit=0.2, contrast_limit=0.2, p=0.9),
            albumentations.CLAHE(clip_limit=4.0, tile_grid_size=(4, 4), p=0.9),
        ]),
        albumentations.HorizontalFlip(p=0.5),
        albumentations.ShiftScaleRotate(shift_limit=0.2, scale_limit=0.2, rotate_limit=20,
                                        interpolation=cv2.INTER_LINEAR, border_mode=cv2.BORDER_CONSTANT, p=1),
        albumentations.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225), max_pixel_value=255.0, p=1.0)
    ])

這是一個圖像增強的pipline,其中的流程是:

  • Resize就是拉伸圖片修改尺寸
  • RandomGamma就是使用gamma變換
  • RandomBrightnessContrast就是隨機選擇圖片的對比度和亮度
  • CLAHE是一種對比度受限情況下的自適應直方圖均衡化算法
  • HorizontalFlip水平翻轉
  • ShiftScaleRotate這個就是平移縮放旋轉三合一,給力!
  • Normalize這個就是圖像歸一化了。

本文主要講解的就是CLAHE這個直方圖均衡化的算法。

3 openCV繪製直方圖

使用openCV的代碼來獲取一個圖片的灰度直方圖:

import cv2
import numpy as np
import matplotlib.pyplot as plt

def plot(grayHist):
    plt.plot(range(256), grayHist, 'r', linewidth=1.5, c='red')
    y_maxValue = np.max(grayHist)
    plt.axis([0, 255, 0, y_maxValue]) # x和y的範圍
    plt.xlabel("gray Level")
    plt.ylabel("Number Of Pixels")
    plt.show()

if __name__ == "__main__":
    # 讀取圖像並轉換爲灰度圖
    img = cv2.imread(r'E:\dog.jpg', 0)
    # 圖像的灰度級範圍是0~255
    grayHist = cv2.calcHist([img], [0], None, [256], [0, 256])

    # 繪製直方圖
    plot(grayHist)

狗子的圖片就是左邊的這個,發現灰度值在100左右的像素個數最多:

4 對比度Contrast

在生活中,我們在PS圖片的時候,往往會用到圖片對比度,那麼這個究竟是什麼東西呢?

圖片對比度指的是一幅圖片中最亮的白和最暗的黑之間的反差大小。常用的定量度量方法是Michelson對比度
\(C = \frac{I_{max}-I_{min}}{I_{max}+I_{min}}\)

  • 當一幅圖像最白和最黑像素灰度都是128時,圖像對比度最低,C=0;
  • 當一幅圖像最白像素灰度=255,最黑像素灰度=0時,圖像對比度最高,C=1.0。

【英文中如何描述高對比度與低對比度的?】
當一幅圖像最白和最黑像素灰度都在128附近浮動時,圖像的直方圖集中在中間的幾個桶,圖像看起來灰濛濛的,英語中使用dull描述這種效果。相反,如果圖像中黑白像素的跨度較大,則圖像富有通透感,英語中使用clarity描述這種效果。

圖片中左邊的圖片就是dull,灰度直方圖也是集中在中間區域,這就是低對比度;最右邊的圖片是clarity,直方圖感覺是被拉開了、舒展了,這就是高對比度

5 Contrast Stretching

我們已經搞懂了圖片不通透的原因,就是灰度直方圖不夠舒展,集中在了一個小區域,這樣我們可以通過數學的方法把低對比度的圖像提高對比度。最簡單的方法就是對比度拉伸(Contrast Stretching)


現在有這樣的一個低對比度的圖片,其灰度直方圖集中在中間的區域。然後我們想把這個灰度直方圖拉伸到整個0~255的區間,我們怎麼做呢?(這裏假設這個低對比度的圖片的灰度集中在100到200之間好了)


用一個這樣的分段線性函數,來處理上面那個低對比度圖片的時候,可以把(r2,s2)極端的設置成(100,0),把(r3,s3)設置成(200,255),這樣把原來的直方圖通過這個函數映射,其實就是把100~200範圍線性拉伸到0~255這麼大。

這種方法最簡單,簡單的說就是線性拉伸直方圖。對於某些圖片可以起到效果:

但是對於比較複雜的圖片,並沒有什麼效果:

6 Histogram Equalization

對比度解決不了的問題,我們來用HE試試。Histogram Equalization的思想就是用數學方法重新調整像素的亮度分佈,來保證直方圖具有最大的動態範圍,也就是儘可能地讓灰度直方圖是一個矩形!

其實Contrast Stretching也是做的一樣的事情,只是它用的簡單的分段線性函數來重新映射灰度,現在用更巧妙地方法。

【定義一些數學符號】

  • \(p(x)\):調整之前的直方圖的概率密度函數
  • \(q(y)\):調整之後的直方圖的概率密度函數,可以看出來,是一個常數,所以用C來表示

因爲不管怎麼轉換,概率密度函數的累積總是1,而轉換前後的取值範圍都是[0,1],所以可以得到:
\(\int_0^1{p(x)dx=\int_0^1Cdy=1}\)
(當然,這裏可以很快的算出來,C=1)

我們希望找到,一個x和y的映射關係,也就是\(y=f(x)\)不難想到,這個\(f(x)\)就應該是\(p(x)\)的累積分佈函數,也就是:
\(f(x)=\int_0^xp(u)du\)


這個圖中,直觀的展示了,任何一個直方圖,只要按照該直方圖的累積分佈函數進行拉伸,就可以得到一個矩形的直方圖。

下面是一個利用這樣的方法增強對比度的例子:

可以發現,在直方圖密集的地方,就會被拉的鬆散

再看另外一個例子:

可以發現,使用HE之後的直方圖的累積分佈函數,是一個直線

7 CLAHE

HE算法在一種情況下,效果不好,如果一個圖片中有大塊的暗區或者亮區的話,效果非常不好。這個的原因,也非常好理解,因爲HE其實要求一個圖片中必須有10%的最亮的像素點,必須有10%第二亮的像素點,必須有10%第三亮的像素點……假設有一張純黑的圖片,你想想經過HE處理之後,會出現什麼情況?答案就是一部分黑的像素也會被強行搞成白的

下面是一個例子,發現經過HE之後的圖片出現了大量噪點:

【Histogram Equalization的缺點】

  1. 對於灰度非常集中的區域,直方圖會被拉的非常稀疏,從而導致對比度增強過大,成爲噪音;
  2. 一些區域調整後丟失細節

7.1 Contrast Limited HE

針對第一個問題,提出了CLHE,加入對比度限制,其實原理很簡單置直方圖分佈的閾值,將超過該閾值的分佈“均勻”分散至概率密度分佈上,由此來限制轉換函數(累計直方圖)的增幅。

這樣的話,直方圖就不會出現概率密度函數過大的區域,從而避免了某些集中區域被拉得過於係數。

7.2 Adaptive HE

Adaptive HE的基本思想是將原始圖片劃分成子區域,然後對每個子區域進行HE變換。 當然,這樣做的問題應該是顯而易見的:

每一塊區域之間都會有非常大的不連續。因此爲了解決這個問題,提出了優化方案雙線性插值的AHE ,然後這個基礎上再使用CLHE的截斷對比度的思想,就變成了我們現在的CLAHE算法。

【使用雙線性插值的方案】

  1. 將圖像分爲多個矩形塊大小,對於每個矩形塊子圖,分別計算其灰度直方圖和對應的變換函數(累積直方圖)

  2. 將原始圖像中的像素按照分佈分爲三種情況處理:

    • 紅色區域中的像素按照其所在子圖的變換函數進行灰度映射
    • 綠色區域中的像素按照所在的兩個相鄰子圖變換函數變換後進行線性插值得到
    • 紫色區域中的像素按照其所在的四個相鄰子圖變換函數變換後雙線性插值得到

8 結果對比與openCV實現

【這裏是openCV實現HE的方法】

img = cv.imread(r'E:\dog.jpg', 0)
equ = cv.equalizeHist(img)  # 輸入爲灰度圖
res = np.hstack((img, equ))  # stacking images side-by-side
cv.imwrite('res.png',res)

運行結果:

【openCV實現CLAHE】

img = cv2.imread(r'E:\dog.jpg', 0)

# create a CLAHE object
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
cl1 = clahe.apply(img)
res = np.hstack((img, cl1))
cv2.imwrite('res.jpg', res)

結果是:


【更多對比的例子】

  • 左邊是原圖
  • 中間是HE,有過亮過暗的區域;
  • 右邊是CLAHE,沒有過亮過暗的區域。

然後我在另外一個博文,找到了上面那個例子的彩色版本哈哈:

參考文章:

  1. https://zhuanlan.zhihu.com/p/98541241
  2. https://blog.csdn.net/lwx309025167/article/details/103770834
  3. https://blog.csdn.net/u013066730/article/details/82970380
  4. https://www.cnblogs.com/imageshop/archive/2013/04/07/
  5. http://helloworld2020.net/393/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章