2014-05-16 10 views
16

Ich habe zwei Schwarz-Weiß-Bilder und ich muss die gegenseitigen Informationen berechnen.Gegenseitige Information und gemeinsame Entropie von zwei Bildern - MATLAB

Image 1 = X 
Image 2 = Y 

Ich weiß, dass die gegenseitige Information definiert werden kann als:

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

MATLAB bereits hat eingebaute Funktionen, die Entropie zu berechnen, aber nicht die gemeinsame Entropie zu berechnen. Ich denke, die wahre Frage ist: Wie berechne ich die gemeinsame Entropie von zwei Bildern? Hier

ist ein Beispiel für die Bilder Ich mag würde die gemeinsame Entropie finden:

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

Wenn Ihre Bildintensitäten im Bereich von '[0,1]' liegen, können Sie immer noch den Code verwenden, den ich unten geschrieben habe, aber Sie müssen sicherstellen, dass die Intensitäten ganze Zahlen sind. Wenn Sie 8-Bit-Bilder haben, verwenden Sie "im2uint8", bevor Sie durchgehen, was ich getan habe. – rayryeng

+0

Wenn Ihr Bild rein binär ist, konvertieren Sie es nicht mit 'im2uint8', da dies eine Verschwendung von Speicherplatz wäre. Sie können den Code unverändert verwenden. Belassen Sie es als ein Histogramm mit 4 gemeinsamen Behältern, anstatt "256 x 256" zu haben. – rayryeng

+0

Vielen Dank für Ihre Hilfe. Ich multiplizierte mein Bild mit 100 und rundete dann die Zahl + 1 -> Im1 = rund (100 * Im0 + 1) Auf diese Weise reparierte ich alle Fehler 1) der Code will ganze Zahlen 2) er will positive Werte. : D – Jorge

Antwort

49

die gemeinsame Entropie zu berechnen, müssen Sie das gemeinsame Histogramm zwischen zwei Bildern berechnen. Das Verbindungshistogramm ist im Wesentlichen dasselbe wie ein normales 1D-Histogramm, aber die erste Dimension protokolliert Intensitäten für das erste Bild und die zweite Dimension protokolliert Intensitäten für das zweite Bild. Dies ist sehr ähnlich zu dem, was allgemein als co-occurrence matrix bezeichnet wird. An der Stelle (i,j) im Gelenkhistogramm wird angegeben, wie viele Intensitätswerte wir im ersten Bild mit der Intensität i und im zweiten Bild mit der Intensität j haben.

Wichtig ist, dass protokolliert wird, wie oft wir dieses Intensitätenpaar an den gleichen Stellen gesehen haben. Wenn wir zum Beispiel eine gemeinsame Histogrammzählung von (7,3) = 2 haben, bedeutet dies, dass, wenn wir beide Bilder scannten, wenn wir die Intensität von 7 an der gleichen entsprechenden Stelle im zweiten Bild trafen, die Intensität von 3 insgesamt auftraten von 2 mal.

Der Aufbau eines gemeinsamen Histogramms ist sehr einfach.

  1. Zuerst erstellen Sie eine 256 x 256 Matrix (vorausgesetzt, Ihr Bild ist 8-Bit-Integer ohne Vorzeichen) und initialisieren Sie sie auf alle Nullen. Außerdem müssen Sie sicherstellen, dass beide Bilder die gleiche Größe (Breite und Höhe) haben.
  2. Sobald Sie das tun, werfen Sie einen Blick auf den ersten Pixel jedes Bildes, die wir als die obere linke Ecke bezeichnen. Schauen Sie sich speziell die Intensitäten für das erste und zweite Bild an diesem Ort an. Die Intensität des ersten Bildes wird als die Zeile dienen, während die Intensität des zweiten Bildes als die Spalte dienen wird.
  3. Suchen Sie diese Stelle in der Matrix und inkrementieren Sie diesen Punkt in der Matrix um 1.
  4. Wiederholen Sie dies für den Rest der Standorte in Ihrem Bild.
  5. Nachdem Sie fertig sind, teilen Sie alle Einträge durch die Gesamtzahl der Elemente in einem Bild (denken Sie daran, sie sollten die gleiche Größe haben). Dies gibt uns die gemeinsame Wahrscheinlichkeitsverteilung zwischen beiden Bildern.

Man würde geneigt sein, dies mit for Schleifen zu tun, aber wie es allgemein bekannt ist, for Schleifen sind notorisch langsam und sollten wenn möglich vermieden werden. Sie können dies jedoch problemlos in MATLAB auf folgende Weise durchführen: ohne Schleifen. Nehmen wir an, dass im1 und im2 das erste und zweite Bild sind, mit denen Sie vergleichen möchten. Was wir tun können, ist im1 und im2 in Vektoren zu konvertieren.Wir können dann accumarray verwenden, um uns bei der Berechnung des Gelenkhistogramms zu helfen. accumarray ist eine der mächtigsten Funktionen in MATLAB. Sie können es sich als ein Miniatur-MapReduce-Paradigma vorstellen. Einfach gesagt, jede Dateneingabe hat einen Schlüssel und einen zugehörigen Wert. Das Ziel von accumarray ist, alle Werte, die zu demselben Schlüssel gehören, zu übernehmen und einige Operationen für alle diese Werte auszuführen. In unserem Fall wären der "Schlüssel" die Intensitätswerte und die Werte selbst der Wert 1 für jeden Intensitätswert. Wir möchten dann hinzufügen bis alle Werte von 1, die auf den gleichen bin zuordnen, das ist genau, wie wir ein Histogramm berechnen würden. Das Standardverhalten für accumarray besteht darin, alle diese Werte hinzuzufügen. Insbesondere wäre die Ausgabe von accumarray ein Array, in dem jede Position die Summe aller Werte berechnet, die diesem Schlüssel zugeordnet sind. Zum Beispiel wäre die erste Position die Summe aller Werte, die dem Schlüssel von 1 zugeordnet sind, die zweite Position wäre die Summe aller Werte, die dem Schlüssel von 2 zugeordnet sind, und so weiter.

Allerdings möchten Sie für das gemeinsame Histogramm herausfinden, welche Werte auf das gleiche Intensitätspaar von (i,j) abgebildet werden, und daher wären die Schlüssel hier ein Paar 2D-Koordinaten. Als solche werden alle Intensitäten, die eine Intensität von i in dem ersten Bild und j in dem zweiten Bild in dem gleichen räumlichen Ort haben, der zwischen den zwei Bildern geteilt wird, zu demselben Schlüssel verwendet. Im 2D-Fall wäre die Ausgabe von accumarray also eine 2D-Matrix, in der jedes Element (i,j) die Summe aller Werte enthält, die dem Schlüssel (i,j) zugeordnet sind, ähnlich dem zuvor erwähnten 1D-Fall, der genau das ist, wonach wir suchen.

Mit anderen Worten:

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

Mit accumarray, der erste Eingang sind die Schlüssel und der zweite Eingang sind die Werte. Eine Notiz mit accumarray ist, dass, wenn jeder Schlüssel den selben Wert hat, Sie einfach eine Konstante dem zweiten Eingang zuweisen können, was ich getan habe und es ist 1. Im Allgemeinen ist dies ein Array mit der gleichen Anzahl von Zeilen wie die erste Eingabe. Beachten Sie auch die ersten beiden Zeilen. Es wird unvermeidlich eine Intensität von 0 in Ihrem Bild sein, aber da MATLAB die Indizierung bei 1 beginnt, müssen wir beide Arrays um 1 versetzen.

Jetzt haben wir das gemeinsame Histogramm, es ist wirklich einfach, die gemeinsame Entropie zu berechnen. Es ist ähnlich der Entropie in 1D, nur dass wir jetzt nur über die gesamte gemeinsame Wahrscheinlichkeitsmatrix summieren. Denken Sie daran, dass es sehr wahrscheinlich ist, dass Ihr gemeinsames Histogramm viele 0 Einträge enthält. Wir müssen sicherstellen, dass wir diese überspringen oder die log2 Operation wird undefiniert sein. Lassen Sie uns jetzt alle Nulleinträge loswerden:

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

Beachten Sie, dass ich das gemeinsame Histogramm statt der gemeinsamen Wahrscheinlichkeitsmatrix durchsucht habe. Dies liegt daran, dass das gemeinsame Histogramm aus ganzen Zahlen besteht, während die gemeinsame Wahrscheinlichkeitsmatrix zwischen 0 und 1 liegt. Wegen der Division möchte ich vermeiden, irgendwelche Einträge in dieser Matrix mit 0 aufgrund numerischer Abrundung und Instabilität zu vergleichen. Das Obige wird auch unsere gemeinsame Wahrscheinlichkeitsmatrix in einen gestapelten 1D-Vektor umwandeln, was in Ordnung ist.

Als solches kann die gemeinsame Entropie berechnet werden als:

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

Wenn mein Verständnis Entropie für ein Bild in MATLAB für die Berechnung korrekt ist, sollte es die Histogramm/Wahrscheinlichkeitsverteilung über 256 Bins berechnen, so dass Sie kann diese Funktion hier mit der gerade errechneten Gelenkentropie durchaus verwenden.

Was ist, wenn wir stattdessen Gleitkommadaten haben?

Bisher haben wir angenommen, dass die Bilder, mit denen Sie gearbeitet haben, Intensitäten haben, die ganzzahlig sind. Was ist, wenn wir Fließkommadaten haben? accumarray geht davon aus, dass Sie versuchen, mit Ganzzahlen in das Ausgangsarray zu indizieren, aber wir können immer noch mit Sicherheit erreichen, was wir mit diesem kleinen Schlag auf der Straße wollen. Was Sie tun würden, ist einfach jeden Gleitkommawert in beiden Bildern zuzuweisen, um eine eindeutige ID zu haben. Sie würden also accumarray stattdessen mit diesen IDs verwenden. Um diese ID-Zuweisung zu erleichtern, verwenden Sie unique - speziell die dritte Ausgabe der Funktion. Sie würden jedes der Bilder nehmen, sie in unique setzen und diese zu den Indizes machen, die in accumarray eingegeben werden sollen. Mit anderen Worten, dies zu tun, statt:

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

Beachten Sie, dass mit indrow und indcol sind wir direkt die dritte Ausgabe von unique auf diese Variablen zuweisen und dann die gleiche Verbundentropie Code aus, den wir früher berechnet. Außerdem müssen wir die Variablen nicht wie bisher um 1 versetzen, da unique die IDs ab 1 zuweisen.

Neben

Sie können die Histogramme oder Wahrscheinlichkeitsverteilungen für jedes Bild tatsächlich berechnen individuell die gemeinsame Wahrscheinlichkeitsmatrix. Wenn Sie die Histogramme/Wahrscheinlichkeitsverteilungen für das erste Bild berechnen möchten, würden Sie einfach alle Spalten für jede Zeile akkumulieren. Um dies für das zweite Bild zu tun, würden Sie einfach alle Zeilen für jede Spalte akkumulieren. Als solche können Sie tun:

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

Nachdem Sie die Entropie diese beiden selbst berechnen kann. Um dies zu überprüfen, stellen Sie sicher, dass Sie beide in PDFs umwandeln und berechnen Sie dann die Entropie mithilfe der Standardgleichung (wie oben).


Wie berechne ich schließlich gegenseitige Informationen?

Um schließlich gegenseitige Informationen zu berechnen, benötigen Sie die Entropie der beiden Bilder. Sie können die in MATLAB integrierte Funktion entropy verwenden, aber dies setzt voraus, dass es 256 eindeutige Ebenen gibt. Wahrscheinlich möchten Sie dies für den Fall anwenden, dass N unterschiedliche Stufen statt 256 sind, und Sie können also das, was wir oben mit dem gemeinsamen Histogramm gemacht haben, verwenden, dann die Histogramme für jedes Bild in dem obigen Seitencode berechnen und dann berechnen Entropie für jedes Bild. Sie würden einfach die Entropie Berechnung wiederholen, die gemeinsam verwendet wurde, sondern gilt es individuell auf jedes Bild:

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

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

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

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

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

hoffe, das hilft!

+2

Schöne Alternative zu 'For' Loops. – eigenchris

+3

Das ist fast ein Spam-Kommentar, aber ich musste sagen: Das ist eine der besten Antworten, die ich auf SO gefunden habe. es erklärt kurz den Hintergrund, die Logik hinter dem Code und geht vom einfachen (ganzzahligen) zum härteren tatsächlichen Fall (reell bewertet). Auch eines der saubersten Beispiele für die Verwendung von 'accumarray'. – AruniRC

+0

@ArunIRC vielen Dank :) Das war eigentlich eine meiner früheren Antworten, als ich anfing, Fragen zu beantworten. Ich habe nie erwartet, dass dies so beliebt ist. Tatsächlich hat die aktuelle Version, die Sie jetzt sehen, viele Änderungen von der ursprünglichen Version. Ich habe nur für den Integer-Fall gelöst und nur für das Joint-Histogramm gelöst. Ich habe dies im Laufe der Zeit bearbeitet und den Gleitkomma-Fall einbezogen und schließlich die gegenseitige Information berechnet. Wie auch immer, danke für den Kommentar :) schätze es sehr. – rayryeng