直方图均衡方法不使用histeq

时间:2013-04-03 21:44:12

标签: matlab

我是Matlab的新手,我正在尝试实现代码以执行与histeq相同的功能,而无需实际使用该函数。在我的代码中,当它不应该改变那么多时,我得到的图像颜色会发生巨大变化。图像中的平均强度(范围在0到255之间)是105.3196。图像是开源花粉粒子。

非常感谢任何帮助。越快越好!由于我的Matlab理解有限,请帮助简化。感谢。

clc;
clear all;
close all;

pollenJpg = imread ('pollen.jpg', 'jpg');
greyscalePollen = rgb2gray (pollenJpg);

histEqPollen = histeq(greyscalePollen);

averagePollen = mean2 (greyscalePollen)

sizeGreyScalePollen = size(greyscalePollen);
rowsGreyScalePollen = sizeGreyScalePollen(1,1);
columnsGreyScalePollen = sizeGreyScalePollen(1,2);

for  i = (1:rowsGreyScalePollen)
    for  j = (1:columnsGreyScalePollen)
        if (greyscalePollen(i,j) > averagePollen)
            greyscalePollen(i,j) = greyscalePollen(i,j) + (0.1 * averagePollen);

            if (greyscalePollen(i,j) > 255)
                greyscalePollen(i,j) = 255;
            end

        elseif (greyscalePollen(i,j) < averagePollen)
            greyscalePollen(i,j) = greyscalePollen(i,j) - (0.1 * averagePollen);

            if (greyscalePollen(i,j) > 0)
                greyscalePollen(i,j) = 0;
            end

        end
    end
end

figure;
imshow (pollenJpg);
title ('Original Image');
figure;
imshow (greyscalePollen);
title ('Attempted Histogram Equalization of Image');
figure;
imshow (histEqPollen);
title ('True Histogram Equalization of Image');

2 个答案:

答案 0 :(得分:2)

要实施equalisation algorithm described on the Wikipedia page,请按以下步骤操作:

决定binSize对灰度值进行分组。 (这是一个可调整的,bin越大,理想情况下的结果越不准确,但我认为如果在真实图像上选择太小则会导致问题。)

然后,计算像素为灰色阴影的概率:

pixelCount = imageWidth * imageHeight
histogram = all zero
for each pixel in image at coordinates i, j
    histogram[floor(pixel / 255 / 10) + 1] += 1 / pixelCount // 1-based arrays, not 0-based
    // Note a technicality here: you may need to 
    // write special code to handle pixels of 255,
    // because they will fall in their own bin. Or instead use rounding with an offset. 

此计算中的直方图被缩放(除以像素数),以使这些值作为概率有意义。你当然可以将除法归结为for循环。

现在你需要计算这个的累积总和:

histogramSum = all zero // length of histogramSum must be one bigger than histogram

for i == 1 .. length(histogram)
    histogramSum[i + 1] = histogramSum[i] + histogram[i]

现在你必须反转这个功能,这是一个棘手的部分。最好的方法是不计算显式逆,而是在现场计算,并将其应用于图像。基本思想是在histogramSum中搜索像素值(找到下面最接近的索引),然后在索引和下一个索引之间进行线性插值。

foreach pixel in image at coordinates i, j
   hIndex = findIndex(pixel, histogramSum) // You have to write findIndex, it should be simple
   equilisationFactor = (pixel - histogramSum[hIndex])/(histogramSum[hIndex + 1] - histogramSum[hIndex]) * binSize
   // This above is the linear interpolation step. 
   // Notice the technicality that you need to handle:
   // histogramSum[hIndex + 1] may be out of bounds

   equalisedImage[i, j] = pixel * equilisationFactor

编辑:没有钻进数学,我不能100%肯定,但我认为除0错误是可能的。如果一个bin为空,则会发生这些情况,因此连续的总和相等。所以你需要特殊的代码来处理这种情况。您可以做的最好的事情是将因子的值作为hIndexhIndex + n之间的中间值,其中nhistogramSum[hIndex + n] == histogramSum[hIndex]的最高值。


一旦你处理了所有技术问题,应该成为它。

上述算法很慢(特别是在findIndex步骤中)。您可以使用特殊的查找数据结构对其进行优化。但只有在工作时才这样做,并且只在必要时才这样做。


关于Matlab代码的另一件事:行和列是反转的。由于算法的对称性,结果是相同的,但它可能会导致其他算法中出现令人费解的错误,如果在调试期间检查像素值,则会非常混乱。在上面的伪代码中,我使用它们和你一样。

答案 1 :(得分:1)

相对较少的(5)行代码可以做到这一点。我在http://commons.wikimedia.org/wiki/File%3ALepismium_lorentzianum_pollen.jpg

找到了一个名为'pollen.jpg'的低对比度文件

我在使用您的代码时阅读它,运行以上所有内容,然后执行以下操作:

% find out the index of pixels sorted by intensity:
[gv gi] = sort(greyscalePollen(:));  

% create a table of "approximately equal" intensity values:
N = numel(gv);
newVals = repmat(0:255, [ceil(N/256) 1]);

% perform lookup: 
% the pixels in sorted order need new values from "equal bins" table:
newImg = zeros(size(greyscalePollen));
newImg(gi) = newVals(1:N);

% if the size of the image doesn't divide into 256, the last bin will have 
% slightly fewer pixels in it than the others

当我运行此算法,然后创建四个图像(原始,您的尝试,我的尝试和histeq)的合成时,您将获得以下内容: comparison fourblock

我认为这很有说服力。图像并不完全相同 - 我相信这是因为matlab histeq例程忽略了值为0的所有像素。因为它是完全矢量化的,所以它也非常快(尽管不如histeq那么快。在我的图像上约为15倍。

编辑:可能会有一些解释。我用来创建repmat矩阵的newVals命令会创建一个如下所示的矩阵:

0  1  2  3  4  ...  255
0  1  2  3  4  ...  255
0  1  2  3  4  ...  255
...
0  1  2  3  4  ...  255

由于matlab以“第一个索引优先”的顺序存储矩阵,如果你用一个索引读取这个矩阵(就像我在行newVals(1:N)中那样),你首先访问所有零,然后是所有零,等:

0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 ...

所以 - 当我按照强度顺序知道像素的索引时(由sort命令的第二个参数返回,我称之为gi),然后我可以很容易地分配使用我使用的命令,0到第一个N/256像素的值,值1到下一个N/256等:

newImg(gi) = newVals(1:N);

我希望这会使代码更容易理解。