两幅图像的互信息和联合熵-MATLAB
image
image-processing
matlab
4
0

我有两个黑白图像,我需要计算相互信息。

Image 1 = X 
Image 2 = Y

我知道相互信息可以定义为:

MI = entropy(X) + entropy(Y) - JointEntropy(X,Y)

MATLAB已经具有内置函数来计算熵,但没有计算联合熵。我想真正的问题是:如何计算两个图像的联合熵?

这是我要查找联合熵的图像的示例:

X =

0    0    0    0    0    0
0    0    1    1    0    0
0    0    1    1    0    0
0    0    0    0    0    0
0    0    0    0    0    0

Y =

0    0    0    0    0    0 
0    0    0.38 0.82 0.38 0.04 
0    0    0.32 0.82 0.68 0.17
0    0    0.04 0.14 0.11 0 
0    0    0    0    0    0
参考资料:
Stack Overflow
收藏
评论
共 1 个回答
高赞 时间 活跃

要计算联合熵,您需要计算两个图像之间的联合直方图。联合直方图与正常的1D直方图基本相同,但第一维记录了第一幅图像的强度,第二维记录了第二幅图像的强度。这非常类似于通常被称为共现矩阵的矩阵 。在位置(i,j)在联合直方图,它告诉我们你强多少值已经遇到了有强度i在第一图像和强度j第二形象。

重要的是,这要记录我们在相同的对应位置看到这对强度的次数 。例如,如果我们的联合直方图计数为(7,3) = 2 ,则这意味着当我们扫描两个图像时,当我们在第二个图像中相同的对应位置遇到强度7时,都遇到了强度为3 ,共2次。

构造联合直方图非常简单。

  1. 首先,创建一个256 x 256矩阵(假设您的图像是8位无符号整数),并将它们初始化为全零。另外,您需要确保两个图像的大小(宽度和高度)相同。
  2. 完成此操作后,请查看每个图像的第一个像素,我们将其表示为左上角。具体来说,请看一下此位置的第一张和第二张图像的强度。第一张图像的强度将用作行,而第二张图像的强度将用作列。
  3. 在矩阵中找到此位置,并将矩阵中的该点增加1
  4. 对图像中的其余位置重复此操作。
  5. 完成后,将所有条目除以任一图像中的元素总数(请记住它们的大小应相同)。这将为我们提供两个图像之间的联合概率分布。

人们可能倾向于使用for循环来执行此操作,但是众所周知, for循环非常慢,因此应尽可能避免。但是,您可以通过以下方式在MATLAB中轻松进行此操作, 而无需循环。假设im1im2是您要比较的第一张和第二张图片。我们可以做的是将im1im2转换为向量。然后,我们可以使用accumarray帮助我们计算联合直方图。 accumarray是MATLAB中最强大的功能之一。您可以将其视为微型MapReduce范例。简而言之,每个数据输入都有一个键和一个关联的值。 accumarray的目标是对属于同一键的所有值进行accumarray ,并对所有这些值进行一些操作。在我们的示例中,“键”将是强度值,并且每个强度值的值本身就是1的值。然后,我们希望将映射到同一bin的所有1加起来 ,这正是我们计算直方图的方式。 accumarray的默认行为是添加所有这些值。具体来说, accumarray的输出将是一个数组,其中每个位置都会计算映射到该键的所有值的总和。例如,第一个位置将是映射到键1的所有值的总和,第二个位置将是映射到键2的所有值的总和,依此类推。

但是,对于联合直方图,您想弄清楚哪些值映射到(i,j)的同一强度对,因此此处的键将是一对2D坐标。这样,在两个图像之间共享的相同空间位置中,第一图像中的强度i和第二图像中的强度j任何强度都将到达相同的关键点。因此,在2D情况下, accumarray的输出将是2D矩阵,其中每个元素(i,j)包含映射到键(i,j)的所有值的总和,类似于前面提到的1D情况,即正是我们所追求的。

换一种说法:

indrow = double(im1(:)) + 1;
indcol = double(im2(:)) + 1; %// Should be the same size as indrow
jointHistogram = accumarray([indrow indcol], 1);
jointProb = jointHistogram / numel(indrow);

使用accumarray ,第一个输入是键,第二个输入是值。使用accumarray的注意accumarray是,如果每个键具有相同的值,则只需将常量分配给第二个输入,这就是我所做的,它是1 。通常,这是与第一个输入具有相同行数的数组。另外,请特别注意前两行。图像中的强度不可避免地为0 ,但是由于MATLAB从1开始索引,所以我们需要将两个数组都偏移1

现在我们有了联合直方图,计算联合熵非常简单。它类似于一维中的熵,只是现在我们只是对整个联合概率矩阵求和。请记住,您的联合直方图很有可能会包含许多0项。我们需要确保跳过这些操作,否则log2操作将是未定义的。现在让我们摆脱任何零条目:

indNoZero = jointHistogram ~= 0;
jointProb1DNoZero = jointProb(indNoZero);

请注意,我搜索的是联合直方图,而不是联合概率矩阵。这是因为联合直方图由整数组成,而联合概率矩阵将介于01之间。由于存在除法运算,由于数值舍入和不稳定性,我想避免将此矩阵中的任何条目都与0进行比较。上面的方法还将我们的联合概率矩阵转换为堆叠的一维矢量,这很好。

这样,联合熵可以计算为:

jointEntropy = -sum(jointProb1DNoZero.*log2(jointProb1DNoZero));

如果我对在MATLAB中计算图像的熵的理解是正确的,那么它应该计算256 bin上的直方图/概率分布,因此,您当然可以在此处将函数与刚刚计算的联合熵一起使用。

如果我们有浮点数据呢?

到目前为止,我们已经假设您处理的图像的强度是整数值。如果我们有浮点数据怎么办? accumarray假定您尝试使用整数索引到输出数组中,但是我们仍然可以通过这小小的颠簸来完成我们想要的操作。您只需在两个图像中为每个浮点值分配一个唯一的ID 。因此,您可以将accumarray与这些ID结合使用。为了简化此ID的分配,请使用unique -特别是功能的第三个输出。您将拍摄每个图像,将它们放入unique的图像,然后将这些索引输入到accumarray 。换句话说,改为执行以下操作:

[~,~,indrow] = unique(im1(:)); %// Change here
[~,~,indcol] = unique(im2(:)); %// Change here

%// Same code
jointHistogram = accumarray([indrow indcol], 1);
jointProb = jointHistogram / numel(indrow);
indNoZero = jointHistogram ~= 0;
jointProb1DNoZero = jointProb(indNoZero);
jointEntropy = -sum(jointProb1DNoZero.*log2(jointProb1DNoZero));

请注意,使用indrowindcol ,我们直接为这些变量分配unique的第三输出,然后使用我们之前计算的相同联合熵代码。我们也不必像以前那样将变量偏移1,因为unique将分配从1开始的 ID。

在旁边

实际上,您可以使用联合概率矩阵分别计算每个图像的直方图或概率分布。如果要计算第一张图像的直方图/概率分布,则只需累加每一行的所有列。要针对第二个图像执行此操作,您只需累积每一列的所有行。因此,您可以执行以下操作:

histogramImage1 = sum(jointHistogram, 1);
histogramImage2 = sum(jointHistogram, 2);

之后,您可以自己计算这两者的熵。要仔细检查,请确保将它们都转换为PDF,然后使用标准方程式(如上)计算熵。


最终如何计算互信息?

要最终计算互信息,您将需要两个图像的熵。您可以使用MATLAB的内置entropy函数,但这是假定存在256个唯一级别。您可能希望将其应用到存在N不同级别而不是256个的情况下,因此您可以对联合直方图使用上面的操作,然后在上面的备用代码中为每个图像计算直方图,然后计算每个图像的熵。您只需重复使用联合使用的熵计算,然后将其分别应用于每个图像:

%// Find non-zero elements for first image's histogram
indNoZero = histogramImage1 ~= 0;

%// Extract them out and get the probabilities
prob1NoZero = histogramImage1(indNoZero);
prob1NoZero = prob1NoZero / sum(prob1NoZero);

%// Compute the entropy
entropy1 = -sum(prob1NoZero.*log2(prob1NoZero));

%// Repeat for the second image
indNoZero = histogramImage2 ~= 0;
prob2NoZero = histogramImage2(indNoZero);
prob2NoZero = prob2NoZero / sum(prob2NoZero);
entropy2 = -sum(prob2NoZero.*log2(prob2NoZero));

%// Now compute mutual information
mutualInformation = entropy1 + entropy2 - jointEntropy;

希望这可以帮助!

收藏
评论
新手导航
  • 社区规范
  • 提出问题
  • 进行投票
  • 个人资料
  • 优化问题
  • 回答问题

关于我们

常见问题

内容许可

联系我们

@2020 AskGo
京ICP备20001863号