python的opencv操作记录(13)-增强之直方图均衡化

这篇具有很好参考价值的文章主要介绍了python的opencv操作记录(13)-增强之直方图均衡化。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


前段时间忙活深度网络和android的东西去了,好久没讲讲传统图像处理了,这一篇继续来说说opencv中的传统图像处理部分——图像增强之直方图增强。

图像增强是一种基本的图像处理操作,简单的来说就是把图像变的更清晰,或者说感兴趣的某个区域需要变的更加清晰。

而清晰度这个概念,在清晰度计算这一章节中提到过,一般来说,像素之间的梯度越大,图像就越清晰。

而直方图是用于统计像素分布的一个工具,计算每幅图像的直方图是传统图像处理中的一种基本操作,直方图表现了一张图像所有的像素的分布情况,直方图增强就是通过调整直方图的分布来实现图像的增强,简单的说就是把图像像素重新分布一下,提高图像中像素的整体梯度,让图像变得更清晰。

这个过程被称作直方图均衡化

附上之前直方图的基本计算方式:

https://blog.csdn.net/pcgamer/article/details/124989015?spm=1001.2014.3001.5501

清晰度计算:

https://blog.csdn.net/pcgamer/article/details/127942102?spm=1001.2014.3001.5501

直方图增强基本逻辑-均衡化

上面提到了均衡化的过程,其实就是把图像像素的分布改变一下。那么问题来了,怎么变?根据什么变?

首先来看一下opencv中的函数*equalizeHist()*的方式。

  • 首先说下累计分布函数CDF(cumulative distribution function),这个函数可以这么理解:

    • 直方图就是统计了某个灰度值的像素个数,比如灰度为100的像素个数有50个,总共有256中灰度值,那么可以记做:
      n 100 = 50 n_{100} = 50 n100=50
      ,或者是$ n_i = 100, i = 100, 0<i<255$

    • 归一化到[0, 1]的范围内,其实就是求这个灰度值出现的概率: p ( i ) = n i n p(i) = \frac{n_i}{n} p(i)=nni,n为像素总数。

    • 那么累计分布函数就是:
      H ( x ) = ∑ j = 1 i p x ( j ) H(x) = \sum_{j=1}^ip_x(j) H(x)=j=1ipx(j)
      也就是某个灰度值所有的累计分布,比如灰度值100的H(x)就是从0-100的所有灰度值概率分布之和。

    • 通过把每个点的像素值通过 H ( x ) H(x) H(x)来进行转换获得新的目标图像的灰度值。

  • 有意思的是为什么要这么进行转换,这个证明过程不复杂,可以简单列一列。

    • 首先可以认为原始图S,和目标图D。

    • 原始图S的直方图分布记做 H A ( S ) H_A(S) HA(S),目标图D的直方图分布记做 H B ( D ) H_B(D) HB(D)

    • 我们的目的就是要找到一个映射关系 f f f,可以把原始图S中的像素值映射到目标图D,也就是说 D = f ( S ) D = f(S) D=f(S)

    • 直方图归一化到[0, 1]后,实际上就是某个灰度值的概率,所有的概率之和都是等于。

    • 对于原图的直方图表示: ∑ 0 S H ( S ) \sum_0^SH(S) 0SH(S)就表示所有的概率之和。那么目标图的表示就是 ∑ 0 D H ( D ) \sum_0^DH(D) 0DH(D), 两者是相等的。可以表示为:
      ∑ 0 S H ( S ) = ∑ 0 D H ( D ) \sum_0^SH(S) = \sum_0^DH(D) 0SH(S)=0DH(D)

    • 最理想的目标图分布是均匀分布,也就是 H ( D ) = A N H(D) = \frac{A}{N} H(D)=NA, 其中的A表示每种像素值的值(每种都是相同的)。那么上面的公式就可以写成:
      ∑ 0 S H ( S ) = ∑ 0 D H ( D ) = D A N \sum_0^SH(S) = \sum_0^DH(D) = \frac{DA}{N} 0SH(S)=0DH(D)=NDA
      其中 D = f ( S ) D=f(S) D=f(S)
      所有有可以写成:
      ∑ 0 S H ( S ) = f ( S ) A N \sum_0^SH(S) = \frac{f(S)A}{N} 0SH(S)=Nf(S)A

      换一下项就可以得到:
      f ( S ) = N A ∑ 0 S H ( S ) f(S) = \frac{N}{A}\sum_0^SH(S) f(S)=AN0SH(S)

      最右边的那一坨中的H(S)就是上面提到的累积概率分布,只是这里要对整张图像的像素再做一次求和或者积分。

    • 具体怎么计算,这里就不说了,有兴趣的朋友可以去了解下。

    • 当然,这里有个问题,上面的理想状态是不太可能达到的,如果某些图像的直方图在某个小区域出现比较大的聚集的话,可能就没法非常好的进行平均分布了。

calcHist && equalizeHist

在opencv中,用于直方图均衡化的函数就是equalizeHist:

先上代码:

  img = cv2.imread("xxxx")

  img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

  hist = cv2.calcHist([img], [0], None, [256], [0, 255])

  plt.title('Gray Histogram Contour')
  plt.xlabel('gray level')
  plt.ylabel('number of pixels')

  plt.figure(1)
  plt.plot(hist)

  dst = cv2.equalizeHist(img)

  hist_new = cv2.calcHist([dst], [0], None, [256], [0, 255])

  plt.title('Gray Histogram Contour new')
  plt.xlabel('gray level')
  plt.ylabel('number of pixels')

  plt.figure(2)
  plt.plot(hist_new)

  plt.show()

  cv2.imshow("src", img)
  cv2.imshow("new", dst)

  cv2.waitKey()
  cv2.destroyAllWindows()

calcHist

在调用均衡化之前,先要计算图像的直方图,用于后续进行对比实验。
计算图像直方图的函数:调用opencv中的calcHist函数:

  • calcHist函数接受下面几个参数
  • [img],以列表的形式作为参数,img为需要计算直方图的图像。
  • [0],通道数,如果是灰度图,就传0
  • None,mask,用于ROI的掩码,传None就是统计整张图像。
  • [256],histSize,就是说分成多少类,如果全部统计的话就是256个类。
  • [0, 255],就是说哪些像素值需要被统计,[0, 255]就表示所有的像素值都需要被统计(8位)

然后再通过plt库进行绘图展示。

equalizeHist

直方图均衡化,这个函数就相对比较简单了,直接从源图到目标图进行转换。

我们看一下上面代码的结果,用来处理经典的一张图:

  • 源图:
    python的opencv操作记录(13)-增强之直方图均衡化

  • 源图直方图
    python的opencv操作记录(13)-增强之直方图均衡化

  • 目标图
    python的opencv操作记录(13)-增强之直方图均衡化

  • 目标图直方图
    python的opencv操作记录(13)-增强之直方图均衡化

从直方图分布可以看出,均衡化已经将像素点从相对集中变成了相对平衡的分布了。而这个累积分布概率函数的转换就是表明希望通过这样一个转换,使得像素尽量去满足一个像素值平均分布。
从最终形成的图像上来看,也是把一幅雾蒙蒙的图像变得相对清晰了。
但是存在一个这个方法典型的确定,马赛克现象比较严重。

自适应直方图均衡化

上面提到的均衡化方法有两个比较明显的不足:

  1. 马赛克现象,我理解是因为灰度是一个离散的点,会造成某个小区域发生阶跃性的变化,造成这种现象。
  2. 噪声被放大的现象,因为在整张图像上把像素值拉平的原因。

进一步的一个算法就是自适应直方图均衡化。
简单来说就是在上面的算法上做了两点改动:

  1. 利用局部特征,或者说局部的ROI特征进行CDF变换。也就是某个像素点周边的一个W*W的区域。这样就可以让灰度的阶跃变小。因为在一个小的区域里变换,噪声被放大的影响也不会太大。
  2. 上一步的改进中,会造成区域与区域之间被认为造成一些“边界”,所以这些边界需要通过双线性插值来进行“模糊”,让图像过渡比较连续。(双线性插值可以参考https://blog.csdn.net/pcgamer/article/details/125426351?spm=1001.2014.3001.5502)
  3. 为了防止局部对比度过于夸张,增加了一个限制对比度的参数,如果超过这个阈值,则会通过某种规则把这些灰度值分摊到区域中的其他像素值上去,让整个局部直方图更加的平缓。

代码也挺简单:

    clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
    cl1 = clahe.apply(img)

    hist_cl1 = cv2.calcHist([cl1], [0], None, [256], [0, 255])

    plt.title('Gray Histogram Contour hist_cl1')
    plt.xlabel('gray level')
    plt.ylabel('number of pixels')

    plt.figure(3)
    plt.plot(hist_cl1)

    plt.show()

    cv2.imshow("hist_cl1", cl1)

其中的方法cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))是创建了一个CLANE类,其中的两个参数

  • clipLimit = 2.0,对比度限制这个参数是用每块的直方图的每个bins的数和整图的平均灰度分布数的比值来限制的。 裁剪则是将每块图像直方图中超过ClipLimit的bins多出的灰度像素数去除超出部分,然后将所有bins超出的像素数累加后平均分配到所有bins。具体怎么分配的就不是特别清楚了。
  • tileGridSize就是每个小区域的大小
  • 再通过apply应用到图像上去
  • CLANE是opencv算法库中的一种。
    python的opencv操作记录(13)-增强之直方图均衡化

python的opencv操作记录(13)-增强之直方图均衡化

相比之前算法的图,有两点改进:

  1. 对比度与源图更类似,而不是整体上改变了源图的对比度,相对于普通的均衡化方法,分布的不是那么的均匀,但是更好的代表了源图的某些特征。
  2. 马赛克现象得到了缓解。

当然,不是在所有的图像上,自适应方法都可以比普通的均衡化方法更好的,需要根据图像的特征来进行判断。``文章来源地址https://www.toymoban.com/news/detail-441687.html

到了这里,关于python的opencv操作记录(13)-增强之直方图均衡化的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Python Opencv实践 - 直方图显示

       

    2024年02月11日
    浏览(42)
  • OpenCV——《bitwise_and》mask的操作以及直方图的操作

    bitwise_and该函数是一个and操作当两者全为1的时候才会为1,有0则0. 对应的是直方图横坐标代表的是0-256.纵坐标代表的是出现的次数。 三种颜色分别代表的是RGB三种通道上的信息

    2024年02月11日
    浏览(47)
  • 直方图统计增强方法

    直方图统计增强方法的原理:   直方图统计增强是一种基于像素值分布的图像增强技术,通过调整像素值的分布来增强图像的对比度和细节。其原理是根据图像的直方图信息,将原始像素值映射到一个新的像素值域,从而改变图像的亮度和对比度。 直方图统计增强方法的

    2024年02月09日
    浏览(39)
  • Python Opencv实践 - 图像直方图均衡化

         

    2024年02月11日
    浏览(43)
  • Python可视化在量化交易中的应用(13)_Seaborn直方图

    seaborn中绘制直方图使用的是sns.histlot()函数: sns.histplot(data,x,y,hue,weights,stat=‘count’,bins=‘auto’,binwidth,binrange,discrete,cumulative,common_bins,common_norm,multiple=‘layer’,element=‘bars’,fill,shrink=1,kde,kde_kws,line_kws,thresh=0,pthresh,pmax,cbar,cbar_ax,cbar_kws,palette,hue_order,hue_norm,color,log_scale,legend,ax

    2024年02月12日
    浏览(48)
  • Python-OpenCV中的图像处理-直方图

    通过直方图你可以对整幅图像的灰度分布有一个整体的了解。直方图的 x 轴是灰度值( 0 到 255), y 轴是图片中具有同一个灰度的点的数目。 BINS:上面的直方图显示了每个灰度值对应的像素数。如果像素值为 0到255,你就需要 256 个数来显示上面的直方图。但是,如果你不需

    2024年02月13日
    浏览(75)
  • Python Opencv实践 - 图像直方图自适应均衡化

       

    2024年02月11日
    浏览(47)
  • Python-OpenCV中的图像处理-图像直方图

    通过直方图你可以对整幅图像的灰度分布有一个整体的了解。直方图的 x 轴是灰度值( 0 到 255), y 轴是图片中具有同一个灰度的点的数目。 BINS:上面的直方图显示了每个灰度值对应的像素数。如果像素值为 0到255,你就需要 256 个数来显示上面的直方图。但是,如果你不需

    2024年02月12日
    浏览(71)
  • OpenCV-Python中的图像处理-图像直方图

    通过直方图你可以对整幅图像的灰度分布有一个整体的了解。直方图的 x 轴是灰度值( 0 到 255), y 轴是图片中具有同一个灰度的点的数目。 BINS:上面的直方图显示了每个灰度值对应的像素数。如果像素值为 0到255,你就需要 256 个数来显示上面的直方图。但是,如果你不需

    2024年02月12日
    浏览(61)
  • python opencv 图片缺陷检测(讲解直方图以及相关系数对比法)

    2.1灰度转换(将原图和要检测对比的图分开灰度化) 灰度化的作用是因为后面的直方图比较需要以像素256为基准进行相关性比较 2.2 直方图计算(结果其实是二维的图表–用画图的方式展示) 第一个参数: 必须为列表[],哪怕只有一个图片 ,image输入图像 channels::传入图像的

    2024年01月23日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包