栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

2021-10-10

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

2021-10-10

直方图均衡化的python实现

直方图均衡化是图像处理中非常经典的算法,作为图像处理的小白,我对算法进行了python语言的实现。代码中使用了大量的for循环,效率不是很高,但是笔者作为编程小白,还没有能力优化,所以请大家明白原理之后自己动手。

数学原理

其实本来不想讲数学原理,但是对于理解程序还是有帮助的,我是按照数学的推导步骤一步一步向下进行的。

首先考虑连续化灰度值,连续化灰度值便于数学表达式的推导

r 表示原图像的灰度值,其值域为 [0,L-1] r = 0 时像素为黑色,r = L-1 时像素为白色。
s 表示均衡化后图像的灰度值,在rs 之间存在某种映射关系,将此种关系表达为T,有下式:
s=T( r ),0≪r≪L-1
这里有两个要求:
1): T( r ) 在区间 0≪r≪L-1 上为单调递增函数。
2): 0≪T( r )≪L-1
条件1是为了保证输出灰度值不低于相应的输入值,防止灰度反变换时产生人为缺陷(个人理解:是为了保证不会出现图像灰度反转的情况,例如:映射是单调减函数,低灰度级会映射出高灰度级,这样将会造成部分或者整体灰度的反转,造成不良影响)。
条件2是为了保证输出灰度的范围与输入灰度的范围相同(个人理解:保证输出的图像位数是等于输入的图像位数,例如:256灰度级的图像是8位的图像,输入也应该是256灰度级8位图像)。
一幅图像的灰度级可视为区间固定在 [0,L-1] 的一个随机变量(连续性),对连续性的随机变量我们可以用概率密度函数来描述其数学表达,令 p_r ( r ) 表示随机变量 r 的概率密度函数,p_s (s) 同理。
p_r ( r ) 是原图像的概率密度函数(我们已经知道它的数学表达式),如果我们再知晓 T® 的表达形式,那么可以通过概率论里的:《连续性随机变量的函数的概率密度函数》的内容来得到 p_s (s) 因此我们有:p_s (s)=p_r ( r )*dr/ds
对于 T( r ) 我们有重要的变换函数(课本上给的,我也没找见出处):

这个变换满足条件1与条件2,所以我们可以用于图像的处理。
最终课本给出 p_s (s) 的概率密度函数(公式太长,有兴趣参考冈萨雷斯的数字图像处理课本:p_s (s)=1/(L-1),0≪r≪L-1
这说明:均衡化之后的随机变量s 由一个均匀PDF表征,它与 p_r ® 的表示形式无关。(这一点可以用在直方图规定化之中)

再考虑离散值,因为实际的应用我们对图像的处理都是离散的数字图像

对于离散值,我们处理其概率(直方图值)与求和来替代处理概率密度函数与积分。
一幅数字图像中灰度级 r_k出现的概率近似为:p_r (r_k )=n_k/MN ,k=0,1,2,3, …….,L-1 MN是图像的总像素,n_k 是灰度级 r_k 的像素的共个数,L是图像中可能的灰度级的数量(8位图像就是256)
最终:

这个公式是指导我们的工程实现的算法。

技术路线


使用的软件为vs code 。
使用的python库有: CV2,math,matplotlib.pyplot,numpy。不清楚的可以百度一下这些库是做什么的。

代码示例
import numpy as np
import matplotlib.pyplot as plt
import cv2
import math

# 定义函数,功能:展示图像灰度直方图
def Showhist(imgname):
    plt.hist(imgname.ravel(), bins=255, rwidth=0.8, range=(0, 255),density=True)     #设定坐标值域
    plt.xlabel('Gray value')                                                         #设定x轴名字
    plt.ylabel('number')                                                             #设定y轴名字
    plt.title(r'灰度图')                                                             #设定直方图名字
    plt.show()
# 定义函数,功能:展示图像
def Showimg(imgname):
    cv2.imshow('intput', imgname)                                                    #展示图片-imgname,窗口名为intput
    # 设定窗口等待任意按键之后被关闭,不然窗口自动关闭根本看不清
    cv2.waitKey(0)
    cv2.destroyAllWindows()

# 读取照片
img = cv2.imread(r"C:Usersli_leiDesktoppicturelena.jpg", cv2.IMREAD_GRAYSCALE)  #图片地址不能含中文

# 展示原图像
Showimg(img)

# 展示原图像灰度的直方图
Showhist(img)

img1=img.copy()                         #预设的输出图片
# 生成列表用来存储相关数据因为这个demo处理的是8位灰度图像,所以值都是256
hist1 = np.zeros(256, dtype=np.float32) #直方图统计结果-频次
Ph = np.zeros(256, dtype=np.float32)    #灰度频率
s = np.zeros(256, dtype=np.float32)     #均衡化之后的频率 
S = np.zeros(256, dtype=np.float32)     #均衡化之后的灰度级是浮点数
ABS = np.zeros(256, dtype=np.int)       #四舍五入之后的灰度级 
value=255                               #value的值取决于图像的位数,8位就是(256-1)
# 直方图统计
row, col = np.shape(img)
    # 灰度频次计算
for i in range(row):
        for j in range(col):
            hist1[img[i][j]] += 1
    # 灰度频率计算
for i in range(0,256):  
    Ph[i] = hist1[i]/(row*col) 
    # 均衡化之后的频率 
for i in range(1,256):
    s[0] = Ph[0]
    s[i] = (s[i-1]+Ph[i])
    # 均衡化之后的灰度级
for i in range(0,256):
    S[i]=value*s[i]
    # 四舍五入算法  对 ‘均衡化之后的灰度级’ 取整
for i in range(0,256):
    ABS[i]=math.ceil(S[i]-0.5)
    # 进行对文件的灰度值重写,这个功能比较重要 
for i in range(row):
    for j in range(col):
        img1[i,j]=ABS[img[i,j]]        #原图像某位置的灰度值经ABS[]的映射为新的灰度值,这个新的灰度值就是均衡化后的新图像的灰度值
                                       #本质是一个映射列表,原图像的灰度值是输入,是ABS[]的下标,ABS[]内存储的是‘均衡化之后的灰度级’,对于每个下标,都给出相应的值
Showimg(img1)
Showhist(img1)
# 保存图片
cv2.imwrite('ec_lena.jpg', img1)

我们使用lean图像

直方图为:

均衡化之后:

直方图为:

可以发现,虽然直方图不是完全的均衡,但是其效果已经展示出来了,笔者尝试对第二章lena图进行再次均衡化,

直方图为:

发现虽然直方图上更加均衡,但是效果不是特别明显。个人感觉进行二次均衡化的意义不是很大。

文章内照片素材来自网络,若有侵权,联系作者删除,对此给您造成的困扰道歉。
文章内代码内容为原创,仅提供给学习使用!文章写的比较仓促,如有错误,望诸位海涵,如能斧正

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/313745.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号