直方图均衡化实现

原文链接:点击打开链接

相比C++而言,Python适合做原型。本系列的文章介绍如何在Python中用OpenCV图形库,以及与C++调用相应OpenCV函数的不同之处。这篇文章介绍在Python中使用OpenCV和NumPy对直方图进行均衡化处理。

提示:

本文内容:

  • 使用查找表拉伸直方图
  • 使用OpenCV和NumPy的函数以不同的方式进行直方图均衡化

在某些情况下,一副图像中大部分像素的强度都集中在某一区域,而质量较高的图像中,像素的强度应该均衡的分布。为此,可将表示像素强度的直方图进行拉伸,将其平坦化。如下:


图来自维基百科

实验数据

本节的实验数据来自维基百科,原图如下:

其直方图为:


使用查找表来拉伸直方图

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

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

实现的任务主要集中在查询表的创建中,代码如下:

  1. minBinNo, maxBinNo = 0, 255
  2. #计算从左起第一个不为0的直方图位置
  3. for binNo, binValue in enumerate(hist):
  4. if binValue != 0:
  5. minBinNo = binNo
  6. break
  7. #计算从右起第一个不为0的直方图位置
  8. for binNo, binValue in enumerate(reversed(hist)):
  9. if binValue != 0:
  10. maxBinNo = 255-binNo
  11. break
  12. print minBinNo, maxBinNo
  13. #生成查找表,方法来自参考文献1第四章第2节
  14. for i,v in enumerate(lut):
  15. print i
  16. if i < minBinNo:
  17. lut[i] = 0
  18. elif i > maxBinNo:
  19. lut[i] = 255
  20. else:
  21. lut[i] = int( 255.0*(i-minBinNo)/(maxBinNo-minBinNo)+ 0.5)
查询表创建完成后,就直接调用相应的OpenCV函数即可,这里调用的是cv2.LUT函数:
  1. #计算
  2. result = cv2.LUT(image, lut)

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

  1. #coding=utf-8
  2. import cv2
  3. import numpy as np
  4. image = cv2.imread( "D:/test/unequ.jpg", 0)
  5. lut = np.zeros( 256, dtype = image.dtype ) #创建空的查找表
  6. hist= cv2.calcHist([image], #计算图像的直方图
  7. [ 0], #使用的通道
  8. None, #没有使用mask
  9. [ 256], #it is a 1D histogram
  10. [ 0.0, 255.0])
  11. minBinNo, maxBinNo = 0, 255
  12. #计算从左起第一个不为0的直方图柱的位置
  13. for binNo, binValue in enumerate(hist):
  14. if binValue != 0:
  15. minBinNo = binNo
  16. break
  17. #计算从右起第一个不为0的直方图柱的位置
  18. for binNo, binValue in enumerate(reversed(hist)):
  19. if binValue != 0:
  20. maxBinNo = 255-binNo
  21. break
  22. print minBinNo, maxBinNo
  23. #生成查找表,方法来自参考文献1第四章第2节
  24. for i,v in enumerate(lut):
  25. print i
  26. if i < minBinNo:
  27. lut[i] = 0
  28. elif i > maxBinNo:
  29. lut[i] = 255
  30. else:
  31. lut[i] = int( 255.0*(i-minBinNo)/(maxBinNo-minBinNo)+ 0.5)
  32. #计算
  33. result = cv2.LUT(image, lut)
  34. cv2.imshow( "Result", result)
  35. cv2.imwrite( "LutImage.jpg", result)
  36. cv2.waitKey( 0)
  37. cv2.destroyAllWindows()
直方图结果如下,可以看到原来占的区域很小的直方图尖峰被移动了:


处理结果为:


关于直方图的绘制,请参考这篇文章

直方图均衡化

介绍

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

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

lut[i] = int(255.0 *p[i]) #p[i]是是强度值小于或等于i的像素的数目。
p[i]即直方图累积值,这是包含小于给点强度值的像素的直方图,以代替包含指定强度值像素的数目。比如第一幅图像的累计直方图如下图中的蓝线:


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

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

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

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

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

  1. img = cv2.imread( '图像路径', 0)
  2. equ = cv2.equalizeHist(img)
  3. cv2.imshow( 'equ',equ)
这样图像就均衡化了。可以通过 直方图的计算与显示 这篇文章中介绍的方法将结果绘制出来。

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

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

  1. #coding=utf-8
  2. import cv2
  3. import numpy as np
  4. image = cv2.imread( "D:/test/unequ.jpg", 0)
  5. lut = np.zeros( 256, dtype = image.dtype ) #创建空的查找表
  6. hist,bins = np.histogram(image.flatten(), 256,[ 0, 256])
  7. cdf = hist.cumsum() #计算累积直方图
  8. cdf_m = np.ma.masked_equal(cdf, 0) #除去直方图中的0值
  9. cdf_m = (cdf_m - cdf_m.min())* 255/(cdf_m.max()-cdf_m.min()) #等同于前面介绍的lut[i] = int(255.0 *p[i])公式
  10. cdf = np.ma.filled(cdf_m, 0).astype( 'uint8') #将掩模处理掉的元素补为0
  11. #计算
  12. result2 = cdf[image]
  13. result = cv2.LUT(image, cdf)
  14. cv2.imshow( "OpenCVLUT", result)
  15. cv2.imshow( "NumPyLUT", result2)
  16. cv2.waitKey( 0)
  17. cv2.destroyAllWindows()
最终结果


验证

比较查找表和OpenCV直方图均衡化生成的直方图:


可以看出,总体上来看是吻合的,但OpenCV中函数的实现 可能 还有一些细微的差别(有空去翻下源码,不过今天就先到这里了)。

参考资料:

1、《Opencv2 Computer Vision Application Programming Cookbook》

2、《OpenCV References Manule》

3、http://opencvpython.blogspot.com/2013/03/histograms-2-histogram-equalization.html

如果觉得本文写的还可以的话,请轻点“顶”,您的支持是我写下去的动力之一。未完待续。。。如有错误请指正,本人会虚心接受并改正!谢谢!

猜你喜欢

转载自blog.csdn.net/charlotte_android/article/details/80985268