24 Stimmen

Algorithmen für das Downsampling von Bildern

Welches ist der beste Re-Sampling-Algorithmus, den ich verwenden kann, um ein Bild in die Hälfte seiner ursprünglichen Größe zu unterteilen? Die Geschwindigkeit ist von größter Bedeutung, aber die Qualität sollte nicht zu sehr darunter leiden. Ich versuche im Grunde, eine Bildpyramide zu erzeugen.

Ursprünglich hatte ich vor, die Pixel auszulassen. Ist das der beste Weg? Nach dem, was ich gelesen habe, ist das durch das Überspringen von Pixeln erzeugte Bild zu scharf. Könnte jemand, der dies ausprobiert hat, etwas dazu sagen? Meine Bilder enthalten Kartendaten in der Art von dies.

39voto

Mark Ransom Punkte 283960

Das Überspringen von Pixeln führt zu Aliasing, bei dem hochfrequente Änderungen (z. B. abwechselnd helle und dunkle Bänder) in niedrige Frequenzen umgewandelt werden (z. B. konstant hell oder dunkel).

Der schnellste Weg, das Bild ohne Aliasing auf die Hälfte zu verkleinern, besteht darin, 2x2 Pixel zu einem einzigen Pixel zu mitteln. Bessere Ergebnisse lassen sich mit ausgefeilteren Verkleinerungskernen erzielen, aber das geht auf Kosten der Geschwindigkeit.

Im Folgenden finden Sie einige Beispiele für die bisher besprochenen Techniken.

Wenn man jeden zweiten Pixel überspringt, kann man sehen, dass die Ergebnisse nicht sehr gut sind, wenn man sich die Legende auf der linken Seite ansieht. Sie ist fast unleserlich:

Skipping every other pixel

Mittelwertbildung in jedem 2x2-Raster - Der Text ist jetzt scharf und gut lesbar:

Average 2x2

Gaußscher Weichzeichner, wie vorgeschlagen von R. - ein wenig unschärfer, aber bis zu einem gewissen Grad besser lesbar. Der Grad der Unschärfe kann angepasst werden, um unterschiedliche Ergebnisse zu erzielen:

Gaussian blur followed by pixel selection

R. Es ist auch richtig, dass die Gamma-Kurve die Ergebnisse beeinflusst, aber dies sollte nur bei den anspruchsvollsten Anwendungen sichtbar sein. Meine Beispiele wurden ohne Gammakorrektur erstellt.

Bearbeiten: Und hier ist ein Beispiel für einen anspruchsvolleren, aber langsamen Kernel, einen Lanczos-5 in einem linearen (nicht Gamma-angepassten) Farbraum durchgeführt.

Lanczos-5 in linear space

Der Kontrast in der Schrift ist geringer, wahrscheinlich wegen der Umstellung der Farbräume. Aber sehen Sie sich das Detail der Küstenlinie an.

6voto

Für das Downscaling ist die Flächenmittelung (siehe Marks Antwort) fast das Beste, was Sie bekommen können.

Der wichtigste andere Anwärter ist Gauß, der einen etwas größeren Radius hat. Dies erhöht die Unschärfe ein wenig, was als Nachteil angesehen werden könnte, würde aber die Unschärfe gleichmäßiger und nicht von der Ausrichtung der Pixel mod 2 abhängig machen.

Falls es nicht sofort klar ist, was ich meine, betrachten Sie die Pixelmuster 0,0,2,2,0,0 und 0,0,0,2,2,0. Bei der Flächenmittelung würden sie zu 0,2,0 bzw. 0,1,1 herunterskaliert, d. h. eines wäre scharf und hell, das andere unscharf und dunkel. Bei Verwendung eines längeren Filters sind beide unscharf, aber sie sehen sich ähnlicher, was für den menschlichen Betrachter vermutlich wichtig ist.

Ein weiterer Punkt, der zu berücksichtigen ist, ist Gamma. Wenn Gamma nicht linear ist, werden zwei Pixel mit der Intensität k hat eine viel geringere Gesamtintensität als ein einzelnes Pixel der Intensität 2*k . Wenn Ihr Filter eine ausreichende Unschärfe erzeugt, ist das vielleicht nicht so wichtig, aber mit einem einfachen Flächenmittelwertfilter kann es ein großes Problem sein. Die einzige Lösung, die ich kenne, ist die Anwendung und Umkehrung der Gammakurve vor und nach der Skalierung...

5voto

Thilo Köhler Punkte 3611

Wenn Geschwindigkeit ein Thema ist, empfehle ich, wie erwähnt, einen 2x2-Block zu nehmen und den Durchschnitt als resultierenden Pixel zu berechnen. Die Qualität ist nicht die beste, die erreicht werden kann, aber nahe dran. Man kann diesen Algorithmus provozieren, damit er seine Schwächen zeigt, aber bei den meisten Bildern wird man keinen Unterschied sehen, der die um ein Vielfaches höhere Berechnungszeit rechtfertigen würde. Sie haben auch keinen Speicher-Overhead. Wenn die Farbauflösung auf 6 Bit pro Kanal gesenkt werden kann, gibt es einen ziemlich schnellen Weg, der die Zerlegung der ARGB-Kanäle verhindert (hier wird von 32 Bit ARGB ausgegangen):

destPixel[x,y] = ((sourcePixel[2*x  ,2*y  ]>>2)&0x3f3f3f3f) +
                 ((sourcePixel[2*x+1,2*y  ]>>2)&0x3f3f3f3f) +
                 ((sourcePixel[2*x  ,2*y+1]>>2)&0x3f3f3f3f) +
                 ((sourcePixel[2*x+1,2*y+1]>>2)&0x3f3f3f3f);

Ein Nebeneffekt dieses Algorithmus ist, dass die Dateigröße beim Speichern als PNG kleiner wird. So sieht es aus: Test image downscaled with the above algorithm

2voto

Ich habe versucht, die Lösung von Thilo Köhler zu verallgemeinern (allerdings in Python):

STRIDE = 2
MASK = 0x3F3F3F3F
color = 0
for x, y in itertools.product(range(STRIDE), repeat=2):
    color += (get_pixel(x + x, y + y) // STRIDE) & MASK

Dies funktioniert gut für die Skalierung durch 2 (Viertel Größe Ergebnis), aber nicht für die Skalierung durch 3 oder 4 oder andere int Werte. Ist es möglich, dies zu verallgemeinern?

BTW für Nicht-Pythonisten ist die obige for-Schleife äquivalent zu dieser (außer dass die erste Version durch Ändern der STRIDE skalierbar ist):

for x, y in [(0, 0), (0, 1), (1, 0), (1, 1)]:
    color += (get_pixel(x + x, y + y) // STRIDE) & MASK

Ich verwende 32-Bit-ARGB-Werte.

1voto

Nemo Punkte 67866

En NetPBM-Suite enthält ein Dienstprogramm namens pamscale die einige Optionen für das Downsampling bietet. Es ist quelloffen, Sie können also die verschiedenen Optionen ausprobieren und dann den Algorithmus kopieren, der Ihnen am besten gefällt (oder einfach libnetpbm verwenden).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X