web-dev-qa-db-fra.com

Information mutuelle et entropie conjointe de deux images - MATLAB

J'ai deux images en noir et blanc et je dois calculer les informations mutuelles.

Image 1 = X 
Image 2 = Y

Je sais que les informations mutuelles peuvent être définies comme:

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

MATLAB a déjà des fonctions intégrées pour calculer l'entropie mais pas pour calculer l'entropie conjointe. Je suppose que la vraie question est: comment calculer l'entropie conjointe de deux images?

Voici un exemple des images que j'aimerais trouver l'entropie conjointe de:

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
24
Jorge

Pour calculer l'entropie conjointe, vous devez calculer l'histogramme conjoint entre deux images. L'histogramme commun est essentiellement le même qu'un histogramme 1D normal, mais la première dimension enregistre les intensités pour la première image et la deuxième dimension enregistre les intensités pour la deuxième image. Ceci est très similaire à ce qui est communément appelé matrice de cooccurrence . À l'emplacement (i,j) dans l'histogramme conjoint, il vous indique le nombre de valeurs d'intensité que nous avons rencontrées et qui ont une intensité i dans la première image et une intensité j dans la deuxième image.

Ce qui est important, c'est que cela enregistre combien de fois nous avons vu cette paire d'intensités aux mêmes emplacements correspondants . Par exemple, si nous avons un nombre d'histogrammes communs de (7,3) = 2, cela signifie que lorsque nous numérisions les deux images, lorsque nous rencontrions l'intensité de 7, au même endroit correspondant dans la deuxième image, nous avons rencontré l'intensité de 3 pour un total de 2 fois.

La construction d'un histogramme commun est très simple à faire.

  1. Créez d'abord un 256 x 256 matrice (en supposant que votre image est un entier 8 bits non signé) et initialisez-les à tous les zéros. Vous devez également vous assurer que vos deux images sont de la même taille (largeur et hauteur).
  2. Une fois que vous avez fait cela, jetez un œil au premier pixel de chaque image, que nous désignerons comme le coin supérieur gauche. Plus précisément, jetez un œil aux intensités pour la première et la deuxième image à cet endroit. L'intensité de la première image servira de ligne tandis que l'intensité de la seconde image servira de colonne.
  3. Trouvez cet emplacement dans la matrice et incrémentez ce point dans la matrice de 1.
  4. Répétez cette opération pour les autres emplacements de votre image.
  5. Une fois que vous avez terminé, divisez toutes les entrées par le nombre total d'éléments dans l'une ou l'autre image (n'oubliez pas qu'ils doivent être de la même taille). Cela nous donnera la distribution de probabilité conjointe entre les deux images.

On serait enclin à le faire avec des boucles for, mais comme il est communément connu, les boucles for sont notoirement lentes et doivent être évitées si possible. Cependant, vous pouvez facilement le faire dans MATLAB de la manière suivante sans boucles . Supposons que im1 et im2 sont les première et deuxième images auxquelles vous souhaitez comparer. Ce que nous pouvons faire, c'est convertir im1 et im2 en vecteurs. Nous pouvons ensuite utiliser accumarray pour nous aider à calculer l'histogramme conjoint. accumarray est l'une des fonctions les plus puissantes de MATLAB. Vous pouvez le considérer comme un paradigme miniature de MapReduce. Autrement dit, chaque entrée de données a une clé et une valeur associée. Le but de accumarray est de regrouper toutes les valeurs qui appartiennent à la même clé et d'effectuer une opération sur toutes ces valeurs. Dans notre cas, la "clé" serait les valeurs d'intensité, et les valeurs elles-mêmes sont la valeur de 1 pour chaque valeur d'intensité. Nous voudrions alors ajouter toutes les valeurs de 1 cette carte dans le même bac, ce qui est exactement la façon dont nous calculerions un histogramme. Le comportement par défaut de accumarray consiste à ajouter toutes ces valeurs. Plus précisément, la sortie de accumarray serait un tableau dans lequel chaque position calcule la somme de toutes les valeurs associées à cette clé. Par exemple, la première position serait la somme de toutes les valeurs mappées à la clé de 1, la seconde position serait la somme de toutes les valeurs mappées à la clé de 2, etc.

Cependant, pour l'histogramme conjoint, vous voulez déterminer quelles valeurs correspondent à la même paire d'intensité (i,j), et donc les clés ici seraient une paire de coordonnées 2D. Ainsi, toutes les intensités qui ont une intensité de i dans la première image et j dans la deuxième image au même emplacement spatial partagé entre les deux images aller sur la même clé. Par conséquent, dans le cas 2D, la sortie de accumarray serait une matrice 2D où chaque élément (i,j) contient la somme de toutes les valeurs associées à la clé (i,j), similaire au cas 1D mentionné précédemment, qui est exactement ce que nous recherchons.

En d'autres termes:

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

Avec accumarray, la première entrée est les clés et la deuxième entrée les valeurs. Une note avec accumarray est que si chaque touche a la même valeur , vous pouvez simplement assigner une constante à la deuxième entrée, qui est ce que j'ai fait et c'est 1. En général, il s'agit d'un tableau avec le même nombre de lignes que la première entrée. Notez également les deux premières lignes. Il y aura inévitablement une intensité de 0 dans votre image, mais parce que MATLAB commence l'indexation à 1, nous devons décaler les deux tableaux de 1.

Maintenant que nous avons l'histogramme conjoint, il est très simple de calculer l'entropie conjointe. Elle est similaire à l'entropie en 1D, sauf que maintenant nous sommons simplement sur la matrice de probabilité conjointe entière. Gardez à l'esprit qu'il est très probable que votre histogramme conjoint contiendra de nombreux 0 entrées. Nous devons nous assurer de les ignorer ou de log2 l'opération ne sera pas définie. Supprimons maintenant les entrées nulles:

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

Notez que j'ai recherché l'histogramme conjoint au lieu de la matrice de probabilité conjointe. En effet, l'histogramme conjoint se compose de nombres entiers tandis que la matrice de probabilité conjointe se situe entre 0 et 1. En raison de la division, je veux éviter de comparer les entrées de cette matrice avec 0 en raison de l'arrondi numérique et de l'instabilité. Ce qui précède convertira également notre matrice de probabilité conjointe en un vecteur 1D empilé, ce qui est bien.

En tant que telle, l'entropie conjointe peut être calculée comme suit:

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

Si ma compréhension du calcul de l'entropie d'une image dans MATLAB est correcte, il devrait calculer la distribution histogramme/probabilité sur 256 bins, vous pouvez donc certainement utiliser cette fonction ici avec l'entropie conjointe qui vient d'être calculée.

Et si nous avions à la place des données à virgule flottante?

Jusqu'à présent, nous avons supposé que les images que vous avez traitées ont des intensités à valeur entière. Et si nous avons des données en virgule flottante? accumarray suppose que vous essayez d'indexer dans le tableau de sortie à l'aide d'entiers, mais nous pouvons toujours accomplir ce que nous voulons avec cette petite bosse sur la route. Ce que vous feriez serait simplement d'assigner chaque valeur à virgule flottante dans les deux images pour avoir un ID unique . Vous utiliseriez donc accumarray avec ces ID à la place. Pour faciliter l'attribution de cet ID, utilisez unique - spécifiquement la troisième sortie de la fonction. Vous devez prendre chacune des images, les mettre dans unique et en faire les index à saisir dans accumarray. En d'autres termes, faites ceci à la place:

[~,~,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));

Notez qu'avec indrow et indcol, nous attribuons directement la troisième sortie de unique à ces variables, puis utilisons le même code d'entropie conjoint que nous avons calculé plus tôt. Nous n'avons pas non plus à décaler les variables de 1 comme nous l'avons fait précédemment car unique attribuera des ID à partir de 1 .

De côté

Vous pouvez réellement calculer les histogrammes ou les distributions de probabilité pour chaque image individuellement en utilisant la matrice de probabilité conjointe. Si vous vouliez calculer les histogrammes/distributions de probabilité pour la première image, vous accumuleriez simplement toutes les colonnes pour chaque ligne. Pour le faire pour la deuxième image, vous accumuleriez simplement toutes les lignes de chaque colonne. En tant que tel, vous pouvez faire:

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

Après, vous pouvez calculer vous-même l'entropie de ces deux éléments. Pour vérifier, assurez-vous de transformer ces deux en PDF, puis calculez l'entropie en utilisant l'équation standard (comme ci-dessus).


Comment puis-je enfin calculer les informations mutuelles?

Pour enfin calculer les informations mutuelles, vous allez avoir besoin de l'entropie des deux images. Vous pouvez utiliser la fonction intégrée entropy de MATLAB, mais cela suppose qu'il existe 256 niveaux uniques. Vous voudrez probablement appliquer cela pour le cas où il y a N niveaux distincts au lieu de 256, et vous pouvez donc utiliser ce que nous avons fait ci-dessus avec l'histogramme commun, puis calculer les histogrammes pour chaque image dans le code ci-dessus ci-dessus , puis calculer l'entropie pour chaque image. Vous devez simplement répéter le calcul d'entropie utilisé conjointement, mais l'appliquer à chaque image individuellement:

%// 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;

J'espère que cela t'aides!