zoukankan      html  css  js  c++  java
  • 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()
    
    
    

  • 相关阅读:
    php自动跳转中英文页面
    如何让一个层关闭之后,就算刷新页面了也不显示。除非关闭页面再次打开
    彻底杜绝warning: Cannot add header information headers already sent in......
    大三了
    X牛人關於編程語錄
    C++虚函数表解析
    epoll:Edge or Level Triggered
    LRU和LFU的区别
    会话、进程组与僵死进程
    Effective C++学习笔记:确定基类有虚析构函数
  • 原文地址:https://www.cnblogs.com/juicebox/p/9775883.html
Copyright © 2011-2022 走看看