基于numpy和opencv的数字图像处理(三):图像直方图

数字图像处理


Author:louwill

Machine Learning Lab

     简单而言,图像直方图就是图像中不同数值的像素出现的次数。只不过使用直方图的形式呈现更为直观。但如果从概率统计的角度来理解图像直方图,却又并不是那么容易掌握。

图像直方图

     参考以下四张不同灰度级的图像直方图:

     按照0-255的灰度级划分,图像直方图分布越靠近横坐标左端则图像越暗,越靠近横坐标右端则图像越亮。第一幅图图像较暗,直方图分布集中在左侧,第二幅图图像较亮,直方图分布集中于右侧。另外,低对比度的图像直方图分布较窄,高对比度的图像直方图分布较宽。若一幅图像的像素分布倾向于占据全部像素范围且分布均匀,则该图像会有高对比度且会有较为丰富的图像细节。

     先来看如何基于numpy和matplotlib绘制图像的直方图:

import cv2
import numpy as np
import matplotlib.pyplot as plt
# 读取图像
img = cv2.imread("harden.png")
# 直方图展示
plt.hist(img.ravel(), bins=255, rwidth=0.8, range=(0, 255))
plt.show();

     原图:

     直方图:

     opencv中也提供了直方图计算函数cv2.calcHist:

img = cv2.imread("harden.png")
hist = cv2.calcHist([img], [0], None, [256], [0,256])
plt.plot(hist)
plt.show();

     可以看到opencv绘制出来的直方图和numpy绘制一致。

直方图均衡

     直方图均衡就是将图像直方图变得更加平坦的一种操作,本质上可以理解为是一种分布变换。在图像处理中有经典的变换函数形式如下:

     其中T(r)为像素r的变换函数,L-1为像素取值上限,积分式表示随机变量r的累积分布函数。

     若一幅数字图像中像素r_k出现的概率近似为:

     其中MN是图像总像素,n_k为像素为r_k的像素个数。则经典变换函数的离散表达可写为:

     根据离散公式,我们可以基于numpy定义直方图均衡化函数如下:

def hist_equal(img, z_max=255):
    H, W, C = img.shape
    # 总像素数
    S = H * W * C * 1.
    out = img.copy()
    sum_h = 0.
    # 遍历所有像素
    for i in range(1, 255):
        # 计算像素为i的累积分布函数
        ind = np.where(img == i)
        sum_h += len(img[ind])
        z_prime = z_max / S * sum_h
        out[ind] = z_prime
    out = out.astype(np.uint8)
    return out

     测试效果如下:

img = cv2.imread("harden.png")
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 直方图均衡
out = hist_equal(img)
# 展示
plt.hist(out.ravel(), bins=255, rwidth=0.8, range=(0, 255))
plt.show();
plt.imshow(out);

     通过均衡化处理后图像直方图相较于原始图形像素分布要均衡许多。

     opencv对于图像直方图均衡有cv2.equalizeHist函数可以直接实现,但该操作不能直接对彩色图像进行处理,笔者查阅资料发现opencv的彩色图像直方图均衡一般有两种方法,一种是将BGR三个通道分开单独进行均衡化处理,完了之后再进行合并。另一种则是将BGR颜色空间变换到YUV颜色空间,然后再单独对Y通道进行均衡化处理。笔者实验后发现两种方法处理结果均有一些颜色畸变,下面提供三通道分开均衡方法参考:

import cv2
import numpy as np
img = cv2.imread("harden.png")
plt.imshow(img);
# 通道分开并对每一通道进行均衡
(b, g, r) = cv2.split(img)
bH = cv2.equalizeHist(b)
gH = cv2.equalizeHist(g)
rH = cv2.equalizeHist(r)
# 合并均衡化之后的RGB
result = cv2.merge((rH, gH, bH))
plt.imshow(result);



     可以看到,基于opencv的彩色图像直方图均衡相较于原始的numpy操作结果有一些区别,结果仅供大家参考。

参考资料:

冈萨雷斯 数字图像处理 第四版

https://github.com/yoyoyo-yo/Gasyori100knock

往期精彩:

2019,算法工程师第一年

基于numpy和opencv的数字图像处理(一):通道替换与灰度化


一个算法工程师的成长之路

长按二维码.关注机器学习实验室

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值