S0.6 直方图均衡化

S0.6 直方图均衡化


  • 直方图均衡化能提高图像的质量

累积直方图

这是后面均衡化所要知道的先验知识。

如果说直方图统计的是等于像素值的数量,那么累积直方图统计的就是小于等于像素值的数量

均衡化步骤

我们均衡化的目标就是把灰度直方图变得平坦,那么什么是最平坦的直方图呢?当然就是下图这样:

4X4的图像,每个像素有4个,按概率论的角度来讲,这是均匀分布。

我们一般用和概率相关的直方图来表示,像这样:

我们希望直方图都像均匀分布的直方图那样,可以换种思路:只要任何直方图的累积直方图像均匀分布的累积直方图那样(即阶梯型),我们同样可以使直方图均匀分布。

假设我们有如下直方图:

首先,我们说明灰度直方图均衡化可能会发生的事:

  1. 相邻的两个像素可能会合并为一个,其后所有的像素值向前移一格。如图:

图1的像素值0和1由于太小而合并,小的具体判断标准是少于累积灰度直方图的\(\frac{k}{N}\),N为原像素种类,这里为8(其实可以取更大的任何值),k为第几个柱子,这里是第1个,具体看例子。

  1. 可能会空出一个像素区域。

当某一个像素的数量太大时,(例如图中的像素值6),它的前面往往会空出一个像素区域,以平衡该区域。(在直方图中我们假设不做分离,把像素值当做一个整体,不把同一像素值的数量分为两份,但可以合并不同像素值的数量)

例子

实际操作我们是看累积直方图,一个一个柱子分析并建立像素映射关系表。

第一个柱子为像素值0,它的值为0.02,小于\(\frac{1}{8}\)=0.125,大于\(\frac{0}{8}\)=0,于是把它映射到0。(需要说明的是,本例子像素值正好是0,1,2,3……,要是像素值不是这样,读者可以想想)

第二个柱子为像素值1,它的值为0.06,小于\(\frac{1}{8}\)=0.125,大于\(\frac{0}{8}\)=0.125,于是把它映射到0。

第三个柱子为像素值2,它的值为0.16,小于\(\frac{2}{8}\)=0.25,大于\(\frac{1}{8}\)=0.125,于是把它映射到1。

第四个柱子为像素值3,它的值为0.28,小于\(\frac{3}{8}\)=0.375,大于\(\frac{2}{8}\)=0.25,于是把它映射到2。

第五个柱子为像素值4,它的值为0.42,小于\(\frac{4}{8}\)=0.5,大于\(\frac{3}{8}\)=0.375,于是把它映射到3。

第六个柱子为像素值5,它的值为0.62,小于\(\frac{5}{8}\)=0.625,大于\(\frac{4}{8}\)=0.5,于是把它映射到4。

第七个柱子为像素值6,它的值为0.84,小于\(\frac{7}{8}\)=0.875,大于\(\frac{6}{8}\)=0.75,于是把它映射到6。

第八个柱子为像素值7,它的值为1,等于\(\frac{8}{8}\)=1,于是把它映射到7。

映射表f->g如下:

f 0 1 2 3 4 5 6 7
g 0 0 1 2 3 4 6 7

我们根据映射关系得到新的均衡化直方图:(横坐标变成g)

我想你应该已经懂了-。-

算法代码演示

我们统计图片0-255的灰度,然后均衡化这个灰度图。

from cv2 import *
import numpy as np
import matplotlib.pyplot as plt

src = imread(r"images/favorite/Lena.jpg",0)
dst = src.copy()
hist_array = [0 for i in range(256)]

for i in range(src.shape[0]):
    for j in range(src.shape[1]):
        hist_array[src[i,j]] += 1


hist_sum_array = [hist_array[i] for i in range(256)]

for i in range(1, len(hist_array)):
    hist_sum_array[i] += hist_sum_array[i-1]

print(hist_array)
# print(hist_sum_array)

plt.figure()
plt.subplot(2,2,3)

width = 0.35
index = np.arange(0, 256, 1)

plt.bar(index, hist_array, width, color = "#87CEFA")

plt.xlabel("f")
plt.ylabel("c(f)")
plt.xticks(np.arange(0, 300, 60))
plt.yticks(np.arange(0, 1000, 100))

plt.subplot(2,2,4)

k = 0
eta = 1.0
map = [i for i in range(256)]

for i in range(256):
    while hist_sum_array[i]/256 - k*eta > 0:
        k+=1
    map[i] = k
    if map[i] == 256:
        map[i] = 255
print(map)


for k in range(256):
    # print(dst[0])
    # print(k,"->",map[k])
    for i in range(dst.shape[0]):
        for j in range(dst.shape[1]):
            if(src[i,j] == k):
                dst[i,j] = map[k]

# for i in range(dst.shape[0]):
#     print(dst[i])

hist_array = [0 for i in range(256)]
for i in range(dst.shape[0]):
    for j in range(dst.shape[1]):
        hist_array[dst[i,j]] += 1
print(hist_array)

plt.bar(index, hist_array, width, color="#87CEFA")
plt.xlabel("g")
plt.ylabel("c(g)")
plt.xticks(np.arange(0, 300, 60))
plt.yticks(np.arange(0, 1000, 100))

plt.subplot(221), plt.imshow(src,'gray'), plt.title('Origin')
plt.subplot(222), plt.imshow(dst,'gray'), plt.title('Equalize')

plt.show()

OpenCV函数实现

参考https://blog.csdn.net/yjp19871013/article/details/78232726

OpenCV均衡方法有两种,第一种(全局直方图均衡化)属于本文提到的方法,即使某一像素过大也不会把它减少,第二种(限制对比度的自适应直方图均衡化)方法会把过大像素减少。

from cv2 import *
import matplotlib.pyplot as plt

src = imread(r"images/favorite/Lena.jpg",0)
hist = calcHist([src], [0], None, [256], [0,256])


equ_src = equalizeHist(src)
equ_hist = calcHist([equ_src], [0], None, [256], [0,256])


clahe = createCLAHE(clipLimit=3.0)
clahe_src = clahe.apply(src)
clahe_hist = calcHist(clahe_src, [0], None, [256], [0, 256])


plt.subplot(231), plt.imshow(src,'gray'), plt.title('Origin')
plt.subplot(232), plt.imshow(equ_src,'gray'), plt.title('Equalize')
plt.subplot(233), plt.imshow(clahe_src,'gray'), plt.title('Clahe')

plt.subplot(234)
plt.hist(hist.flatten(), 256, [0, 256], color='b')
plt.title('Origin Hist')

plt.subplot(235)
plt.hist(equ_hist.flatten(), 256, [0, 256], color='b')
plt.title('Equalize Hist')

plt.subplot(236)
plt.hist(clahe_hist.flatten(), 256, [0, 256], color='b')
plt.title('Equalize Hist')
plt.show()

猜你喜欢

转载自www.cnblogs.com/juicebox/p/9775883.html