Source code for medpy.metric.image
# Copyright (C) 2013 Oskar Maier
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# author Oskar Maier
# version r0.1.0
# since 2013-07-09
# status Release
# build-in modules
# third-party modules
import numpy
# own modules
from ..core import ArgumentError
# code
[docs]def mutual_information(i1, i2, bins=256):
r"""
Computes the mutual information (MI) (a measure of entropy) between two images.
MI is not real metric, but a symmetric and nonnegative similarity measures that
takes high values for similar images. Negative values are also possible.
Intuitively, mutual information measures the information that ``i1`` and ``i2`` share: it
measures how much knowing one of these variables reduces uncertainty about the other.
The Entropy is defined as:
.. math::
H(X) = - \sum_i p(g_i) * ln(p(g_i)
with :math:`p(g_i)` being the intensity probability of the images grey value :math:`g_i`.
Assuming two images :math:`R` and :math:`T`, the mutual information is then computed by comparing the
images entropy values (i.e. a measure how well-structured the common histogram is).
The distance metric is then calculated as follows:
.. math::
MI(R,T) = H(R) + H(T) - H(R,T) = H(R) - H(R|T) = H(T) - H(T|R)
A maximization of the mutual information is equal to a minimization of the joint
entropy.
Parameters
----------
i1 : array_like
The first image.
i2 : array_like
The second image.
bins : integer
The number of histogram bins (squared for the joined histogram).
Returns
-------
mutual_information : float
The mutual information distance value between the supplied images.
Raises
------
ArgumentError
If the supplied arrays are of different shape.
"""
# pre-process function arguments
i1 = numpy.asarray(i1)
i2 = numpy.asarray(i2)
# validate function arguments
if not i1.shape == i2.shape:
raise ArgumentError('the two supplied array-like sequences i1 and i2 must be of the same shape')
# compute i1 and i2 histogram range
i1_range = __range(i1, bins)
i2_range = __range(i2, bins)
# compute joined and separated normed histograms
i1i2_hist, _, _ = numpy.histogram2d(i1.flatten(), i2.flatten(), bins=bins, range=[i1_range, i2_range]) # Note: histogram2d does not flatten array on its own
i1_hist, _ = numpy.histogram(i1, bins=bins, range=i1_range)
i2_hist, _ = numpy.histogram(i2, bins=bins, range=i2_range)
# compute joined and separated entropy
i1i2_entropy = __entropy(i1i2_hist)
i1_entropy = __entropy(i1_hist)
i2_entropy = __entropy(i2_hist)
# compute and return the mutual information distance
return i1_entropy + i2_entropy - i1i2_entropy
def __range(a, bins):
'''Compute the histogram range of the values in the array a according to
scipy.stats.histogram.'''
a = numpy.asarray(a)
a_max = a.max()
a_min = a.min()
s = 0.5 * (a_max - a_min) / float(bins - 1)
return (a_min - s, a_max + s)
def __entropy(data):
'''Compute entropy of the flattened data set (e.g. a density distribution).'''
# normalize and convert to float
data = data/float(numpy.sum(data))
# for each grey-value g with a probability p(g) = 0, the entropy is defined as 0, therefore we remove these values and also flatten the histogram
data = data[numpy.nonzero(data)]
# compute entropy
return -1. * numpy.sum(data * numpy.log2(data))