当前位置:   article > 正文

直方图的均衡化(Python)_numpy 直方图均衡化

numpy 直方图均衡化

这篇文章介绍在Python中使用OpenCV和NumPy对直方图进行均衡化处理。

本文内容:
1、使用查找表拉伸直方图
2、使用OpenCV和NumPy的函数以不同的方式进行直方图均衡化
在某些情况下,一副图像中大部分像素的强度都集中在某一区域,而质量较高的图像中,像素的强度应该均衡的分布。为此,可将表示像素强度的直方图进行拉伸,将其平坦化。如下:
这里写图片描述

实验数据

这里写图片描述

直方图:

这里写图片描述

使用查找表来拉伸直方图

在图像处理中,直方图均衡化一般用来均衡图像的强度,或增加图像的对比度。在介绍使用直方图均衡化来拉伸图像的直方图之前,先介绍使用查询表的方法。

观察上图中原始图像的直方图,很容易发现大部分强度值范围都没有用到。因此先检测图像非0的最低(imin)强度值和最高(imax)强度值。将最低值imin设为0,最高值imax设为255。中间的按255.0*(i-imin)/(imax-imin)+0.5)的形式设置。

代码:

minBinNo, maxBinNo = 0, 255  

#计算从左起第一个不为0的直方图位置  
for binNo, binValue in enumerate(hist):  
    if binValue != 0:  
        minBinNo = binNo  
        break  
#计算从右起第一个不为0的直方图位置  
for binNo, binValue in enumerate(reversed(hist)):  
    if binValue != 0:  
        maxBinNo = 255-binNo  
        break  
print minBinNo, maxBinNo  

#生成查找表,方法来自参考文献1第四章第2节  
for i,v in enumerate(lut):  
    print i  
    if i < minBinNo:  
        lut[i] = 0  
    elif i > maxBinNo:  
        lut[i] = 255  
    else:  
        lut[i] = int(255.0*(i-minBinNo)/(maxBinNo-minBinNo)+0.5)  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

查询表创建完成后,就直接调用相应的OpenCV函数即可,这里调用的是cv2.LUT函数:

#计算  
result = cv2.LUT(image, lut) 
  • 1
  • 2

cv2.LUT函数只有两个参数,分别为输入图像和查找表,其返回处理的结果,完整代码如下:

#coding=utf-8  
import cv2  
import numpy as np  

image = cv2.imread("D:/test/unequ.jpg", 0)  
lut = np.zeros(256, dtype = image.dtype )#创建空的查找表  
hist= cv2.calcHist([image], #计算图像的直方图  
    [0], #使用的通道  
    None, #没有使用mask  
    [256], #it is a 1D histogram  
    [0.0,255.0])  

minBinNo, maxBinNo = 0, 255  

#计算从左起第一个不为0的直方图柱的位置  
for binNo, binValue in enumerate(hist):  
    if binValue != 0:  
        minBinNo = binNo  
        break  
#计算从右起第一个不为0的直方图柱的位置  
for binNo, binValue in enumerate(reversed(hist)):  
    if binValue != 0:  
        maxBinNo = 255-binNo  
        break  
print minBinNo, maxBinNo  

#生成查找表,方法来自参考文献1第四章第2节  
for i,v in enumerate(lut):  
    print i  
    if i < minBinNo:  
        lut[i] = 0  
    elif i > maxBinNo:  
        lut[i] = 255  
    else:  
        lut[i] = int(255.0*(i-minBinNo)/(maxBinNo-minBinNo)+0.5)  

#计算  
result = cv2.LUT(image, lut)  
cv2.imshow("Result", result)  
cv2.imwrite("LutImage.jpg", result)  
cv2.waitKey(0)  
cv2.destroyAllWindows()  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

直方图结果如下,可以看到原来占的区域很小的直方图尖峰被移动了:
这里写图片描述

效果图:
这里写图片描述

直方图均衡化

有时图像的视觉上的缺陷并不在强度值集中在很窄的范围内。而是某些强度值的使用频率很大。比如第一幅图中,灰度图中间值的占了很大的比例。

在完美均衡的直方图中,每个柱的值都应该相等。即50%的像素值应该小于128,25%的像素值应该小于64。总结出的经验可定义为:在标准的直方图中p%的像素拥有的强度值一定小于或等于255×p%。将该规律用于均衡直方图中:强度i的灰度值应该在对应的像素强度值低于i的百分比的强度中。因此,所需的查询表可以由下面的式子建立:

[python] view plain copy
lut[i] = int(255.0 *p[i]) #p[i]是是强度值小于或等于i的像素的数目。
  • 1
  • 2

p[i]即直方图累积值,这是包含小于给点强度值的像素的直方图,以代替包含指定强度值像素的数目。比如第一幅图像的累计直方图如下图中的蓝线:
这里写图片描述

而完美均衡的直方图,其累积直方图应为一条斜线,如上图中均衡化之后的红线。

更专业一点,这种累积直方图应称为累积分布(cumulative distribition)。在NumPy中有一个专门的函数来计算。这在NumPy实现直方图均衡化一节中介绍。

通过上面的介绍,应该可以明白,直方图均衡化就是对图像使用一种特殊的查询表。在第三个例子中可以看到使用查询表来获得直方图均衡化的效果。通常来说,直方图均衡化大大增加了图像的表象。但根据图像可视内容的不同,不同图像的直方图均衡化产生的效果不尽相同。

直方图均衡化之OpenCV函数实现
用OpenCV实现直方图均衡化很简单,只需调用一个函数即可:

img = cv2.imread('图像路径',0)  
equ = cv2.equalizeHist(img)  
cv2.imshow('equ',equ)  
  • 1
  • 2
  • 3

这样图像就均衡化了。可以通过直方图的计算与显示这篇文章中介绍的方法将结果绘制出来。

直方图均衡化之NumPy函数实现

通过前面的介绍,可以明白直方图均衡化就是用一种特殊的查找表来实现的。所以这里用NumPy函数,以查找表的方式手动实现图像直方图的均衡化:

#coding=utf-8  
import cv2  
import numpy as np  

image = cv2.imread("D:/test/unequ.jpg", 0)  

lut = np.zeros(256, dtype = image.dtype )#创建空的查找表  

hist,bins = np.histogram(image.flatten(),256,[0,256])   
cdf = hist.cumsum() #计算累积直方图  
cdf_m = np.ma.masked_equal(cdf,0) #除去直方图中的0值  
cdf_m = (cdf_m - cdf_m.min())*255/(cdf_m.max()-cdf_m.min())#等同于前面介绍的lut[i] = int(255.0 *p[i])公式  
cdf = np.ma.filled(cdf_m,0).astype('uint8') #将掩模处理掉的元素补为0  

#计算  
result2 = cdf[image]  
result = cv2.LUT(image, cdf)  

cv2.imshow("OpenCVLUT", result)  
cv2.imshow("NumPyLUT", result2)  
cv2.waitKey(0)  
cv2.destroyAllWindows()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

效果图:
这里写图片描述

本博客转载:http://blog.csdn.net/sunny2038/article/details/9403059再次谢谢博主。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/661416
推荐阅读
相关标签
  

闽ICP备14008679号