In Anwendungen zum Arbeiten mit Bildern ist die Größenänderung von Jeeps (mit dem JPEG-Algorithmus komprimierte Bilder) weit verbreitet. In diesem Fall können Sie die Größe nicht sofort ändern und müssen zuerst die Originaldaten dekodieren. Daran ist nichts Kompliziertes und Neues, aber wenn Sie es viele Millionen Mal am Tag tun müssen, ist die Optimierung der Leistung einer solchen Lösung, die sehr schnell sein sollte, von besonderer Bedeutung.

Dieses Problem tritt häufig beim Organisieren von Remote-Hosting für ein Bild-Repository auf, da die meisten Kameras und Telefone im JPEG-Format aufnehmen. Täglich werden Fotoarchive führender Webdienste (soziale Netzwerke, Foren, Fotohosting und viele andere) mit einer erheblichen Anzahl solcher Bilder aufgefüllt. Daher ist die Frage, wie solche Bilder gespeichert werden sollen, äußerst wichtig. Viele Webdienste speichern Dutzende von Dateien für ein einzelnes Bild in verschiedenen Auflösungen, um die Größe des ausgehenden Datenverkehrs zu verringern und die Antwortzeit auf die Anforderung eines Benutzers zu verbessern. Die Reaktionsgeschwindigkeit ist gut, aber diese Kopien nehmen viel Platz ein. Dies ist ein Hauptproblem, obwohl dieser Ansatz andere Nachteile aufweist.
Die Idee zur Lösung dieses Problems besteht nicht darin, viele Optionen für das Originalbild in verschiedenen Auflösungen auf dem Server zu speichern, sondern das gewünschte Bild mit den angegebenen Abmessungen aus dem zuvor vorbereiteten Original dynamisch und so schnell wie möglich zu erstellen. So können Sie in Echtzeit ein Bild mit der gewünschten Auflösung erstellen und sofort an den Benutzer senden. Es ist sehr wichtig, dass die Auflösung dieses Bildes sofort vorgenommen werden kann, damit das Gerät des Benutzers keine Bildschirmgröße ändert, da dies einfach nicht erforderlich ist.
Die Verwendung anderer Formate als JPEG als Grundlage für die Organisation eines solchen Bildspeichers erscheint nicht gerechtfertigt. Natürlich gibt es weit verbreitete Standardformate, die eine bessere Komprimierung bei gleicher Qualität ermöglichen (JPEG2000, WebP), aber die Kodierungs- und Dekodierungsgeschwindigkeit solcher Bilder ist im Vergleich zu JPEG sehr gering. Daher ist es sinnvoll, JPEG als Basisformat für die Speicherung von Originalfotos zu wählen. Diese wird bei Bedarf nach Erhalt einer Anfrage vom Benutzer in Echtzeit skaliert.
Natürlich hat jede Site neben Jeeps am häufigsten PNG- und GIF-Bilder, aber normalerweise ist ihre relative Anzahl gering und Fotos in diesen Formaten sind äußerst selten. Daher haben diese Formate in den meisten Fällen keinen wesentlichen Einfluss auf die betreffende Aufgabe.
Beschreibung des Größenänderungsalgorithmus im laufenden Betrieb
Die Eingabedaten sind also JPEG-Dateien. Um eine schnelle Dekodierung zu erreichen (dies gilt sowohl für die CPU als auch für die GPU), müssen die komprimierten Bilder über integrierte Neustartmarkierungen verfügen. Diese Markierungen sind im JPEG-Standard beschrieben und ein Teil der Codecs kann mit ihnen arbeiten, der Rest weiß, wie man sie nicht bemerkt. Wenn Jeeps keine solchen Markierungen haben, können sie im Voraus mit dem Dienstprogramm jpegtran hinzugefügt werden. Wenn Markierungen hinzugefügt werden, ändert sich das Bild nicht, aber die Dateigröße wird etwas größer. Als Ergebnis erhalten wir das folgende Arbeitsschema:
- Holen Sie sich Bilddaten aus dem CPU-Speicher
- Wenn es ein Farbprofil gibt, holen Sie es aus dem EXIF-Bereich und speichern Sie es
- Kopieren Sie das Bild auf die Grafikkarte
- JPEG dekodieren
- Wir machen eine Größenänderung nach dem Lanczos-Algorithmus (Abnahme)
- Schärfe
- Wir codieren das Bild mit JPEG
- Bild auf Host kopieren
- Fügen Sie der resultierenden Datei das ursprüngliche Farbprofil hinzu.
Sie können eine genauere Entscheidung treffen, wenn vor der Größenänderung das inverse Gamma jeder Komponente des Pixels überlagert wird, sodass sich die Größenänderung im linearen Raum befindet, und dann das Gamma erneut anwenden, jedoch nach dem Scharfzeichnen. Der tatsächliche Unterschied für den Benutzer ist gering, existiert jedoch, und der Rechenaufwand für eine solche Modifikation ist minimal. Es ist nur notwendig, die Überlagerung des inversen und direkten Gammas in das allgemeine Verarbeitungsschema einzufügen.
Es gibt auch eine mögliche Lösung, wenn die Dekodierung von Jeeps auf einer Mehrkern-CPU unter Verwendung der libjpeg-turbo-Bibliothek durchgeführt wird. In diesem Fall wird jedes Bild in einem separaten CPU-Stream decodiert und alle anderen Aktionen werden auf der Grafikkarte ausgeführt. Bei einer großen Anzahl von CPU-Kernen kann dies noch schneller geschehen, es kommt jedoch zu einem ernsthaften Latenzverlust. Wenn die Latenz beim Decodieren eines Jeeps auf einem einzelnen CPU-Kern akzeptabel ist, kann diese Option sehr schnell sein, insbesondere wenn die ursprünglichen Jeeps eine geringe Auflösung haben. Mit zunehmender Auflösung des Originalbilds erhöht sich die Decodierungszeit des Jeeps in einem CPU-Stream, sodass diese Option nur für kleine Auflösungen geeignet ist.
Grundlegende Anforderungen für die Web-Größenänderungsaufgabe
- Es ist ratsam, nicht Dutzende Kopien jedes Bildes in unterschiedlichen Auflösungen auf dem Server zu speichern, sondern das gewünschte Bild sofort nach Eingang der Anfrage schnell mit der richtigen Auflösung zu erstellen. Dies ist wichtig, um die Größe des Speichers zu verringern, da Sie sonst viele verschiedene Kopien jedes Bildes speichern müssen.
- Das Problem muss so schnell wie möglich gelöst werden. Dies ist eine Frage zur Qualität des bereitgestellten Dienstes im Hinblick auf die Verkürzung der Antwortzeit auf eine Benutzeranforderung.
- Die Qualität des gesendeten Bildes sollte hoch sein.
- Die Dateigröße für das gesendete Bild sollte so klein wie möglich sein und die Auflösung muss genau der Größe des Fensters entsprechen, in dem es angezeigt wird. Folgende Punkte sind hier wichtig:
a) Wenn die Bildgröße nicht mit der Größe des Fensters übereinstimmt, führt das Benutzergerät (Telefon, Tablet, Laptop) nach dem Dekodieren eine Größenänderung der Hardware durch, bevor das Bild auf dem Bildschirm angezeigt wird. In OpenGL erfolgt die Größenänderung dieser Hardware nur nach dem bilinearen Algorithmus, der häufig das Auftreten von Moiré (Flecken) und anderen Artefakten in Bildern mit kleinen Details verursacht.
b) Die Größenänderung des Bildschirms verbraucht zusätzlich Geräteenergie.
c) Wenn Sie eine Reihe vorskalierter Bilder verwenden, um das Problem zu lösen, ist es nicht immer möglich, genau die richtige Größe zu erhalten. Dies bedeutet, dass Sie ein Bild mit einer höheren Auflösung senden müssen. Die vergrößerte Bildgröße führt zu mehr Verkehr, den ich auch vermeiden möchte.
Beschreibung des allgemeinen Arbeitsschemas
- Wir erhalten Bilder von Benutzern in allen Formaten und in allen Auflösungen. Die Originale werden (falls erforderlich) in einer separaten Datenbank gespeichert.
- Speichern Sie offline mit ImageMagick oder einer ähnlichen Software das Farbprofil, konvertieren Sie die Original-Originalbilder in das Standard-BMP- oder PPM-Format, ändern Sie die Größe auf 1K- oder 2K-Auflösung und komprimieren Sie sie auf JPEG. Anschließend fügen Sie mit dem Dienstprogramm jpegtran Neustartmarkierungen mit dem angegebenen festen Intervall hinzu.
- Wir erstellen eine Datenbank mit solchen 1K- oder 2K-Bildern.
- Nach Erhalt einer Anfrage des Benutzers erhalten wir Informationen über das Bild und die Größe des Fensters, in dem dieses Bild angezeigt werden soll.
- Wir finden das Bild in der Datenbank und senden es an den Resizer.
- Der Resizer empfängt die Bilddatei, decodiert, ändert die Größe, schärft, codiert und fügt das ursprüngliche Farbprofil in den resultierenden Jeep ein. Danach gibt es das Bild an ein externes Programm weiter.
- Auf jeder Grafikkarte können Sie mehrere Threads ausführen und mehrere Grafikkarten auf Ihrem Computer installieren, wodurch eine Leistungsskalierung erzielt wird.
- All dies kann auf der Basis von NVIDIA Tesla-Grafikkarten (z. B. P40 oder V100) erfolgen, da NVIDIA GeForce-Grafikkarten nicht für einen kontinuierlichen Langzeitbetrieb ausgelegt sind und NVIDIA Quadro über viele Videoausgänge verfügt, die in diesem Fall nicht benötigt werden. Um dieses Problem zu lösen, sind die Anforderungen an die GPU-Speichergröße minimal.
- Außerdem können Sie aus der Datenbank mit vorbereiteten Bildern dynamisch einen Cache für häufig verwendete Dateien zuweisen. Dort ist es sinnvoll, häufig verwendete Bilder nach Statistiken aus der Vorperiode zu speichern.

Programmparameter
- Breite und Höhe des neuen Bildes. Sie können beliebig sein und es ist besser, sie explizit festzulegen.
- JPEG-Ausdünnungsmodus (Unterabtastung). Es gibt drei Optionen: 4: 2: 0, 4: 2: 2 und 4: 4: 4, aber normalerweise werden 4: 4: 4 oder 4: 2: 0 verwendet. Die maximale Qualität beträgt 4: 4: 4, die minimale Rahmengröße 4: 2: 0. Das Ausdünnen erfolgt für Farbunterschiedskomponenten, die das Sehvermögen einer Person nicht so gut wahrnimmt wie die Leuchtdichte. Jeder Dezimierungsmodus hat sein eigenes optimales Intervall für Neustartmarkierungen, um die maximale Codierungs- oder Decodierungsgeschwindigkeit zu erreichen.
- JPEG-Komprimierungsqualität und Dezimierungsmodus beim Erstellen einer Bilddatenbank.
- Das Scharfzeichnen erfolgt in einem 3x3-Fenster, Sigma (Radius) kann gesteuert werden.
- JPEG-Komprimierungsqualität und Dezimierungsmodus beim Codieren des endgültigen Bildes. Typischerweise bedeutet eine Qualität von mindestens 90%, dass diese Komprimierung "visuell verlustfrei" ist, d.h. Ungeschulte Benutzer sollten unter normalen Anzeigebedingungen keine Artefakte des JPEG-Algorithmus sehen. Es wird angenommen, dass für einen geschulten Benutzer 93-95% benötigt werden. Je größer dieser Wert ist, desto größer ist der an den Benutzer gesendete Frame und desto länger ist die Decodierungs- und Codierungszeit.
Wichtige Einschränkungen
Markierungen neu starten. Wir können JPEG-Bilder auf einer Grafikkarte nur dann schnell dekodieren, wenn sich darin Neustartmarkierungen befinden. Im offiziellen JPEG-Standard werden diese Marker beschrieben, dies ist ein Standardparameter. Wenn keine Neustartmarkierungen vorhanden sind, kann die Decodierung des Bilds auf der Grafikkarte nicht parallelisiert werden, was zu einer sehr niedrigen Decodiergeschwindigkeit führt. Daher benötigen wir eine Datenbank mit vorbereiteten Bildern, in der sich diese Marker befinden.
Fester Algorithmus für Bildcodec. Das Dekodieren und Kodieren von Bildern mit dem JPEG-Algorithmus ist bei weitem die schnellste Option.
Die Auflösung von Bildern in der vorbereiteten Datenbank kann beliebig sein, aber als Optionen werden 1K und 2K in Betracht gezogen (Sie können 4K nehmen). Sie können beim Ändern der Größe auch nicht nur die Bilder verkleinern, sondern auch vergrößern.
Schnelle Größenänderung der Leistung
Wir haben die Anwendung für die schnelle Größenänderung vom Fastvideo SDK auf der NVIDIA Tesla V100-Grafikkarte (OS Windows Server 2016, 64-Bit, Treiber 24.21.13.9826) auf 24-Bit-Bildern 1k_wild.ppm und 2k_wild.ppm mit einer Auflösung von 1K und 2K (1280x720 und) getestet 1920 x 1080). Es wurden Tests für eine unterschiedliche Anzahl von Threads durchgeführt, die auf derselben Grafikkarte ausgeführt wurden. Dies erfordert nicht mehr als 110 MB Speicher auf der Grafikkarte pro Stream. 4 Streams benötigen nicht mehr als 440 MB.
Zuerst komprimieren wir das Originalbild in JPEG mit einer Qualität von 90%, wobei wir 4: 2: 0 oder 4: 4: 4 ausdünnen. Dann dekodieren und ändern wir die Größe zweimal in Breite und Höhe, machen eine scharfe und codieren dann erneut mit 90% Qualität bei 4: 2: 0 oder 4: 4: 4. Die Quelldaten befinden sich im RAM, das endgültige Bild wird dort platziert.
Die Betriebszeit wird vom Beginn des Ladens des Originalbilds aus dem RAM bis zum Speichern des verarbeiteten Bildes im RAM gezählt. Programminitialisierungszeit und Speicherzuordnung auf der Grafikkarte sind nicht in den Messungen enthalten.
Beispiel einer Befehlszeile für ein 24-Bit-1K-Image
PhotoHostingSample.exe -i 1k_wild.90.444.jpg -o 1k_wild.640.jpg -outputWidth 640 -q 90 -s 444 -sharp_after 0.95 -repeat 200
Benchmark für die Verarbeitung eines Bildes 1K in einem Thread
Decodierung (einschließlich Datenübertragung auf die Grafikkarte): 0,70 ms
Ändern Sie die Größe zweimal (in Breite und Höhe): 0,27 ms
Scharf: 0,02 ms
JPEG-Codierung (einschließlich Datenübertragung von der Grafikkarte): 0,20 ms
Gesamtzeit pro Frame: 1,2 msLeistung für 1K
| Qualität | Ausdünnen | Größe ändern | Streams | Bildrate (Hz) |
1 | 90% | 4: 4: 4/4: 2: 0 | 2 mal | 1 | 868/682 |
2 | 90% | 4: 4: 4/4: 2: 0 | 2 mal | 2 | 1039/790 |
3 | 90% | 4: 4: 4/4: 2: 0 | 2 mal | 3 | 993/831 |
4 | 90% | 4: 4: 4/4: 2: 0 | 2 mal | 4 | 1003/740 |
Leistung für 2K
| Qualität | Ausdünnen | Größe ändern | Streams | Bildrate (Hz) |
1 | 90% | 4: 4: 4/4: 2: 0 | 2 mal | 1 | 732/643 |
2 | 90% | 4: 4: 4/4: 2: 0 | 2 mal | 2 | 913/762 |
3 | 90% | 4: 4: 4/4: 2: 0 | 2 mal | 3 | 891/742 |
4 | 90% | 4: 4: 4/4: 2: 0 | 2 mal | 4 | 923/763 |
Durch Ausdünnen von 4: 2: 0 für das Quellbild wird die Geschwindigkeit verringert, die Größe der Quell- und Zieldateien wird jedoch kleiner. Beim Umschalten auf 4: 2: 0 sinkt der Parallelitätsgrad um das Vierfache, da der 16x16-Block jetzt als einzelne Einheit betrachtet wird. In diesem Modus ist die Geschwindigkeit daher niedriger als bei 4: 4: 4.
Die Leistung wird hauptsächlich von der JPEG-Decodierungsstufe bestimmt, da in dieser Phase das Bild die maximale Auflösung aufweist und der Rechenaufwand dieser Verarbeitungsstufe höher ist als bei allen anderen.
Zusammenfassung
Die Testergebnisse zeigten, dass für die NVIDIA Tesla V100-Grafikkarte die Verarbeitungsgeschwindigkeit von 1K- und 2K-Bildern maximal ist, wenn 2-4 Streams gleichzeitig gestartet werden, und zwischen 800 und 1000 Bildern pro Sekunde pro Grafikkarte liegt. Die Verarbeitung von 1K-Bildern ist schneller als 2K, und die Arbeit mit 4: 2: 0-Bildern ist immer langsamer als mit 4: 4: 4. Um das endgültige Ergebnis der Leistung zu erhalten, müssen Sie alle Parameter des Programms genau bestimmen und für ein bestimmtes Modell der Grafikkarte optimieren.
Eine Latenz in der Größenordnung von einer Millisekunde ist ein gutes Ergebnis. Soweit wir wissen, kann eine solche Latenz für eine ähnliche Größenänderungsaufgabe auf einer CPU nicht erreicht werden (selbst wenn Jeeps nicht codiert und decodiert werden müssen). Dies ist daher ein weiteres wichtiges Argument für die Verwendung von Grafikkarten in Hochleistungs-Bildverarbeitungslösungen.
Bis zu 16 NVIDIA Tesla V100-Grafikkarten können erforderlich sein, um eine Milliarde Jeeps pro Tag mit 1K- oder 2K-Auflösungen zu verarbeiten. Einige unserer Kunden verwenden diese Lösung bereits, andere testen sie in ihren Aufgaben.
Das Ändern der Größe von Jeeps auf einer Grafikkarte kann nicht nur für Webdienste sehr nützlich sein. Es gibt eine große Anzahl von Hochleistungs-Bildverarbeitungsanwendungen, bei denen solche Funktionen möglicherweise gefragt sind. Beispielsweise ist für fast jedes Verarbeitungsschema für von Kameras empfangene Bilder häufig eine schnelle Größenänderung erforderlich, bevor ein Bild auf einem Monitor angezeigt wird. Diese Lösung kann für Windows / Linux auf jeder NVIDIA-Grafikkarte verwendet werden: Tegra K1 / X1 / X2 / Xavier, GeForce GT / GTX / RTX, Quadro, Tesla.
Vorteile einer schnellen Größenänderungslösung auf einer Grafikkarte
- Deutliche Reduzierung der Speichergröße für Quellbilder
- Reduzierung der Primärkosten für Infrastrukturkosten (Hardware und Software)
- Verbesserung der Servicequalität aufgrund der kurzen Reaktionszeit
- Reduzierung des ausgehenden Verkehrs
- Geringerer Stromverbrauch bei Benutzergeräten
- Zuverlässigkeit und Geschwindigkeit der vorgestellten Lösung, die bereits an großen Datenmengen getestet wurde
- Reduzierte Entwicklungszeit für die Vermarktung solcher Anwendungen für Linux und Windows
- Skalierbarkeit einer Lösung, die sowohl auf einer einzelnen Grafikkarte als auch als Teil eines Clusters funktioniert
- Schnelle Kapitalrendite für solche Projekte
Wer könnte interessiert sein
Die Bibliothek zur schnellen Größenänderung von Jeeps kann in hoch geladenen Webdiensten, großen Online-Shops, sozialen Netzwerken, Online-Fotomanagementsystemen und E-Commerce in fast jeder großen Unternehmensverwaltungssoftware verwendet werden.
Softwareentwickler können diese Bibliothek verwenden, die eine Latenz in der Größenordnung von mehreren Millisekunden für die Größenänderung von Jeeps mit einer Auflösung von 1K, 2K und 4K auf einer Grafikkarte bietet.
Anscheinend könnte sich dieser Ansatz als schneller als die NVIDIA DALI-Lösung für die schnelle Dekodierung von Jeeps, Größenänderung und Bildvorbereitung in der Phase des Trainings neuronaler Netze für Deep Learning herausstellen.
Was kann man noch tun?
- Zusätzlich zum Ändern der Größe und Schärfe können Sie dem vorhandenen Algorithmus Zuschneiden hinzufügen, 90/180/270 drehen, ein Wasserzeichen anwenden, Helligkeit und Kontrast steuern.
- Optimierung der Lösung für NVIDIA Tesla P40- und V100-Grafikkarten.
- Zusätzliche Optimierungsleistung JPEG-Decoder.
- Burst-Modus zum Dekodieren von Jeeps auf einer Grafikkarte.