图像增强 -- 直方图均衡化及其python实现

直方图均衡化及其python实现

#数字图像处理

文章目录

  • 直方图均衡化及其python实现
    • 展示效果
    • 理论简介
      • 什么是直方图
      • 均衡化
      • 流程图:
      • 代码:

这里贴一下 我最近数字图像学习阶段写的代码 – github 仓库。有机会一起学习。

展示效果

先上一下均衡化的效果:

图像增强 -- 直方图均衡化及其python实现_第1张图片
图像增强 -- 直方图均衡化及其python实现_第2张图片

左图是均衡化之前,右图是均衡化之后。

理论简介

注意这里只是对直方图均衡化进行一个简要介绍,详细的理论基础,支撑希望从书中找答案。
代码在最下面,没有使用 opencv,主要基于numpy,这里主要方便我之后回顾以及同我一样的初学者整理。

什么是直方图

先引出《数字图像处理-第三版-冈萨雷斯》中3.3节第一段对直方图的介绍,我再简单介绍一下。
图像增强 -- 直方图均衡化及其python实现_第3张图片

简单来说,直方图可以看做对一副灰度图像每个像素的灰度值进行统计,计算每一个灰度级的像素个数。

比方说下面这样一个用矩阵表示的 8x8 图像,每一个位置的数字对于该位置像素的灰度值。(一副单通道灰度图,本身可以看做一个对应分辨率的矩阵,比如一个 128x128 分辨率的单通道灰度图,可以看做一个128x128 的矩阵,空间域的处理本质上可以看做对这个矩阵的处理)。

图像增强 -- 直方图均衡化及其python实现_第4张图片
对矩阵中每个数字(即灰度值)进行统计出现的次数,得到:

r 0 r_0 r0 r 1 r_1 r1 r 2 r_2 r2 r 3 r_3 r3 r 4 r_4 r4 r 5 r_5 r5 r 6 r_6 r6 r 7 r_7 r7
8 0 0 0 31 16 8 1

再根据以上表格数据建立类似于柱状图的直方图即可,需要注意的是,上表中出现次数为 0 的灰度值也要再图中表现出来。

均衡化

原始图像可能显得较暗或者太亮,导致图像辨识效果不好。图像较暗或者较亮在直方图上具体体现在,直方图的分量主要集中在高区间和低区间。如下图(图片取自《数字图像处理-第三版-冈萨雷斯》-p144)
图像增强 -- 直方图均衡化及其python实现_第5张图片

均衡化的目的即使尽可能的让直方图的分量,在整个灰度范围内均匀(均衡)分布。这样使得图像的对比度较高。比如上图中的最后一副。

对比度:我们定义一幅图像中最高和最低灰度级间的灰度差为对比度。

这里根据这个公式来计算(即下面提到的 3.3-8式):

以及整个例子:
图像增强 -- 直方图均衡化及其python实现_第6张图片

图像增强 -- 直方图均衡化及其python实现_第7张图片

流程图:

图像增强 -- 直方图均衡化及其python实现_第8张图片

代码:

from collections import defaultdict

import numpy as np
import matplotlib.image as mpimg    # 用于读取
import matplotlib.pyplot as plt     # 用于显示
import logging


logging.basicConfig(level=logging.INFO)

# 直方图均衡化
class Histogram(object):
    def __init__(self):
        pass
    # 显示直方图
    def showByHistogram(hist,*,title = ''):
        x_axis = range(0,256)
        y_axis = list(map(lambda x : hist[x] ,x_axis))

        fig = plt.figure(num = title)
        plot_1 = fig.add_subplot(111)
        plot_1.set_title(title)
        plot_1.plot(x_axis,y_axis)
        plt.show()
        del fig

    def show(img,*,title = ''):
        # 只取单通道
        img = img[:,:,0]
        size_h,size_w= img.shape
        logging.info(f' size_h :{size_h} size_w:{size_w} MN:{size_w*size_h}')

        hist = defaultdict(lambda: 0)

        for i in range(size_h):
            for j in range(size_w):
                hist[img[i,j]] += 1
        x_axis = range(0,256)
        y_axis = list(map(lambda x : hist[x] ,x_axis))

        fig = plt.figure(num = title)
        plot_1 = fig.add_subplot(111)
        plot_1.set_title(title)
        plot_1.plot(x_axis,y_axis)
        plt.show()
        del fig
    # 获取直方图,参数Normalized 决定是否归一化
    def get_histogram(img ,*,Normalized = False):
        # 只取 0 通道,若本身只有一个通道不会有影响
        img = img[:,:,0]
        size_h,size_w = img.shape
        logging.info(f' size_h :{size_h} size_w:{size_w} MN:{size_w*size_h}')

        hist = defaultdict(lambda: 0)
        
        for i in range(size_h):
            for j in range(size_w):
                hist[img[i,j]] += 1
                
        # 根据 Normalized 参数决定是否进行归一化
        if Normalized == True:
            sum = 0
            MN = size_h * size_w
            for pixel_value in hist: # Key 迭代
                hist[pixel_value] = hist[pixel_value]/MN
                sum += hist[pixel_value]
            logging.info(f'归一化后加和为:{sum}')
            del sum
        return hist
    # 直方图均衡化函数
    def equalization(img):
        size_h,size_w,size_c = img.shape
        hist = Histogram.get_histogram(img)
        MN = size_h * size_w
        new_hist = defaultdict(lambda: 0)
        # 公式 3.3-8 计算 S_k
        for i in range(0,256):
            for pixel in range(i+1):
                new_hist[i] += hist[pixel]
            new_hist[i] = new_hist[i] * 255/MN
        
        for key in new_hist:
            new_hist[key] = round(new_hist[key])
        new_img = img.copy()
        
        for i in range(new_img.shape[0]):
            for j in range(new_img.shape[1]):
                new_img[i,j] = new_hist[new_img[i,j,0]]

        return new_img
    pass

if __name__ == '__main__':

    pic1 = mpimg.imread('.\hw2_picture1.jpg')  # 读取图像
    # Histogram.show(pic1,title='pic1_Histogram')
    # Histogram.showByHistogram(Histogram.get_histogram(pic1,Normalized=True),title='pic1_Histogram')
    # Histogram.get_histogram(pic1,Normalized=True)

    # Histogram.show(pic1,title='pic1_Histogram')

    new_pic = Histogram.equalization(pic1)
    plt.imshow(pic1)
    plt.axis('off')
    plt.show()
    plt.imshow(new_pic)
    plt.axis('off')
    plt.show()

    Histogram.show(pic1,title='pic1_Histogram')
    Histogram.show(new_pic,title='pic1_Histogram after equalization')
    mpimg.imsave(r'.\output_HistogramEqualization.png',new_pic)


你可能感兴趣的:(数字图像处理,图像处理)