Was ist der beste Bild-Downscaling-Algorithmus (qualitativ)?

78

Ich möchte herausfinden, welcher Algorithmus der beste ist, um ein Rasterbild zu verkleinern. Mit best meine ich die, die die schönsten Ergebnisse liefert. Ich weiß von Bikubik, aber gibt es noch etwas Besseres? Ich habe zum Beispiel von einigen Leuten gehört, dass Adobe Lightroom über einen proprietären Algorithmus verfügt, der bessere Ergebnisse liefert als die von mir verwendete Standard-Bikubik. Leider möchte ich diesen Algorithmus selbst in meiner Software verwenden, sodass die sorgfältig gehüteten Geschäftsgeheimnisse von Adobe nicht ausreichen.

Hinzugefügt:

Ich habe Paint.NET ausgecheckt und zu meiner Überraschung scheint Super Sampling beim Verkleinern eines Bildes besser als bikubisch zu sein. Das lässt mich fragen, ob Interpolationsalgorithmen überhaupt der richtige Weg sind.

Es erinnerte mich auch an einen Algorithmus, den ich selbst "erfunden", aber nie implementiert hatte. Ich nehme an, es hat auch einen Namen (als etwas, das dieses Triviale nicht allein für mich sein kann), aber ich konnte es unter den populären nicht finden. Super Sampling war das nächste.

Die Idee ist folgende: Berechnen Sie für jedes Pixel im Zielbild, wo es sich im Quellbild befinden würde. Es würde wahrscheinlich ein oder mehrere andere Pixel überlagern. Es wäre dann möglich, die Flächen und Farben dieser Pixel zu berechnen. Um dann die Farbe des Zielpixels zu erhalten, würde man einfach den Durchschnitt dieser Farben berechnen und ihre Bereiche als "Gewichte" hinzufügen. Wenn also ein Zielpixel 1/3 eines gelben Quellpixels und 1/4 eines grünen Quellpixels abdecken würde, würde ich (1/3 * gelb + 1/4 * grün) / (1/3 +) erhalten 1/4).

Dies wäre natürlich rechenintensiv, sollte aber dem Ideal so nahe wie möglich kommen, oder?

Gibt es einen Namen für diesen Algorithmus?

Vilx-
quelle
1
Sie beschreiben, wie Supersampling genau funktioniert. Es ist nicht besser als bikubisch, da bikubisch mehr Pixel aus dem Quellbild berücksichtigt.
homm
1
Ich stimme dafür, diese sehr alte Frage wieder zu eröffnen, da es eine gute ist. "Sieht am besten aus" klingt subjektiv, aber Leute, die dies studieren, quantifizieren es ausreichend, um gute, nicht subjektive und konsensorientierte Antworten zu erhalten.
Tom10
@ tom10 - Nun, ehrlich gesagt denke ich, dass die Lanczos-Option für die meisten Zwecke bereits gut genug ist.
Vilx

Antworten:

75

Leider kann ich keinen Link zur ursprünglichen Umfrage finden, aber als Hollywood-Kameramänner von Film zu digitalen Bildern wechselten, tauchte diese Frage häufig auf, sodass jemand (vielleicht SMPTE, vielleicht der ASC) eine Reihe professioneller Kameramänner sammelte und ihnen Filmmaterial zeigte das war mit einer Reihe verschiedener Algorithmen neu skaliert worden. Das Ergebnis war, dass für diese Profis, die sich riesige Filme ansehen, der Konsens bestand, dass Mitchell (auch als hochwertiger Catmull-Rom bekannt) am besten zum Vergrößern und sinc am besten zum Verkleinern geeignet ist. Aber sinc ist ein theoretischer Filter, der bis ins Unendliche reicht und daher nicht vollständig implementiert werden kann. Daher weiß ich nicht, was sie eigentlich mit "sinc" gemeint haben. Es bezieht sich wahrscheinlich auf eine abgeschnittene Version von sinc. Lanczosist eine von mehreren praktischen Varianten von sinc, die versuchen, das Abschneiden zu verbessern, und wahrscheinlich die beste Standardoption zum Verkleinern von Standbildern ist. Aber wie üblich hängt es vom Bild und Ihren Wünschen ab: Das Verkleinern einer Strichzeichnung, um Linien zu erhalten, ist beispielsweise ein Fall, in dem Sie möglicherweise die Betonung der Kanten bevorzugen, die beim Verkleinern eines Blumenfotos unerwünscht wären.

Es gibt ein gutes Beispiel für die Ergebnisse verschiedener Algorithmen in Cambridge in Color .

Die Leute von fxguide haben viele Informationen zu Skalierungsalgorithmen zusammengestellt (zusammen mit vielen anderen Dingen über Compositing und andere Bildverarbeitung), die einen Blick wert sind. Sie enthalten auch Testbilder, die bei der Durchführung eigener Tests hilfreich sein können.

Jetzt hat ImageMagick eine umfangreiche Anleitung zum Resampling von Filtern, wenn Sie wirklich darauf eingehen möchten.

Es ist irgendwie ironisch, dass es mehr Kontroversen über das Verkleinern eines Bildes gibt, was theoretisch perfekt möglich ist, da Sie nur Informationen wegwerfen, als über das Vergrößern, wenn Sie versuchen, Informationen hinzuzufügen, die dies nicht tun. t existieren. Aber fangen Sie mit Lanczos an.

Alter Pro
quelle
Ich möchte darauf hinweisen, dass der Sinc-Filter ohne Abschneiden von Signalen mit endlicher Ausdehnung implementiert werden kann. Wenn wir annehmen, dass außerhalb der uns bekannten Region alle Stichproben Null sind, verschwinden die zusätzlichen Terme in der Whittaker-Shannon-Interpolationsformel und wir erhalten eine endliche Summe. Dies ist eine gültige Interpretation der Originaldaten, auch wenn diese wahrscheinlich falsch ist (die Welt ist außerhalb unseres Sichtfelds nicht schwarz). Dieser Filter kann immer noch nicht für Live-Audio und -Video verwendet werden, da er nicht kausal ist, sondern für die Verwendung in Bildern, die keine Rolle spielen.
Tim Seguine
Ich bin zu spät zur Party, aber hier ist meine Meinung dazu. Es gibt nur einen geeigneten Weg, um ein Bild zu verkleinern, und es ist eine Kombination aus zwei Methoden. 1) um x2 verkleinern, weiter verkleinern, bis die nächste Verkleinerung kleiner als die Zielgröße ist. Bei jeder Skalierung ist jedes neue Pixel = Durchschnitt von 4 alten Pixeln, dies ist also die maximale Menge an Informationen, die gespeichert werden. 2) Skalieren Sie von diesem letzten um 2 verkleinerten Schritt mithilfe der BILINEAR-Interpolation auf die Zielgröße. Dies ist wichtig, da bilinear überhaupt kein Klingeln verursacht. 3) (ein Bonus) Skalieren Sie im linearen Raum (degamma-> scale down-> regamma).
Alex
@Alex Es gibt keine allgemein "richtige" Möglichkeit, ein Bild zu verkleinern, da es keine universelle Definition dafür gibt, was in einem Bild "wichtig" ist und beibehalten werden sollte, im Vergleich zu dem, was "unwichtig" ist und verworfen werden kann. Ihr Algorithmus eignet sich möglicherweise hervorragend für einige Bilder, verwandelt jedoch eine Schwarzweiß-Strichzeichnung in eine hellgraue Unschärfe.
Old Pro
Nun ja, ich habe über Fotos gesprochen, aber ich denke, es wird auch besser mit Strichzeichnungen umgehen. Sie wissen sicher, dass es nicht klingeln wird. Wie Null. Kein Filter kann dazu passen. Aber ja, für bestimmte Bilder ist es besser, den nächsten Nachbarn oder etwas anderes zu machen, das geeigneter ist als ein universeller Algorithmus.
Alex
@Alex: Außerdem berücksichtigen Sie nicht die Filtereffekte, die ein Algorithmus wie "sinc" hat. Viele Bilder, die Sie mit einer Digitalkamera aufnehmen, weisen Rauschen auf (ziemlich gleichmäßig verteilt), insbesondere wenn Sie Bilder mit hoher ISO-Empfindlichkeit aufnehmen. Dies kann gefiltert werden, wenn ein Bild verkleinert wird.
Unbestimmt
21

Es gibt Lanczos-Sampling, das langsamer als bikubisch ist, aber Bilder mit höherer Qualität erzeugt.

Greg Dean
quelle
Gibt es dafür bereits eine Implementierung in .NET? Würde mir die Zeit sparen. :)
Vilx
@ Vilx- github.com/dlemstra/Magick.NET ich habe es verwendet , und es wroks völlig in Ordnung für lanczos mit (MagickImage Bild = new MagickImage (Pfad)) {image.FilterType = ImageMagick.FilterType.Lanczos; image.Resize (145,145); // Bild als tiff image speichern.Write ("c: /workbackup/jay_Lanczos.png"); }
Jayant Singh
14

(Bi-) lineares und (bi-) kubisches Resampling sind nicht nur hässlich, sondern auch schrecklich falsch, wenn sie um einen Faktor kleiner als 1/2 verkleinert werden. Sie führen zu einem sehr schlechten Aliasing, ähnlich dem, was Sie erhalten würden, wenn Sie um den Faktor 1/2 herunterscameln und dann das Downsampling für den nächsten Nachbarn verwenden würden.

Persönlich würde ich empfehlen, Stichproben für die meisten Downsampling-Aufgaben (flächen-) zu mitteln. Es ist sehr einfach und schnell und nahezu optimal. Gaußsches Resampling (mit einem Radius, der proportional zum Kehrwert des Faktors gewählt wird, z. B. Radius 5 für das Downsampling um 1/5) kann bessere Ergebnisse mit etwas mehr Rechenaufwand liefern und ist mathematisch fundierter.

Ein möglicher Grund für die Verwendung des Gaußschen Resamplings ist, dass es im Gegensatz zu den meisten anderen Algorithmen sowohl beim Upsampling als auch beim Downsampling korrekt funktioniert (keine Artefakte / Aliasing einführt), solange Sie einen Radius auswählen, der dem Resampling-Faktor entspricht. Andernfalls benötigen Sie zur Unterstützung beider Richtungen zwei separate Algorithmen - die Flächenmittelung für das Downsampling (die sich für das Upsampling auf den nächsten Nachbarn verschlechtern würde) und (bi-) kubisch für das Upsampling (das sich für das Downsampling auf den nächsten Nachbarn verschlechtern würde). Eine Möglichkeit, diese schöne Eigenschaft der mathematischen Gaußschen Neuabtastung zu sehen, besteht darin, dass Gauß mit sehr großem Radius der Flächenmittelung und Gauß mit sehr kleinem Radius der (bi-) linearen Interpolation nahekommt.

R .. GitHub HÖREN SIE AUF, EIS ZU HELFEN
quelle
2
Der Radius ist alles wichtig. Der Grund, warum Bicubic beim Downscaling so häufig fehlschlägt, ist, dass der Radius nicht angepasst wird und derselbe Radius, der für das Upsizing verwendet wird, für das Downsizing verwendet wird. Dies funktioniert einfach nicht und ist im Extremfall schlimmer als der nächste Nachbar. Wenn der Radius richtig eingestellt ist, sollte er bessere Ergebnisse liefern als die Flächenmittelung.
Mark Ransom
3
Einem kubischen Filter ist absolut nichts inhärent, was ihn auf 4 Abtastwerte beschränkt. Die Formel funktioniert einwandfrei, wenn Sie sie erweitern und durch die Summe der Gewichte dividieren. Tatsächlich ähnelt Catmull-Rom Lanczos-2 und kann nahezu identisch eingestellt werden.
Mark Ransom
1
@MarkRansom: Die Definition eines kubischen Filters ist eine Annäherung der Kurve durch ein kubisches Polynom, das eindeutig durch 4 beliebige Punkte auf der Kurve definiert ist.
R .. GitHub STOP HELPING ICE
2
Das mag sein, aber die Mathematik kümmert sich nicht darum. Versuchen Sie es irgendwann und sehen Sie.
Mark Ransom
3
Nachdem ich die am besten aussehenden Downscaling-Methoden untersucht hatte, fand ich auch die Flächenmethode, um die besten Ergebnisse zu erzielen. Die einzige Situation, in der das Ergebnis nicht zufriedenstellend ist, besteht darin, ein Bild um einen kleinen Faktor zu verkleinern. In diesem speziellen Fall verwischt die Flächenmethode im Allgemeinen das Bild, aber der nächste Nachbar kann sich überraschend gut vorformen. Das Lustige an der Verwendung der Gaußschen Verkleinerung ist, dass sie mehr oder weniger der Unschärfe des Bildes und der Verkleinerung mit dem nächsten Nachbarn entspricht.
Jahu
7

Ich habe vor einiger Zeit einen Artikel über Slashdot über Seam Carving gesehen , der sich vielleicht lohnt.

Das Nahtschnitzen ist ein von Shai Avidan und Ariel Shamir entwickelter Algorithmus zur Größenänderung von Bildern. Dieser Algorithmus ändert die Abmessungen eines Bildes nicht durch Skalieren oder Zuschneiden, sondern durch intelligentes Entfernen von Pixeln aus dem Bild (oder Hinzufügen von Pixeln zu dem Bild), die wenig Bedeutung haben.

Verrückt
quelle
Ich habe das gesehen. War nicht genau das, was ich mir vorgestellt hatte, aber es ist auf jeden Fall eine gute Idee, es zu untersuchen! Vielen Dank! Ist dieser Algorithmus irgendwo öffentlich verfügbar?
Vilx
3
Tatsächlich ist das Schnitzen von Nähten ein Retargeting, keine Skalierung. Sie führen zu unterschiedlichen Ergebnissen. @Vilx: Ja, hier gibt es ein GIMP-Plugin: liquidrescale.wikidot.com
Can Berk Güder
Hier ist eine dotNET-Implementierung: blogs.msdn.com/mswanson/archive/2007/10/23/…
Craz
Beachten Sie, dass der Algorithmus für das Retargetting von Nahtschnitzereien seinen Weg in Photoshop 4 gefunden hat. Es würde mich nicht wundern, wenn dieser Algorithmus eine hohe Patentbelastung aufweist.
Lasse V. Karlsen
3
Seamcarving ist dieselbe Idee wie die flüssige Neuskalierung von Gimp und die inhaltsbewusste Skalierung von Photoshop CS4. Es dient nicht zum Skalieren, sondern zum Ändern des Seitenverhältnisses eines Bildes, ohne es gestreckt erscheinen zu lassen.
mk12
4

Der von Ihnen beschriebene Algorithmus wird als lineare Interpolation bezeichnet und ist einer der schnellsten Algorithmen, bei Bildern jedoch nicht der beste.


quelle
Mit der Ausnahme, dass OP die räumliche Position von Subpixeln berücksichtigt, wie dies beim Rendern von Subpixel-Schriftarten der Fall ist. Dies könnte eine wirklich coole Möglichkeit sein, eine kleine Auflösung zu erzielen, könnte aber auch zu merkwürdigen Bildeffekten führen und hängt auch von einer bestimmten Subpixel-Architektur ab.
Adam Tolley
Nein, lineare Interpolation ist eine Art Faltungsalgorithmus. Beschrieben in True Supersampling.
homm
@AdamTolley Ich bezweifle stark, dass Subpixel AA für normale Bilder sogar akzeptabel aussehen würde. Es funktioniert mit Text, weil es nur zwei Farben gibt und selbst dort eine andere Farbe als Weiß ein Problem darstellt
RecursiveExceptionException
1
@itzJanuar Ich denke, es wäre in Ordnung, wenn die Grenzfarben mit dem Subpixel-Schema übereinstimmen würden, aber das würde nur manchmal passieren, was bestenfalls zu inkonsistenter Nützlichkeit und im schlimmsten Fall zu einer Störung der Grundfrequenz der Pixelabtastung führen würde, was zu merkwürdigen Wahrnehmungsartefakten führen würde
Adam Tolley,
2

Gibt es einen Namen für diesen Algorithmus?

Es könnte in der Literatur als "Box" - oder "Fenster" -Resampling bezeichnet werden. Es ist tatsächlich weniger rechenintensiv, wie Sie denken.

Es kann auch verwendet werden, um eine Zwischenbitmap zu erstellen, die anschließend durch bi-kubische Interpolation verwendet wird, um ein Aliasing zu vermeiden, wenn das Downsampling um mehr als 1/2 erfolgt.

Thilo Köhler
quelle
-1

Wenn jemand interessiert ist, hier ist meine C ++ - Implementierung des Algorithmus zur Skalierung der Flächenmittelung:

void area_averaging_image_scale(uint32_t *dst, int dst_width, int dst_height, const uint32_t *src, int src_width, int src_height)
{
    // 1. Scale horizontally (src -> mid)
    int mid_width  = dst_width,
        mid_height = src_height;
    float src_width_div_by_mid_width = float(src_width) / mid_width;
    float mid_width_div_by_src_width = 1.f / src_width_div_by_mid_width;
    std::vector<uint32_t> mid(mid_width * mid_height);
    for (int y=0; y<mid_height; y++)
        for (int x=0; x<mid_width; x++)
            for (int c=0; c<4; c++) {
                float f = x * src_width_div_by_mid_width;
                int i = int(f);
                float d = ((uint8_t*)&src[i + y*src_width])[c] * (float(i) + 1 - f);
                float end = f + src_width_div_by_mid_width;
                int endi = int(end);
                if (end - float(endi) > 1e-4f) {
                    assert(endi < src_width);
                    d += ((uint8_t*)&src[endi + y*src_width])[c] * (end - float(endi));
                }
                for (i++; i < endi; i++)
                    d += ((uint8_t*)&src[i + y*src_width])[c];
                int r = int(d * mid_width_div_by_src_width + 0.5f);
                assert(r <= 255);
                ((uint8_t*)&mid[x + y*mid_width])[c] = r;
            }

    // 2. Scale vertically (mid -> dst)
    float mid_height_div_by_dst_height = float(mid_height) / dst_height;
    float dst_height_div_by_mid_height = 1.f / mid_height_div_by_dst_height;
    for (int y=0; y<dst_height; y++)
        for (int x=0; x<dst_width; x++)
            for (int c=0; c<4; c++) {
                float f = y * mid_height_div_by_dst_height;
                int i = int(f);
                float d = ((uint8_t*)&mid[x + i*mid_width])[c] * (float(i) + 1 - f);
                float end = f + mid_height_div_by_dst_height;
                int endi = int(end);
                if (end - float(endi) > 1e-4f) {
                    assert(endi < mid_height);
                    d += ((uint8_t*)&mid[x + endi*mid_width])[c] * (end - float(endi));
                }
                for (i++; i < endi; i++)
                    d += ((uint8_t*)&mid[x + i*mid_width])[c];
                int r = int(d * dst_height_div_by_mid_height + 0.5f);
                assert(r <= 255);
                ((uint8_t*)&dst[x + y*dst_width])[c] = r;
            }
}
tav
quelle
3
Bitte fügen Sie Ihrer Antwort eine Erklärung hinzu, damit andere daraus lernen können
Nico Haase