【opencv】20.直方图均衡化的数学原理

本文只讲数字图像处理,即离散化后的公式,至于积分形式的分析,网上很多。
具体的数学推导可以参考这篇博客直方图均衡化
如果想自己代码实现直方图均衡化,相关源代码可以参考(不使用api)使用C++实现彩色图像直方图均衡化的三种方法
如果要直接使用opencv的api,直接一个函数搞定,用法如下:

void equalizeHist(InputArray src,OutputArray dst)

在实际均衡化过程中,核心步骤如下:
说明: x i x_i xi是灰度值,取值[0~255] i i i也取值为[0~255] x x x是一个像素(原始的), f ( x ) f(x) f(x)是直方图均衡化之后的值。

  • 1.计算灰度图的直方图;
  • 2.遍历灰度直方图,对灰度值从 0~255 累计求和(图像计算中,积分可以用求和来近似替代),对求和结果除以图像的像素总数,然后乘以 L − 1 \color{red}L-1 L1得到函数结果 得到函数结果 f ( x i ) f(x_i) f(xi)
    f ( x i ) = ( L − 1 ) ∑ 0 x i h ( x i ) w ∗ h \color{red}f(x_i)=(L-1)\sum_{0}^{x_i} {\frac{h(x_i)}{w*h}} f(xi)=(L1)0xiwhh(xi)
    如果写成迭代的式子,就是下面这样:
    f ( x i ) = f ( x i − 1 ) + ( L − 1 ) h ( x i ) w ∗ h = ( L − 1 ) ∑ 0 x i − 1 h ( x i − 1 ) w ∗ h + ( L − 1 ) h ( x i ) w ∗ h \color{red} \begin{aligned} f(x_i) &= f(x_{i-1})+(L-1)\frac{h(x_{i})}{w*h} \\ &=(L-1)\sum_{0}^{x_{i-1}} {\frac{h(x_{i-1})}{w*h}}+(L-1)\frac{h(x_{i})}{w*h} \\ \end{aligned} f(xi)=f(xi1)+(L1)whh(xi)=(L1)0xi1whh(xi1)+(L1)whh(xi)
    不过这种方式会产生小数,然后又取整,每次像素值都取整,有精度损失,虽然影响不大,但是更好的方式是对该像素和该像素之前的像素数量求和, c o u n t + = h ( x i ) count+=h(x_i) count+=h(xi),
    f ( x i ) = ( L − 1 ) c o u n t w ∗ h \color{red}f(x_i)=(L-1)\frac{count}{w*h} f(xi)=(L1)whcount
    这个公式就是,当 x i = 80 x_i=80 xi=80 时,灰度值为80的像素在直方图均衡化之后的灰度值为 f ( x i ) \color{red}f(x_i) f(xi)
  • 3.将每一个灰度值累积求和的结果 f ( x i ) f(x_i) f(xi)存储在一个大小为 256 的int数组中,存储的位置为 i i i;
  • 4.遍历输入图像每一个像素,记点值为 x x x,修改其像素值使等于 f ( x ) f(x) f(x)
  • 5.均衡化结束。

例子:

假设一幅图中的像素范围是 [10~160],有100个像素取值(因为有些像素值可能并没有,例如,一张图中像素值为75的像素一个都没有),直方图均衡化的做法就是:
其实累计求和就是下面这样,假设灰度图片总共有total=2550个像素:

origin_pixel_value 0 1 10 11 12 13 160 255
num 0 0 0 250 500 10 800 100 0 0
calculate:
v n e x t = v p r e + 255 ∗ n u m t o t a l v_{next}=v_{pre}+255* \frac{num}{total} vnext=vpre+255totalnum

例: v 10 = v 9 + 255 ∗ 250 2550 v_{10}=v_{9}+255* \frac{250}{2550} v10=v9+2552550250,

v 255 = v 254 + 255 ∗ 0 2550 v_{255}=v_{254}+255* \frac{0}{2550} v255=v254+25525500
v 0 = 0 v_0=0 v0=0 v 1 = v 0 + 0 v_1=v_0+0 v1=v0+0 0 v 10 = v 9 + 255 ∗ 250 2550 v_{10}=v_{9}+255* \frac{250}{2550} v10=v9+2552550250 v11 v12 v13 v160 v255
final_pixel_value 0 0 0 25 75 76 156 255 255 255

由上表可知,本来像素范围在[10~160],直方图均衡化之后,像素范围变为了[25~255],动态范围大大增加;

  • 原来的低亮度像素值为10的变为了2511的变为了7512的变为了76, 13变为了156160变成了255。可以看出该像素对应的灰度值在整幅图中的个数越多,变换后的灰度值就越大。
  • 本来像素12和像素13只相差1,直方图均衡化之后,变为了76156,对比度显著变大,之所以会这样,就是因为像素13比像素12的灰度值个数多,并且多的不是一个量级。
  • 但是由于直方图均衡化是递增的,对于原来像素11和像素12只相差1,直方图均衡化之后,变为了7576,所以即使二者像素个数相差几百个,对比度也没有增大。
  • 因此灰度值更高时,而像素数量骤减的话,并不会拉升对比度。只对灰度值更高,像素数量陡增时,才会拉升对比度。

假设该图像有total=25500个像素,即像素个数扩大了10倍,本例把像素值为160的像素增大到了3000个:

origin_pixel_value 0 1 10 11 12 13 160 255
num 0 0 0 250 500 10 800 3000 0 0
calculate:
v n e x t = v p r e + 255 ∗ n u m t o t a l v_{next}=v_{pre}+255* \frac{num}{total} vnext=vpre+255totalnum

例: v 10 = v 9 + 255 ∗ 250 25500 v_{10}=v_{9}+255* \frac{250}{25500} v10=v9+25525500250,

v 255 = v 254 + 255 ∗ 0 25500 v_{255}=v_{254}+255* \frac{0}{25500} v255=v254+255255000
v 0 = 0 v_0=0 v0=0 v 1 = v 0 + 0 v_1=v_0+0 v1=v0+0 0 v 10 = v 9 + 255 ∗ 250 25500 v_{10}=v_{9}+255* \frac{250}{25500} v10=v9+25525500250 v11 v12 v13 v160 v255
calculate_pixel_value 0 0 0 2.5 7.5 7.6 15.6 255 255 255
final_pixel_value 0 0 0 3 8 8 16 255 255 255

由上表可知,本来像素范围在 [10~160],直方图均衡化之后,像素范围变为了 [3~255],动态范围大大增加;

原来的低亮度像素值为10的变为了311的变为了8512的变为了8, 13变为了16,160变成了255。可以看出该像素对应的灰度值在整幅图中的个数越多,变换后的灰度值就越大。

图像中像素灰度值数量最多的变亮了,那么整幅图看起来就更亮,对比度更高,更清晰了。


猜你喜欢

转载自blog.csdn.net/u011754972/article/details/121773511