直方图均衡旨在展平您的图像直方图。基本上,它将图像建模为概率密度函数(或者更简单地说,直方图,您可以通过图像中的像素总数对每个条目进行归一化)并尝试确保像素具有特定强度的概率是equiprobable(概率相等)。
直方图均衡化的前提是对比度差的图像。看起来太暗、太褪色或太亮的图像是您应用直方图均衡的理想选择。如果绘制直方图,则像素的分布被限制在一个非常窄的范围内。通过进行直方图均衡化,直方图将因此变平并为您提供更好的对比度图像。直方图的效果是它扩展了直方图的动态范围。
就数学定义而言,我不会对细节感到厌烦,我很想在这里用一些 LaTeX 来做,但不支持。因此,我将您推迟到更详细解释它的链接:http://www.math.uci.edu/icamp/courses/math77c/demos/hist_eq.pdf
但是,执行直方图均衡化的最终方程本质上是一对一的映射。对于图像中的每个像素,您可以提取其强度,然后通过此函数运行它。然后它会为您提供一个输出强度,以放置在您的输出图像中。
假设p_i 是您在图像中遇到强度为i 的像素的概率(获取像素强度i 的直方图箱计数并除以图像中的像素总数)。鉴于您的图像中有L 强度,在给定i 强度的情况下,此位置的输出强度指定为:
g_i = floor( (L-1) * sum_{n=0}^{i} p_i )
您将像素强度从 0、1、2 一直到强度i 的所有概率相加。这就是众所周知的累积分布函数。
MATLAB 本质上是使用这种方法执行直方图均衡化。但是,如果您想自己实现它,它实际上非常简单。假设您有一个无符号 8 位整数类型的输入图像 im。
function [out] = hist_eq(im, L)
if (~exist(L, 'var'))
L = 256;
end
h = imhist(im) / numel(im);
cdf = cumsum(h);
out = (L-1)*cdf(double(im)+1);
out = uint8(out);
此函数接收假定为无符号 8 位整数的图像。您可以选择指定输出的级别数。通常,L = 256 用于 8 位图像,因此如果您省略第二个参数,L 将被假定为这样。第一行计算概率。下一行计算累积分布函数 (CDF)。使用直方图均衡计算输入/输出后的下两行,然后转换回无符号 8 位整数。请注意,uint8 转换为我们隐式执行 floor 操作。您需要注意,在访问 CDF 时,我们必须添加 offset of 1。原因是 MATLAB 从 1 开始索引,而图像中的强度从 0 开始。
MATLAB 命令histeq 几乎做同样的事情,除了如果你调用histeq(im),它假定你的图像中有32 个强度。因此,您可以通过指定一个附加参数来覆盖histeq 函数,该参数指定在图像中看到多少强度值,就像我们上面所做的那样。因此,你会做histeq(im, 256);。在 MATLAB 中调用它,并使用我上面写的函数应该会给你相同的结果。
作为一个练习,让我们使用一个名为 pout.tif 的 MATLAB 发行版中的图像。让我们也显示它的直方图。
im = imread('pout.tif');
figure;
subplot(2,1,1);
imshow(im);
subplot(2,1,2);
imhist(im);
如您所见,图像的对比度很差,因为大多数强度值都在一个狭窄的范围内。直方图均衡化将使图像变平,从而增加图像的对比度。因此,请尝试这样做:
out = histeq(im, 256); %//or you can use my function: out = hist_eq(im);
figure;
subplot(2,1,1);
imshow(out);
subplot(2,1,2);
imhist(out);
这是我们得到的:
如您所见,对比度更好。较暗的像素倾向于向较暗的一端移动,而较亮的像素则被推向较亮的一端。我认为成功的结果!请记住,当您尝试进行直方图均衡时,并非所有图像都能为您提供良好的结果。图像处理主要是一个反复试验的过程,因此您将各种不同的技术混合在一起,直到获得良好的结果。
希望这可以帮助您入门。祝你好运!