直方圖是對數據進行統計的一種方法,並且將統計值組織到一系列實現定義好的bin當中。其中bin為直方圖中經常使用的一個概念,可以譯為“直條”或“組距”,其數值是從數據中計算出的特征統計量,這些數據可以是諸如梯度、方向、色彩或其他任何特征。
圖像直方圖(Image Histogram)是用來表示數字圖像中亮度分布的直方圖,標繪了圖像中每個亮度值的像素個數。這種直方圖中,橫坐標的左側為較暗的區域。因此一張較暗的圖片直方圖中的數據多集中於左側和中間部分,而整體明亮,只有少量陰影的圖像則相反。
注意:直方圖是根據灰度圖繪制的,而不是彩色圖像。假設有一張圖像的信息(灰度值0-255),已知數字的范圍包含256個值,於是可以按照一定規律將這個范圍分割成子區域(也就是bins)。如:
然後再統計每一個bin(i)的像素數目。可以得到下圖(其中x軸表示bin,y軸表示各個bin中的像素個數):
這裡需要注意一下直方圖描述中的一些專業術語:
dims:需要統計的特征數目,在上述例子中,dims=1,因為僅表示了灰度值
bins:每個特征空間子區段的數目,可譯為“直條”或“組距”,在上例中,bins=16
range:要統計特征的取值范圍。在上例中,range = [0,255]
直方圖的意義:
直方圖是圖像中像素強度分布的圖形表達形式
它統計了每一個強度值所具有的像素個數
不同的圖像的直方圖可能是相同的。
我們一般使用opencv中的方法統計直方圖,並使用matplotlib將其繪制出來。
API:
cv2.calcHist(images,channels,mask,histSize,ranges[,hist[,accumulate]])
參數:
images: 原圖像。當傳入函數時應該用中括號 [] 括起來,例如:[img]。
channels: 如果輸入圖像是灰度圖,它的值就是 [0];如果是彩色圖像的話,傳入的參數可以是 [0],[1],[2] 它們分別對應著通道 B,G,R。
mask: 掩模圖像。要統計整幅圖像的直方圖就把它設為 None。但是如果你想統計圖像某一部分的直方圖的話,你就需要制作一個掩模圖像,並使用它。(後邊有例子)
histSize:BIN 的數目。也應該用中括號括起來,例如:[256]。
ranges: 像素值范圍,通常為 [0,256]
代碼示例:
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
# 1 直接以灰度圖的方式讀入
img = cv.imread('./image/cat.jpeg',0)
# 2 統計灰度圖
histr = cv.calcHist([img],[0],None,[256],[0,256])
# 3 繪制灰度圖
plt.figure(figsize=(10,6),dpi=100)
plt.plot(histr)
plt.grid()
plt.show()
掩膜是用選定的圖像、圖形或物體,對要處理的圖像進行遮擋,來控制圖像處理的區域。
在數字圖像處理中,我們通常使用二維矩陣數組進行掩膜。掩膜是由0和1組成一個二進制圖像,利用該掩膜圖像要處理的圖像進行掩膜,其中1值的區域被處理,0值區域被屏蔽,不會處理。
掩膜的主要用途是:
1、提取感興趣區域:用預先制作的感興趣區掩模與待處理圖像進行”與“操作,得到感興趣區圖像,感興趣區內圖像值保持不變,而區外圖像值都為0。
2、屏蔽作用:用掩模對圖像上某些區域作屏蔽,使其不參加處理或不參加處理參數的計算,或僅對屏蔽區作處理或統計。
3、結構特征提取:用相似性變量或圖像匹配方法檢測和提取圖像中與掩模相似的結構特征。
4、特殊形狀圖像制作
掩膜在遙感影像處理中使用較多,當提取道路或者河流、或者房屋時,通過一個掩膜矩陣來對圖像進行像素過濾,然後將我們需要的地物或者標志突出顯示出來。
我們使用cv.calcHist()來查找完整圖像的直方圖。 如果要查找圖像某些區域的直方圖,只需在要查找直方圖的區域上創建一個白色的掩膜圖像,否則創建黑色, 然後將其作為掩碼mask傳遞即可。
代碼示例:
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
# 1. 直接以灰度圖的方式讀入
img = cv.imread('./image/cat.jpeg',0)
# 2. 創建蒙版
mask = np.zeros(img.shape[:2], np.uint8)
mask[400:650, 200:500] = 255
# 3.掩模
masked_img = cv.bitwise_and(img,img,mask = mask)
# 4. 統計掩膜後圖像的灰度圖
mask_histr = cv.calcHist([img],[0],mask,[256],[1,256])
# 5. 圖像展示
fig,axes=plt.subplots(nrows=2,ncols=2,figsize=(10,8))
axes[0,0].imshow(img,cmap=plt.cm.gray)
axes[0,0].set_title("原圖")
axes[0,1].imshow(mask,cmap=plt.cm.gray)
axes[0,1].set_title("蒙版數據")
axes[1,0].imshow(masked_img,cmap=plt.cm.gray)
axes[1,0].set_title("掩膜後數據")
axes[1,1].plot(mask_histr)
axes[1,1].grid()
axes[1,1].set_title("灰度直方圖")
plt.show()
想象一下,如果一副圖像中的大多數像素點的像素值都集中在某一個小的灰度值值范圍之內會怎樣呢?如果一幅圖像整體很亮,那所有的像素值的取值個數應該都會很高。所以應該把它的直方圖做一個橫向拉伸(如下圖),就可以擴大圖像像素值的分布范圍,提高圖像的對比度,這就是直方圖均衡化要做的事情。
“直方圖均衡化”是把原始圖像的灰度直方圖從比較集中的某個灰度區間變成在更廣泛灰度范圍內的分布。直方圖均衡化就是對圖像進行非線性拉伸,重新分配圖像像素值,使一定灰度范圍內的像素數量大致相同。
這種方法提高圖像整體的對比度,特別是有用數據的像素值分布比較接近時,在X光圖像中使用廣泛,可以提高骨架結構的顯示,另外在曝光過度或不足的圖像中可以更好的突出細節。
使用opencv進行直方圖統計時,使用的是:
API:
dst = cv.equalizeHist(img)
參數:
img: 灰度圖像
返回:
dst : 均衡化後的結果
代碼示例:
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
# 1. 直接以灰度圖的方式讀入
img = cv.imread('./image/cat.jpeg',0)
# 2. 均衡化處理
dst = cv.equalizeHist(img)
# 3. 結果展示
fig,axes=plt.subplots(nrows=2,ncols=2,figsize=(10,8),dpi=100)
axes[0].imshow(img,cmap=plt.cm.gray)
axes[0].set_title("原圖")
axes[1].imshow(dst,cmap=plt.cm.gray)
axes[1].set_title("均衡化後結果")
plt.show()
上述的直方圖均衡,我們考慮的是圖像的全局對比度。 的確在進行完直方圖均衡化之後,圖片背景的對比度被改變了,在貓腿這裡太暗,我們丟失了很多信息,所以在許多情況下,這樣做的效果並不好。如下圖所示,對比下兩幅圖像中雕像的畫面,由於太亮我們丟失了很多信息。
為了解決這個問題, 需要使用自適應的直方圖均衡化。 此時, 整幅圖像會被分成很多小塊,這些小塊被稱為“tiles”(在 OpenCV 中 tiles 的 大小默認是 8x8),然後再對每一個小塊分別進行直方圖均衡化。 所以在每一個的區域中, 直方圖會集中在某一個小的區域中)。如果有噪聲的話,噪聲會被放大。為了避免這種情況的出現要使用對比度限制。對於每個小塊來說,如果直方圖中的 bin 超過對比度的上限的話,就把 其中的像素點均勻分散到其他 bins 中,然後在進行直方圖均衡化。
最後,為了 去除每一個小塊之間的邊界,再使用雙線性差值,對每一小塊進行拼接。
API:
cv.createCLAHE(clipLimit, tileGridSize)
參數:
clipLimit: 對比度限制,默認是40
tileGridSize: 分塊的大小,默認為8*88∗8
代碼示例
import numpy as np
import cv2 as cv
# 1. 以灰度圖形式讀取圖像
img = cv.imread('./image/cat.jpeg',0)
# 2. 創建一個自適應均衡化的對象,並應用於圖像
clahe = cv.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
cl1 = clahe.apply(img)
# 3. 圖像展示
fig,axes=plt.subplots(nrows=1,ncols=2,figsize=(10,8),dpi=100)
axes[0].imshow(img,cmap=plt.cm.gray)
axes[0].set_title("原圖")
axes[1].imshow(cl1,cmap=plt.cm.gray)
axes[1].set_title("自適應均衡化後的結果")
plt.show()
直方圖是圖像中像素強度分布的圖形表達方式。
它統計了每一個強度值所具有的像素個數。
不同的圖像的直方圖可能是相同的
cv.calcHist(images,channels,mask,histSize,ranges [,hist [,accumulate]])
這一部分我還沒有搞特別懂,等之後搞懂,會再把這裡優化一下。