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
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.
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.
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.
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.
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