0

我是 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');
4

2 回答 2

2

要实现Wikipedia 页面上描述的均衡算法,请执行以下步骤:

决定对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 错误是可能的。如果一个箱子是空的,这些可能会发生,因此连续的和是相等的。所以你也需要特殊的代码来处理这种情况。您可以做的最好的事情是将因子的值取为 , 之间的中间值hIndexhIndex + n其中n是 的最大值histogramSum[hIndex + n] == histogramSum[hIndex]


一旦你处理了所有的技术问题,就应该这样。

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


关于您的 Matlab 代码的另一件事:行和列是倒置的。由于算法中的对称性,结果是一样的,但是在其他算法中可能会引起令人费解的错误,如果在调试时检查像素值会非常混乱。不过,在上面的伪代码中,我使用的和你一样。

于 2013-04-03T22:29:06.057 回答
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)的合成时,您会得到以下结果: 比较四块

我认为这很有说服力。图像并不完全相同 - 我相信这是因为 matlabhisteq例程忽略了所有值为 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);

我希望这能让代码更容易理解。

于 2013-04-03T23:32:23.627 回答