图像增强-直方图均衡化

图像增强-直方图均衡化

直方图定义

定义1

一个灰度级在范围 [ 0 , L − 1 ] [0,L-1] [0,L1]的数字图像的直方图是一个离散函数 h ( r k ) = n k h(r_k)=n_k h(rk)=nk

其中, n k n_k nk是图像中灰度级为 r k r_k rk的像素个数, r k r_k rk是第k个灰度级, k = 0 , 1 , 2 , . . . , L − 1 k=0,1,2,...,L-1 k=0,1,2,...,L1

由于 r k r_k rk的增量为1,直方图表示为: p ( k ) = n k p(k)=n_k p(k)=nk

定义2

一个灰度级在范围 [ 0 , L − 1 ] [0,L-1] [0,L1]的数字图像的直方图是一个离散函数 p ( r k ) = n k / n p(r_k)=n_k/n p(rk)=nk/n

其中, n n n是图像的像素总数, n k n_k nk是图像中灰度级为 r k r_k rk的像素个数, r k r_k rk是第k个灰度级, k = 0 , 1 , 2 , . . . , L − 1 k=0,1,2,...,L-1 k=0,1,2,...,L1

对比

对比上面两种定义,定义2将其映射至了[0,1]区间,函数值范围于像素总数无关,给出了灰度级 r k r_k rk在图像中的概率密度统计。

注意:直方图没有描述像素的空间关系,仅仅描述灰度级分布。

直方图均衡化

基本思想

希望一幅图像的像素占有全部可能的灰度级且分布均匀,能够具有高对比度

把原始图的直方图变换为均匀分布的形式,增加了像素灰度值的动态范围,从而达到增强图像整体对比度的效果。

其中,我们使用灰度级变换进行实现: s = T ( r ) ,   0 ≤ r ≤ 1 s=T(r),\ 0≤r≤1 s=T(r), 0r1

灰度级变换

T ( r ) T(r) T(r)满足两个条件:

  1. T ( r ) T(r) T(r)在区间 0 ≤ r ≤ 1 0≤r≤1 0r1中为单值单调递增

    保证原图各灰度级在变换后仍保持从黑到白/从白到黑的排列次序

  2. 0 ≤ r ≤ 1 0≤r≤1 0r1时, 0 ≤ T ( r ) ≤ 1 0≤T(r)≤1 0T(r)1

    保证变换前后灰度动态范围的一致性

均衡化计算

对于离散值: p r ( r k ) = n k n p_r(r_k)=\frac{n_k}{n} pr(rk)=nnk

为了将离散值的范围增大,分布更加均匀从而提高对比度,我们利用累加的方式,其变换函数的离散形式为:

s k = T ( r k ) = ( L − 1 ) ∑ j = 0 k p r ( r j ) = ( L − 1 ) ∑ j = 0 k n j n s_k=T(r_k)=(L-1)\sum_{j=0}^kp_r(r_j)=(L-1)\sum_{j=0}^k\frac{n_j}{n} sk=T(rk)=(L1)j=0kpr(rj)=(L1)j=0knnj

其中, k = 0 , 1 , . . . , L − 1 k=0,1,...,L-1 k=0,1,...,L1

通过 s k s_k sk,根据像素点的原灰度值k作为索引,可以得到对应的均衡化后的灰度值 s k s_k sk,从而得到均衡化后的图像

代码实现

导入一些库和函数:

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
%matplotlib inline

#释放窗口
def releaseWin():
    cv.waitKey(0)
    cv.destroyAllWindows()
    key = cv.waitKey(0)
    if key==27:
        print(key)
        cv.destroyAllWindows()
        
def plotHist(img, xstr='gray level'):
    h, w = img.shape[:2]
    histogram, _, _ = plt.hist(img.reshape([h * w, ]), bins=256,
                                  facecolor='black', histtype='bar')
    plt.xlabel(xstr)
    plt.ylabel("the number of pixels")
    plt.axis([0, 255, 0, np.max(histogram)])
    
    plt.show()

def plotPolyHist(img1, img2, img3, strs):
    h, w = img1.shape[:2]
    plt.figure(figsize=(20,5))
    plt.subplot(1,3,1)
    histogram, _, _ = plt.hist(img1.reshape([h * w, ]), bins=256,
                                  facecolor='black', histtype='bar')
    plt.xlabel(strs[0])
    
    plt.subplot(1,3,2)
    histogram, _, _ = plt.hist(img2.reshape([h * w, ]), bins=256,
                                  facecolor='black', histtype='bar')
    plt.xlabel(strs[1])
    
    plt.subplot(1,3,3)
    histogram, _, _ = plt.hist(img3.reshape([h * w, ]), bins=256,
                                  facecolor='black', histtype='bar')
    plt.xlabel(strs[2])
    
def Multiplot(img1, img2, img3, strs):
    plt.figure(figsize=(20,5))
    plt.subplot(1,3,1)
    plt.imshow(img1, cmap='gray')
    plt.xlabel(strs[0])
    
    plt.subplot(1,3,2)
    plt.imshow(img2, cmap='gray')
    plt.xlabel(strs[1])
    
    plt.subplot(1,3,3)
    plt.imshow(img3, cmap='gray')
    plt.xlabel(strs[2])
自己实现直方图均衡化
# 统计灰度直方图
def calcGrayHistNormal(I):
    hist = np.zeros(256)
    for i in range(I.shape[0]):
        for j in range(I.shape[1]):
            hist[I[i][j]] += 1
    return hist / (I.shape[0] * I.shape[1])
    
# 直方图均衡化
def myEqualizeHist(img):
    hist_sum, output_img = np.zeros(256), np.zeros_like(img)
    hist = calcGrayHistNormal(img)

    # 计算均衡后的直方图
    for i in range(256):
        hist_sum[i] = sum(hist[:i+1])
        hist_sum[i] = int(255 * hist_sum[i] + 0.5) # 放缩至[0,255]并四舍五入

    # 根据映射关系进行灰度图均衡化
    for i in range(img.shape[0]):
        for j in range(img.shape[1]):
            output_img[i][j] = hist_sum[img[i][j]]
    
    return output_img
    
hist_sum, output_img = np.zeros(256), np.zeros_like(img)
hist = calcGrayHist(img)

# 计算均衡后的直方图
for i in range(256):
    hist_sum[i] = sum(hist[:i+1])
    hist_sum[i] = int(255 * hist_sum[i] + 0.5) # 放缩至[0,255]并四舍五入

# 根据映射关系进行灰度图均衡化
for i in range(img.shape[0]):
    for j in range(img.shape[1]):
        output_img[i][j] = hist_sum[img[i][j]]
        
plt.imshow(output_img, cmap='gray')
opencv实现直方图均衡化

只需要一个cv.equalizeHist(img)即可实现。

对比自己的和opencv的效果
import os
import time
# 读取文件下的所有灰度图片
def readPathGrayPic(path):
    img_list, namelist = [], []
    for name in os.listdir(path):
        img = cv.imread(path+r'\\'+name, 0)
        img_list.append(img)
        namelist.append(name)
    return img_list, namelist

img_list, namelist = readPathGrayPic(r'C:\Users\admin\Desktop\Data\ComputerVision\exp1\testPic')
timeList1, timeList2 = [], []
for img in img_list:
    time1, time2 = 0, 0
    start = time.time()
    myoutput = myEqualizeHist(img)
    time1 = time.time() - start
    timeList1.append(time1)
    
    start = time.time()
    output = cv.equalizeHist(img)
    time2 = time.time() - start
    timeList2.append(time2)
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

路过的风666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值