圖像加強 | CLAHE 限制對比度自適應直方圖均衡化

1 基本概述

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

CLAHE起到的做用簡單來講就是加強圖像的對比度的同時能夠抑制噪聲算法

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

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

2 競賽中的CLAHE實現

在比賽中,咱們每每使用albumentations庫函數進行圖像的預處理,由於這個預處理庫的運行速度很是的快,並且封裝了大量的圖像加強的方法。圖像任務的話這個庫函數很是滴奈斯。dom

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

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左右的像素個數最多:

spa

4 對比度Contrast

在生活中,咱們在PS圖片的時候,每每會用到圖片對比度,那麼這個到底是什麼東西呢?.net

圖片對比度指的是一幅圖片中最亮的白和最暗的黑之間的反差大小。經常使用的定量度量方法是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/



相關文章
相關標籤/搜索