圖像處理6 灰度直方圖和直方圖均衡化


灰度直方圖

介紹

灰度直方圖(Gray histogram)是關於灰度級分布的函數,是對圖像中灰度級分布的統計。灰度直方圖是將數字圖像中的所有像素,按照灰度值的大小,統計其出現的頻率。灰度直方圖是灰度級的函數,它表示圖像中具有某種灰度級的像素的個數,反映了圖像中某種灰度出現的頻率。
如果將圖像總像素亮度(灰度級別)看成是一個隨機變量,則其分布情況就反映了圖像的統計特性,這可用probability density function (PDF)來刻畫和描述,表現為灰度直方圖。

實現

以下代碼便於理解灰度直方圖的計算,其中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)進行某種非線性變換,使得變換后的圖像直方圖為近似均勻分布,從而,達到提高圖像對比度和增強圖片的目的。普通的直方圖均衡化采用如下形式的非線性變換:

  設 為原始灰度圖像,為直方圖均衡化的灰度圖像,則 和 的每個像素的映射關系如下:

 

  

  其中,L 為灰度級,通常為 256,表明了圖像像素的強度的范圍為 0 ~ L-1;

  p等於圖像 中強度為 n 的像素數占總像素數的比例,即原始灰度圖直方圖的概率密度函數;

  fi,j 表示在圖像 中,第 i 行,第 j 列的像素強度;gi,j 表示在圖像 中,第 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]
"""

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM