我們之前對直方圖有一個大概的了解,它可以将圖像的不同顔色的像素值在坐标上表示出來,現在我們來讨論直方圖的均衡化,在基本概念的基礎上來進行實戰化。
假設有一個圖像,其像素值僅局限于某些特定範圍的值。舉個例子,其比較明亮的圖像區域所有的像素僅局限于高值,但實際上一個好的圖像,其像素會來源于圖像上的所有區域。是以我們需要拉伸/伸展直方圖,這也是直方圖均衡化所做的。而這樣的做法通常也可以優化圖像的對比度:
這種方法通常用來增加許多圖像的全局對比度,尤其是當圖像的有用資料的對比度相當接近的時候。通過這種方法,亮度可以更好地在直方圖上分布。這樣就可以用于增強局部的對比度而不影響整體的對比度,直方圖均衡化通過有效地擴充常用的亮度來實作這種功能。
這種方法對于背景和前景都太亮或者太暗的圖像非常有用,這種方法尤其是可以帶來X光圖像中更好的骨骼結構顯示以及曝光過度或者曝光不足照片中更好的細節。這種方法的一個主要優勢是它是一個相當直覺的技術并且是可逆操作,如果已知均衡化函數,那麼就可以恢複原始的直方圖,并且計算量也不大。
這種方法的一個缺點是它對處理的資料不加選擇,它可能會增加背景噪聲的對比度并且降低有用信号的對比度。
原理
現在我們拿到一個256圖像,我們知道什麼?
1、像素值是0-255,即能表達256種顔色.
2、我們能統計出各個像素值的像素個數.即我們知道原圖的機率分布
3、我們希望生成的新圖的像素值的機率分布是平均分布的.
我們要求的是一個函數T,可以使得像素分布從下面左圖變成右圖.其中L是像素值的最大值+1:
我們根據一道數學題來進行推導:
很簡單,已知x的機率分布,及x,y的轉換關系,可以求得y的機率分布。F_x(x) 就相當于已知的第二點,即原始圖檔的像素的機率分布,F_Y(y)就相當于已知的第三點,即轉換後的圖檔的像素要均勻分布,現在要求的是y = T(x)的這個T是什麼樣的,這樣就可以把原圖的像素x,轉換成均衡化後的圖檔的像素y。根據上面的數學題,我們可以繼續推導,得到s和r的關系.即我們所要求的轉換函數T:
以上,就是做直方圖均衡化的數學原理。
OpenCV直方圖均衡化
直方圖均衡化的三種情況,分别是:
- 灰階圖像直方圖均衡化
- 彩色圖像直方圖均衡化
- YUV 直方圖均衡化
先來看灰階直方圖均衡化,我們輸入一個灰階圖像就可以,函數原型:
dst=cv.equalizeHist(src[, dst])
參數為輸入的圖像。
代碼:
view plaincopy to clipboardprint?
def grayequal(img):
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
dst = cv2.equalizeHist(gray)
cv2.imshow("res", gray)
cv2.imshow("dst", dst)
cv2.waitKey(0)
cv2.destroyWindow()
我們再來看看彩色圖像的均值化,彩色圖像的直方圖均衡化和灰階圖像略有不同,需要将彩色圖像先用split()方法,将三個通道拆分,然後分别進行均衡化.最後使用merge()方法将均衡化之後的三個通道進行合并.操作如下:
view plaincopy to clipboardprint?
def colorequal(img):
(b, g, r) = cv2.split(img)
bH = cv2.equalizeHist(b)
gH = cv2.equalizeHist(g)
rH = cv2.equalizeHist(r)
# 合并每一個通道
result = cv2.merge((bH, gH, rH))
cv2.imshow("img",img)
cv2.imshow("dst", result)
cv2.waitKey(0)
繼續看YUV圖像直方圖均值化:
view plaincopy to clipboardprint?
def yuvequal(img):
imgYUV = cv2.cvtColor(img, cv2.COLOR_BGR2YCrCb)
cv2.imshow("src", img)
channelsYUV = cv2.split(imgYUV)
channelsYUV[0] = cv2.equalizeHist(channelsYUV[0])
channels = cv2.merge(channelsYUV)
result = cv2.cvtColor(channels, cv2.COLOR_YCrCb2BGR)
cv2.imshow("dst", result)
cv2.waitKey(0)
自适應直方圖均值化
我們剛剛看到的第一個直方圖均衡化,考慮了的是圖像的全局對比度。在很多情況下,這并不是一個好的處理方法。例如,下圖顯示了一個輸入圖像及其經過全局直方圖均衡後的結果:
直方圖均衡化後的背景對比度确實有所提高,但是讓我們比較兩幅圖中雕像的臉,由于亮度過高,我們丢失了臉部的大部分資訊。這是因為它的直方圖并不像我們在前面的例子中看到的那樣局限于一個特定的區域。
為了解決這一問題,我們可以采用自适應的直方圖均衡化。在這個方法中,圖像會被劃分為稱為“tiles”的小塊 (在OpenCV中,tileSize預設為8x8)。然後像先前一樣對每個塊進行直方圖均衡。
那麼現在在一個小區域内,直方圖會被限制在一個小區域内(排除有噪聲的情況);如果有噪音,區域會被放大。為了避免這種情況,我們可以應用對比度限制 contrast limiting。
如果任何直方圖中的bin 高于指定的對比度限制 (OpenCV中預設bin 為40),則可以在應用直方圖均衡化之前,将這些像素剪切并均勻分布到其他bin 中。在均勻化後,再采用雙線性插值bilinear interpolation 的方法來去除tiles 小塊邊界中的後天的人工痕迹。
我們來看代碼:
view plaincopy to clipboardprint?
import numpy as np
import cv2
img = cv2.imread('tsukuba_l.png',0)
# 建立一個 CLAHE 對象 (Arguments 可寫可不寫)
# clipLimit顔色對比度的門檻值
# titleGridSize進行像素均衡化的網格大小,即在多少網格下進行直方圖的均衡化操作
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
cl1 = clahe.apply(img)
cv2.imwrite('clahe_2.jpg',cl1)
可以看到,圖像更加的清晰,事實上,我們稱之為——圖像銳化,它是由OpenCV中的直方圖操作完成的。
檢視文章彙總頁https://blog.csdn.net/weixin_44237705/article/details/107864965
更多openvino技術資訊可以入群交流~