Wie verwische ich ein Bild gaußsch, ohne eingebaute gaußsche Funktionen zu verwenden?

Lesezeit: 6 Minuten

Benutzeravatar von Moeb
Möb

Ich möchte mein Bild mit der nativen Gaußschen Unschärfeformel verwischen. ich lese der Wikipedia-Artikelaber ich bin mir nicht sicher, wie ich das umsetzen soll.

Wie verwende ich die Formel, um Gewichte zu bestimmen?

Ich möchte keine eingebauten Funktionen wie die von MATLAB verwenden

  • Grundsätzlich müssen Sie einen Faltungsoperator implementieren, der dem entspricht conv2() Funktion in MATLAB. Da jedoch 2D-Gaußian in zwei 1D-Gaußian getrennt werden kann, ist alles, was Sie brauchen, eine Implementierung der Faltungsfunktion auf 1D, gekoppelt mit der richtigen Kernel-Matrix.

    – Amro

    8. November 2009 um 12:13 Uhr

Benutzeravatar von Goz
Göz

Das Schreiben einer naiven Gaußschen Unschärfe ist eigentlich ziemlich einfach. Es wird genau wie bei jedem anderen Faltungsfilter durchgeführt. Der einzige Unterschied zwischen einem Box- und einem Gaußschen Filter ist die verwendete Matrix.

Stellen Sie sich vor, Sie haben ein Bild, das wie folgt definiert ist:

 0  1  2  3  4  5  6  7  8  9
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
30 31 32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47 48 49
50 51 52 53 54 55 56 57 58 59
60 61 62 63 64 65 66 67 68 69
70 71 72 73 74 75 76 77 78 79
80 81 82 83 84 85 86 87 88 89
90 91 92 93 94 95 96 97 98 99

Eine 3×3-Box-Filtermatrix ist wie folgt definiert:

0.111 0.111 0.111
0.111 0.111 0.111
0.111 0.111 0.111

Um die Gaußsche Unschärfe anzuwenden, würden Sie Folgendes tun:

Für Pixel 11 müssten Sie die Pixel 0, 1, 2, 10, 11, 12, 20, 21, 22 laden.

Sie würden dann Pixel 0 mit dem oberen linken Teil des 3×3-Unschärfefilters multiplizieren. Pixel 1 oben in der Mitte, Pixel 2, Pixel 3 oben rechts, Pixel 10 in der Mitte links und so weiter.

Addieren Sie sie dann zusammen und schreiben Sie das Ergebnis in Pixel 11. Wie Sie sehen können, ist Pixel 11 jetzt der Durchschnitt von sich selbst und den umgebenden Pixeln.

Randfälle werden etwas komplexer. Welche Werte verwenden Sie für die Werte der Kante der Textur? Eine Möglichkeit kann sein, auf die andere Seite zu wickeln. Das sieht gut aus für ein Bild, das später gekachelt wird. Eine andere Möglichkeit besteht darin, das Pixel in die umgebenden Stellen zu schieben.

Oben links könnten Sie die Samples also wie folgt platzieren:

 0  0  1
 0  0  1
10 10 11

Ich hoffe, Sie können sehen, wie dies leicht auf große Filterkerne (dh 5×5 oder 9×9 usw.) erweitert werden kann.

Der Unterschied zwischen einem Gaußschen Filter und einem Boxfilter sind die Zahlen, die in die Matrix eingehen. Ein Gaußscher Filter verwendet eine Gaußsche Verteilung über eine Zeile und eine Spalte.

z. B. für einen willkürlich definierten Filter (dh dies ist kein Gauß, aber wahrscheinlich nicht weit davon entfernt)

0.1 0.8 0.1

die erste Spalte wäre die gleiche, aber mit dem ersten Element der darüber liegenden Zeile multipliziert.

0.01 0.8 0.1
0.08 
0.01 

Die zweite Spalte wäre dieselbe, aber die Werte würden mit 0,8 in der Zeile darüber multipliziert (und so weiter).

0.01 0.08 0.01
0.08 0.64 0.08
0.01 0.08 0.01

Das Ergebnis der Addition aller obigen Punkte sollte gleich 1 sein. Der Unterschied zwischen dem obigen Filter und dem ursprünglichen Box-Filter wäre, dass das geschriebene Endpixel eine viel stärkere Gewichtung in Richtung des zentralen Pixels (dh des Pixels, das sich an dieser Position befindet) hätte schon). Die Unschärfe tritt auf, weil die umgebenden Pixel in dieses Pixel verschwimmen, wenn auch nicht so stark. Mit dieser Art von Filter erhalten Sie eine Unschärfe, die jedoch nicht so viel von der hochfrequenten Information (dh schneller Farbwechsel von Pixel zu Pixel) zerstört.

Diese Art von Filtern kann viele interessante Dinge tun. Mit dieser Art von Filter können Sie eine Kantenerkennung durchführen, indem Sie die umgebenden Pixel vom aktuellen Pixel subtrahieren. Damit bleiben nur die wirklich großen Farbveränderungen (hohe Frequenzen) zurück.

Bearbeiten: Ein 5×5-Filterkernel ist genau wie oben definiert.

Wenn Ihre Zeile z. B. 0,1 0,2 0,4 0,2 0,1 ist, dann multiplizieren Sie jeden Wert in ihr mit dem ersten Element, um eine Spalte zu bilden, und multiplizieren Sie dann jeden Wert mit dem zweiten Element, um die zweite Spalte zu bilden, und so weiter, Sie erhalten einen Filter von

0.01 0.02 0.04 0.02 0.01
0.02 0.04 0.08 0.04 0.02
0.04 0.08 0.16 0.08 0.04
0.02 0.04 0.08 0.04 0.02
0.01 0.02 0.04 0.02 0.01

Wenn Sie einige willkürliche Positionen einnehmen, können Sie sehen, dass Position 0, 0 einfach 0,1 * 0,1 ist. Position 0, 2 ist 0,1 * 0,4, Position 2, 2 ist 0,4 * 0,4 und Position 1, 2 ist 0,2 * 0,4.

Ich hoffe, das gibt Ihnen eine ausreichend gute Erklärung.

  • @Goz Angenommen, ich möchte einen 5×5-Filterkern verwenden. Wie berechne ich die Gewichte, die in den Filter gelangen sollen?

    – Möb

    8. November 2009 um 12:18 Uhr

  • Hätte das Stichwort erwähnen können: Neuronale Netze beziehungsweise künstliche neurale Netzwerke.

    – Bitter blau

    11. März 2015 um 12:45 Uhr

  • @bitterblue: Können Sie erklären, warum neuronale Netze etwas mit der Bildraumfilterung zu tun haben?

    – Göz

    11. März 2015 um 14:29 Uhr

  • @Bitterblau: Wirklich. Wie? Neuronale Netze sind ein maschineller Lernalgorithmus. Hier geht es um die 2D-Bildraumfilterung.

    – Göz

    11. März 2015 um 16:59 Uhr

  • @Bitterblue: Richtig, Sie können Filter verwenden, um Funktionen für maschinelles Lernen zu extrahieren. Für diese Frage ist es jedoch immer noch völlig irrelevant …

    – Göz

    23. März 2015 um 9:59 Uhr

Benutzeravatar von Cecil hat einen Namen
Cecil hat einen Namen

Hier ist der Pseudocode für den Code, den ich in C# verwendet habe, um den Kernel zu berechnen. Ich wage aber nicht zu behaupten, dass ich die Endbedingungen richtig behandle:

double[] kernel = new double[radius * 2 + 1];
double twoRadiusSquaredRecip = 1.0 / (2.0 * radius * radius);
double sqrtTwoPiTimesRadiusRecip = 1.0 / (sqrt(2.0 * Math.PI) * radius);
double radiusModifier = 1.0;

int r = -radius;
for (int i = 0; i < kernel.Length; i++)
{
    double x = r * radiusModifier;
    x *= x;
    kernel[i] = sqrtTwoPiTimesRadiusRecip * Exp(-x * twoRadiusSquaredRecip);
    r++;
}

double div = Sum(kernel);
for (int i = 0; i < kernel.Length; i++)
{
    kernel[i] /= div;
}

Hoffe das hilft.

  • Ich glaube, dass diese Zeile: sqrtTwoPiTimesRadiusRecip * Exp(-x * sqrtTwoPiTimesRadiusRecip); muss sein: sqrtTwoPiTimesRadiusRecip * Exp(-x * twoRadiusSquaredRecip);

    – Ashagi

    30. Juni 2011 um 6:07 Uhr


  • Die Multiplikation mit sqrtTwoPiTimesRadiusRecip wird überhaupt nicht benötigt, da Sie den Kernel sowieso normalisieren.

    – Emily L.

    21. Oktober 2014 um 17:52 Uhr

  • @Simson, ich bin mir nicht sicher, was Ihre Bearbeitung bewirkt hat, abgesehen davon, dass Sie mir die Anerkennung dafür nehmen, dass Sie es offiziell vorgeschlagen haben, nachdem ich mit dem Code meines Kollegen auf dasselbe Problem gestoßen bin

    – Charly G

    10. April 2020 um 1:38 Uhr

  • @Charlie meine Bearbeitung hat dir sofort +2 an Reputation gegeben, da deine Bearbeitung nicht auf die Bestätigung eines zweiten Prüfers warten musste, wenn ich auf „Bearbeitung verbessern“ klicke. Wenn bei einem Beitrag in der Überprüfungswarteschlange noch etwas zu tun ist, können Sie es auf diese Weise beheben. Überprüfen Sie den Bearbeitungsverlauf, es wird Ihnen kein Guthaben gestohlen.

    – Simson

    10. April 2020 um 3:17 Uhr


  • @Simson Ich verstehe, aber ich hatte einen Machttrip darüber, dass mein Name / Bild auf der Fragenseite steht, nicht nur in der Geschichte: (hah, oh, danke für die Erklärung

    – Charly G

    10. April 2020 um 3:59 Uhr

Um den im Wikipedia-Artikel besprochenen Filterkern zu verwenden, müssen Sie (diskret) implementieren Faltung. Die Idee ist, dass Sie eine kleine Wertematrix (den Kernel) haben, diesen Kernel im Bild von Pixel zu Pixel verschieben (dh so, dass die Mitte der Matrix auf dem Pixel liegt), die Matrixelemente mit dem überlappenden Bild multiplizieren Elemente, summieren alle Werte im Ergebnis und ersetzen den alten Pixelwert durch diese Summe.

Die Gaußsche Unschärfe kann in zwei 1D-Falten (eine vertikale und eine horizontale) anstelle einer 2D-Faltung getrennt werden, was die Dinge auch etwas beschleunigt.

Mir ist nicht klar, ob Sie dies einschränken wollen zu bestimmte Technologien, aber wenn nicht SVG (Skalierbare Vektorgrafiken) hat eine Implementierung von Gaußian Blur. Ich glaube, es gilt für alle Grundelemente einschließlich Pixel. SVG hat den Vorteil, ein offener Standard zu sein und weit verbreitet zu sein.

Benutzeravatar von Royi
Royi

Nun, Gaussian Kernel ist ein trennbarer Kernel.
Daher brauchen Sie nur eine Funktion, die trennbare 2D-Faltung unterstützt, wie – ImageConvolutionSeparableKernel().

Sobald Sie es haben, brauchen Sie nur noch einen Wrapper, um den 1D-Gaußschen Kernel zu generieren und ihn wie in ausgeführt an die Funktion zu senden ImageConvolutionGaussianKernel().

Der Code ist eine einfache C-Implementierung der 2D-Bildfaltung, die durch SIMD (SSE) und Multi-Threading (OpenMP) beschleunigt wird.

Das gesamte Projekt ist gegeben durch – Bildfaltung – GitHub.

1413090cookie-checkWie verwische ich ein Bild gaußsch, ohne eingebaute gaußsche Funktionen zu verwenden?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy