我有两张黑白图像,我需要计算互信息。
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
答案 0 :(得分:59)
要计算关节熵,需要计算两幅图像之间的联合直方图。联合直方图与普通1D直方图基本相同,但第一维记录第一图像的强度,第二维记录第二图像的强度。这与通常所说的co-occurrence matrix非常相似。在联合直方图中的位置(i,j)
,它会告诉您我们遇到的强度值有多少,第一张图像中的强度为i
,第二张图像中的强度为j
。
重要的是,这记录了我们在相同的相应位置看到这对强度的次数。例如,如果我们的联合直方图计数为(7,3) = 2
,这意味着当我们扫描两个图像时,当我们遇到强度7
时,在第二个图像中的相同位置,我们遇到3
的强度总共2
次。
构建联合直方图非常简单。
256 x 256
矩阵(假设您的图像是无符号的8位整数)并将它们初始化为全零。此外,您需要确保两个图像的大小(宽度和高度)相同。 1
在矩阵中增加此点。 人们倾向于使用for
循环执行此操作,但众所周知,for
循环非常慢,如果可能的话应该避免。但是,您可以通过以下方式在MATLAB中轻松完成此操作不带循环。我们假设im1
和im2
是您想要比较的第一个和第二个图像。我们可以做的是将im1
和im2
转换为向量。然后我们可以使用accumarray
来帮助我们计算联合直方图。 accumarray
是MATLAB中功能最强大的函数之一。您可以将其视为微缩MapReduce范例。简而言之,每个数据输入都有一个键和一个相关的值。 accumarray
的目标是将属于同一个键的所有值都存储在一起,并对所有这些值执行某些操作。在我们的例子中,"键"将是强度值,并且值本身是每个强度值的1
的值。然后,我们希望添加向上映射到同一个bin的1
的所有值,这正是我们计算直方图的方式。 accumarray
的默认行为是添加所有这些值。具体来说,accumarray
的输出将是一个数组,其中每个位置计算映射到该键的所有值的总和。例如,第一个位置是映射到键1的所有值的总和,第二个位置是映射到键2的所有值的总和,依此类推。
但是,对于联合直方图,您想要确定哪些值映射到(i,j)
的相同强度对,因此这里的键将是一对2D坐标。因此,在两个图像之间共享的第一个图像中强度为i
且第二个图像中的{{1>}在同一空间位置中的任何强度均相同键。因此,在2D情况下,j
的输出将是2D矩阵,其中每个元素accumarray
包含映射到键(i,j)
的所有值的总和,类似于1D情况。之前提到的这正是我们所追求的。
换句话说:
(i,j)
使用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
的注释是,如果每个键都具有相同的值,您可以简单地为第二个输入分配一个常量,这就是我已经完成的并且它是' s accumarray
。通常,这是一个与第一个输入具有相同行数的数组。另外,请特别注意前两行。在图像中不可避免地存在1
的强度,但由于MATLAB开始在0
建立索引,我们需要将这两个数组偏移1
。
现在我们有联合直方图,计算联合熵非常简单。它类似于1D中的熵,除了现在我们只是对整个联合概率矩阵求和。请记住,您的联合直方图很可能会有很多1
个条目。我们需要确保跳过这些或0
操作未定义。现在让我们摆脱任何零条目:
log2
注意我搜索了联合直方图而不是联合概率矩阵。这是因为联合直方图由整数组成,而联合概率矩阵在indNoZero = jointHistogram ~= 0;
jointProb1DNoZero = jointProb(indNoZero);
和0
之间。由于划分,我想避免由于数字舍入和不稳定性而将此矩阵中的任何条目与1
进行比较。以上也将我们的联合概率矩阵转换为堆叠的1D向量,这很好。
因此,联合熵可以计算为:
0
如果我对在MATLAB中计算图像的熵的理解是正确的,它应该计算jointEntropy = -sum(jointProb1DNoZero.*log2(jointProb1DNoZero));
区间上的直方图/概率分布,所以你当然可以在这里使用刚刚计算出的联合熵。
到目前为止,我们假设您处理的图像具有整数值的强度。如果我们有浮点数据怎么办? 256
假设您正在尝试使用整数索引到输出数组,但我们仍然可以通过这个小小的颠簸实现我们想要的目标。您要做的只是将两个图像中的每个浮点值分配为唯一ID 。因此,您将使用accumarray
来代替这些ID。为了便于此ID分配,请使用unique
- 特别是函数的第三个输出。您将获取每个图像,将它们放入accumarray
并将这些索引输入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));
和indrow
,我们直接将indcol
的第三个输出分配给这些变量,然后使用我们之前计算的相同联合熵代码。我们也不必像以前那样将变量偏移1,因为unique
会从1 开始分配ID 。
您实际上可以使用联合概率矩阵单独计算每个图像的直方图或概率分布。如果要计算第一个图像的直方图/概率分布,则只需累加每行的所有列。要为第二个图像执行此操作,您只需累积每列的所有行。因此,您可以这样做:
unique
之后,您可以自己计算这两者的熵。要仔细检查,请确保将这两个转换为PDF,然后使用标准公式计算熵(如上所述)。
要最终计算互信息,您将需要两个图像的熵。您可以使用MATLAB的内置entropy
函数,但这假设有256个唯一级别。您可能希望将此应用于存在histogramImage1 = sum(jointHistogram, 1);
histogramImage2 = sum(jointHistogram, 2);
个不同级别而不是256的情况,因此您可以使用我们在联合直方图上执行的操作,然后在上面的旁边代码中计算每个图像的直方图,然后计算每个图像的熵。您只需重复联合使用的熵计算,但将其单独应用于每个图像:
N
希望这有帮助!