数字图像直方图均衡化python

直方图均衡化

先来看一看效果图:
在这里插入图片描述

数字图像

数字图像,大家应该都有些概念,以前的相片都是通过相机使用胶片来曝光,胶片上面的感光物质,当光线照射到上面的时候,就会形成曝光点。一个图像映射进去过后,就在底片中形成了图片,得到了胶片后,我们还需要经过特殊的处理(洗胶片),才能得到我的照片。
但是现在的图像都是通过数字化处理后存放在内存中,里面都是数字图像。就比如二进制图像,0代表黑色,1代表白色,这样以一个二维矩阵形式存放在内存中。而彩色图像就比较复杂一点儿(我们现在所说的彩色图像就是RGB图像),RGB图像的存储形式我放在了我的另一个博客中:
RGB等图片的图像插值算法python实现
在这个链接里面,感觉还是比较清晰的,有一些图片可以帮助理解三维的RGB图像。

什么是图像里面的直方图?

数字图像的直方图,直方图是多空间域处理技术的基础,直方图操作可以作用于图像增强。书上的定理比较正式,需要自己转进去理解。这里说说我自己的理解吧,先引用冈萨雷斯的《数字图像处理》原文:
在这里插入图片描述
其实说白了就是数学里面的直方图统计。采用数组读取出来的图片(单通道)其实就是一个二维数组,二维数组里面每一个数就是一个灰度级(灰度级越大亮度越大,范围是:0~255,8bit图像)。
请看下面这副图片:
在这里插入图片描述
里面的数就是读取一张图片的结果(一张彩色图片的第0通道),里面的数就是0~255之间,好了我们现在有这个概念了。
接下来我们就对里面的每一个灰度级进行统计,比如我们要对灰度级12进行统计,统计这个数组里面出现了多少个12这个灰度级,使用统计回来的不同灰度级所对应的个数画成统计直方图,这就是图片的直方图。
下面看一下怎么对一张图片中的数据进行概率统计,直接看核心代码:

hist = defaultdict(lambda: 0)  # 定义一个字典,用来存放统计完灰度级的个数
        for i in range(size_h):
            for j in range(size_w):
                hist[img[i, j]] += 1

我们对图像的每一个像素点进行遍历,统计完后存放在这个hist字典里面,字典里面的key就是0~255的灰度级

下面来看一下没有进行直方图均衡化的数字图像是什么样子的,这里我还是引用冈萨雷斯的《数字图像处理》中所讲到的的:
在这里插入图片描述

归一化

使用概率分布来说,对于这个图片样本,灰度级为12的概率就是刚才我们算出来的统计数除以所有的样本点(M*N)。把整个图片中的所有灰度级都进行统计计算,这样我们就会得到每一个灰度级的概率统计,然后把这所有的概率统计画出直方统计图,就得到了数字图像的直方图(归一化后的直方图)。
归一化就是把这些统计回来的数据都除以256,因为有256个灰度级嘛,所以除以256后就对数据进行了归一化,这既是对直方图进行归一化。

直方图均衡化

连续

在这里插入图片描述

离散

离散的变换形式,这也是接下来我们索所要用到的公式。
在这里插入图片描述
下面给出均衡化的代码,其中参数color_pic=True表示我们传进去的是一个彩色图片,对于灰度图片也是可以进行均衡化的。

       def equalize_histogram_pic(img, color_pic=True):
        """直方图均衡化"""
        hist = Histogram.get_histogram(img, color_pic=color_pic)  # 获取实例化对象传进来的图片,获取得到它的直方图
        size_h, size_w= img.shape[0], img.shape[1]
        MN = size_h * size_w  # 获取到M*N

        new_gray_level = defaultdict(lambda: 0)  # 定义一个字典,用来存放灰度级的均衡化变换映射
        print("we are equalizing...")
        for i in range(256):
            for key in range(i + 1):
                new_gray_level[i] += hist[key]  # 把前i项灰度级值都加在第i灰度级中
            new_gray_level[i] = new_gray_level[i] * 255 / MN  # 将第i灰度级数量拿出来,乘上255/MN,就可以把Sk的映射结果存到字典中,就是书上那一个Sk的离散计算公式
            new_gray_level[i] = round(new_gray_level[i])  # 把灰度值进行四舍五入进行均衡化映射

        # 将新的灰度映射关系进行从原图像到均衡化图像进行映射
        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_gray_level[new_img[i, j, 0]]  # 将新的灰度映射关系进行从原图像到均衡化图像进行映射
        print('The equalizing ok')
        return new_img

下面是均衡化后的结果:
在这里插入图片描述
原图中较黑的部分均衡化后,我们看起来就更加清晰了。接下来看看他们的直方图。
来看看怎么将统计回来的字典里面的统计图画出来,看下面代码:

 pic = cv2.imread(r'./bridge.jpg')
    hist1 = Histogram.get_histogram(pic, color_pic=True)
    x_axis1 = range(0, 256)
    y_axis1 = list(map(lambda i: hist1[i], x_axis1))
    fig = plt.figure(num='histogram', figsize=(10, 5))
    plot1 = fig.add_subplot(121)
    plot1.set_title('origin picture histogram')
    plot1.plot(x_axis1, y_axis1)
    plot1.grid()

附件

下面附上我的全部代码:

import matplotlib.pyplot as plt
import numpy as np
from collections import defaultdict
import cv2
import logging


class Histogram(object):
    def __int__(self):
        pass

    def get_histogram(img_x, *, color_pic=True, normalized=False):
        if color_pic:             # color_pic 用来指定是个彩色图片
            img = img_x[:, :, 0]  # 只取出彩色图像的第0通道
        else:
            img = img_x
        size_h, size_w = img.shape
        logging.info(fr'size_h: {size_h}, size_w: {size_w}')
        print(fr'size_h: {size_h}, size_w: {size_w}')
        hist = defaultdict(lambda: 0)  # 定义一个字典,用来存放统计完灰度级的个数
        for i in range(size_h):
            for j in range(size_w):
                hist[img[i, j]] += 1

        # 根据normalized参数决定是否进行归一化
        if normalized:
            sum = 0
            MN = size_h * size_w
            for key in hist:
                hist[key] = hist[key] / MN
                sum += hist[key]
            logging.info(f'归一化后的值为:{sum},归一化后的统计值:{hist}')
            print('归一化后的和:', sum)
            del sum
            logging.info(f'统计回来的数值:{hist}')

        return hist

    # @staticmethod
    def equalize_histogram_pic(img, color_pic=True):   # color_pic 用来指定是个彩色图片
        """直方图均衡化"""
        hist = Histogram.get_histogram(img, color_pic=color_pic)  # 获取实例化对象传进来的图片,获取得到它的直方图
        size_h, size_w= img.shape[0], img.shape[1]
        MN = size_h * size_w  # 获取到M*N

        new_gray_level = defaultdict(lambda: 0)  # 定义一个字典,用来存放灰度级的均衡化变换映射
        print("we are equalizing...")
        for i in range(256):
            for key in range(i + 1):
                new_gray_level[i] += hist[key]  # 把前i项灰度级值都加在第i灰度级中
            new_gray_level[i] = new_gray_level[i] * 255 / MN  # 将第i灰度级数量拿出来,乘上255/MN,就可以把Sk的映射结果存到字典中,就是书上那一个Sk的离散计算公式
            new_gray_level[i] = round(new_gray_level[i])  # 把灰度值进行四舍五入进行均衡化映射

        # 将新的灰度映射关系进行从原图像到均衡化图像进行映射
        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_gray_level[new_img[i, j, 0]]  # 将新的灰度映射关系进行从原图像到均衡化图像进行映射
        print('The equalizing ok')
        return new_img

if __name__ == '__main__':
    pic = cv2.imread(r'./bridge.jpg')
    hist1 = Histogram.get_histogram(pic, color_pic=True)
    x_axis1 = range(0, 256)
    y_axis1 = list(map(lambda i: hist1[i], x_axis1))
    fig = plt.figure(num='histogram', figsize=(10, 5))
    plot1 = fig.add_subplot(121)
    plot1.set_title('origin picture histogram')
    plot1.plot(x_axis1, y_axis1)
    plot1.grid()

    # new_pic 的直方图
    new_pic = Histogram.equalize_histogram_pic(pic, color_pic=True)
    hist2 = Histogram.get_histogram(new_pic, color_pic=True)
    x_axis2 = range(0, 256)
    y_axis2 = list(map(lambda i: hist2[i], x_axis2))
    plot2 = fig.add_subplot(122)
    plot2.set_title('equalized picture histogram')
    plot2.plot(x_axis2, y_axis2)
    plot2.grid()

    # 均衡化
    # cv2.imshow('origin picture', pic)
    # new_pic = Histogram.equalize_histogram_pic(pic, color_pic=True)
    # print(new_pic.shape)
    # cv2.imshow('equalized picture', new_pic)

    plt.show()
  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值