灰度直方圖
介紹
實現
以下代碼便於理解灰度直方圖的計算,其中histogram函數是基於numpy簡化的,運行結果如下。
# coding: utf8 from skimage import data import matplotlib.pyplot as plt import numpy as np def histogram(a, bins=10, range=None): """ Compute the histogram of a set of data. """ import numpy as np from numpy.core import linspace from numpy.core.numeric import (arange, asarray) # 轉成一維數組 a = asarray(a) a = a.ravel() mn, mx = [mi + 0.0 for mi in range] ntype = np.dtype(np.intp) n = np.zeros(bins, ntype) # 預計算直方圖縮放因子 norm = bins / (mx - mn) # 均分,計算邊緣以進行潛在的校正 bin_edges = linspace(mn, mx, bins + 1, endpoint=True) # 分塊對於大數組可以降低運行內存,同時提高速度 BLOCK = 65536 for i in arange(0, len(a), BLOCK): tmp_a = a[i:i + BLOCK] tmp_a_data = tmp_a.astype(float) # 減去Range下限,乘以縮放因子,向下取整 tmp_a = tmp_a_data - mn tmp_a *= norm indices = tmp_a.astype(np.intp) # 對indices標簽分別計數,標簽等於bins減一 indices[indices == bins] -= 1 n += np.bincount(indices, weights=None, minlength=bins).astype(ntype) return n, bin_edges if __name__ =="__main__": img=data.coffee() fig = plt.figure() f1 = fig.add_subplot(141) f1.imshow(img) f1.set_title("image") f2 = fig.add_subplot(142) arr=img.flatten() n, bins, patches = f2.hist(arr, bins=256, facecolor='red') f2.set_title("plt_hist") f3 = fig.add_subplot(143) hist, others = np.histogram(arr, range=(0, arr.max()), bins=256) f3.plot(others[1:],hist) f3.set_title("np_hist1") f4 = fig.add_subplot(144) hist, others = histogram(arr, range=(0, arr.max()), bins=256) f4.plot(others[1:], hist) f4.set_title("np_hist2") plt.show()
關於bincount函數,可以參考Xurtle的博文https://blog.csdn.net/xlinsist/article/details/51346523
bin的數量比x中的最大值大1,每個bin給出了它的索引值在x中出現的次數。下面,我舉個例子讓大家更好的理解一下:
# 我們可以看到x中最大的數為7,因此bin的數量為8,那么它的索引值為0->7 x = np.array([0, 1, 1, 3, 2, 1, 7]) # 索引0出現了1次,索引1出現了3次......索引5出現了0次...... np.bincount(x) #因此,輸出結果為:array([1, 3, 1, 1, 0, 0, 0, 1]) # 我們可以看到x中最大的數為7,因此bin的數量為8,那么它的索引值為0->7 x = np.array([7, 6, 2, 1, 4]) # 索引0出現了0次,索引1出現了1次......索引5出現了0次...... np.bincount(x) #輸出結果為:array([0, 1, 1, 0, 1, 0, 1, 1])下面,我來解釋一下weights這個參數。文檔說,如果weights參數被指定,那么x會被它加權,也就是說,如果值n發現在位置i,那么out[n] += weight[i]而不是out[n] += 1.因此,我們weights的大小必須與x相同,否則報錯。下面,我舉個例子讓大家更好的理解一下:
w = np.array([0.3, 0.5, 0.2, 0.7, 1., -0.6]) # 我們可以看到x中最大的數為4,因此bin的數量為5,那么它的索引值為0->4 x = np.array([2, 1, 3, 4, 4, 3]) # 索引0 -> 0 # 索引1 -> w[1] = 0.5 # 索引2 -> w[0] = 0.3 # 索引3 -> w[2] + w[5] = 0.2 - 0.6 = -0.4 # 索引4 -> w[3] + w[4] = 0.7 + 1 = 1.7 np.bincount(x, weights=w) # 因此,輸出結果為:array([ 0. , 0.5, 0.3, -0.4, 1.7])最后,我們來看一下minlength這個參數。文檔說,如果minlength被指定,那么輸出數組中bin的數量至少為它指定的數(如果必要的話,bin的數量會更大,這取決於x)。下面,我舉個例子讓大家更好的理解一下:
# 我們可以看到x中最大的數為3,因此bin的數量為4,那么它的索引值為0->3 x = np.array([3, 2, 1, 3, 1]) # 本來bin的數量為4,現在我們指定了參數為7,因此現在bin的數量為7,所以現在它的索引值為0->6 np.bincount(x, minlength=7) # 因此,輸出結果為:array([0, 2, 1, 2, 0, 0, 0]) # 我們可以看到x中最大的數為3,因此bin的數量為4,那么它的索引值為0->3 x = np.array([3, 2, 1, 3, 1]) # 本來bin的數量為4,現在我們指定了參數為1,那么它指定的數量小於原本的數量,因此這個參數失去了作用,索引值還是0->3 np.bincount(x, minlength=1) # 因此,輸出結果為:array([0, 2, 1, 2])
直方圖均衡化
直方圖均衡化是一種通過使用圖像直方圖,調整對比度的圖像處理方法;通過對圖像的強度(intensity)進行某種非線性變換,使得變換后的圖像直方圖為近似均勻分布,從而,達到提高圖像對比度和增強圖片的目的。普通的直方圖均衡化采用如下形式的非線性變換:
設 f 為原始灰度圖像,g 為直方圖均衡化的灰度圖像,則 g 和 f 的每個像素的映射關系如下:
其中,L 為灰度級,通常為 256,表明了圖像像素的強度的范圍為 0 ~ L-1;
pn 等於圖像 f 中強度為 n 的像素數占總像素數的比例,即原始灰度圖直方圖的概率密度函數;
fi,j 表示在圖像 f 中,第 i 行,第 j 列的像素強度;gi,j 表示在圖像 g 中,第 i 行,第 j 列的像素強度.
Python代碼
實現如下,代碼和圖片轉自https://www.cnblogs.com/klchang/p/9872363.html
運行結果為
從輸出看,將原來0-255的灰度范圍差異放大,起到了增強對比的效果。
#!/usr/bin/env python # -*- coding: utf8 -*- """ # Author: klchang # Date: 2018.10 # Description: histogram equalization of a gray image. """ from __future__ import print_function import numpy as np import matplotlib.pyplot as plt def histequ(gray, nlevels=256): # Compute histogram histogram = np.bincount(gray.flatten(), minlength=nlevels) print ("histogram: ", histogram) # Mapping function uniform_hist = (nlevels - 1) * (np.cumsum(histogram)/(gray.size * 1.0)) uniform_hist = uniform_hist.astype('uint8') print ("uniform hist: ", uniform_hist) # Set the intensity of the pixel in the raw gray to its corresponding new intensity height, width = gray.shape uniform_gray = np.zeros(gray.shape, dtype='uint8') # Note the type of elements for i in range(height): for j in range(width): uniform_gray[i,j] = uniform_hist[gray[i,j]] return uniform_gray if __name__ == '__main__': fname = "../320px-Unequalized_Hawkes_Bay_NZ.png" # Gray image # Note, matplotlib natively only read png images. gray = plt.imread(fname, format=np.uint8) if gray is None: print ("Image {} does not exist!".format(fname)) exit(-1) # Histogram equalization uniform_gray = histequ(gray) # Display the result fig, (ax1, ax2) = plt.subplots(1, 2) ax1.set_title("Raw Image") ax1.imshow(gray, 'gray') ax1.set_xticks([]), ax1.set_yticks([]) ax2.set_title("Histogram Equalized Image") ax2.imshow(uniform_gray, 'gray') ax2.set_xticks([]), ax2.set_yticks([]) fig.tight_layout() plt.show() """ histogram: [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 1 1 1 2 2 2 6 9 10 17 33 34 35 55 69 95 122 188 206 249 312 349 485 644 798 1042 1285 1536 1807 2241 2542 2921 2862 2586 2398 2259 2092 1897 1986 1860 1724 1782 1673 1772 1632 1670 1716 1595 1478 1466 1271 1197 1066 1028 908 827 807 764 671 606 547 461 417 414 379 347 273 290 273 207 226 198 184 158 171 149 122 133 144 126 137 135 121 118 133 137 158 153 147 138 161 126 128 97 96 46 47 41 37 26 14 10 7 12 6 2 5 3 1 1 0 1 0 0 0 0 1 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] uniform hist: [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 2 3 4 5 6 8 10 13 17 22 28 35 43 53 63 74 84 93 101 109 116 124 131 137 144 150 157 163 169 175 181 187 192 197 202 206 209 213 216 219 222 224 227 229 230 232 233 235 236 237 238 239 240 241 242 242 243 244 244 245 245 246 246 247 247 248 248 249 249 250 250 251 251 252 252 253 253 254 254 254 254 254 254 254 254 254 254 254 254 254 254 254 254 254 254 254 254 254 254 254 254 254 254 254 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255] """