effizient mehrere BufferedImage in eines schreiben

mr.kernel

Mitglied
Hallo liebe Gemeinde :)

Ich verzweifle langsam dran:
Ein Bild soll möglich schnell, also Multithreaded und später auch mit SIMD optimiert gefiltert werden.
Dabei sollen mehrere BufferedImage in eines geschrieben werden, wobei jedes der Einzelbilder nur einen Teil des gesamten Bildes enthält.
Sprich Teil1 - Zeile 0 bis 5, Teil2 - Zeile 5 bis 10 ...
Beim effizienten zusammensetzen hapert es aber.

In einer Schleife habe ich nun:

Java:
        BufferedImage dest = new BufferedImage(img.getWidth(), img.getHeight(),
                BufferedImage.TYPE_3BYTE_BGR);
        int anzThreads = 4;

        for (int x = 0; x < anzThreads; x++) {
            BufferedImage tmp = new BufferedImage(img.getWidth(), img.getHeight(),
                    BufferedImage.TYPE_3BYTE_BGR);
            tmp = Threaded(x, anzThreads, img, tresholds);
        dest.getGraphics().drawImage(tmp, 0, startwert, tmp.getTileWidth(), endwert, null);
}

dabei wird aber im Gesamtbild nur

dargestellt.

Mit folgender Variante klappt es korrekt, ist aber unglaublich langsam:
Java:
             for (ya = startwert; ya < endwert; ya++) {
                    for (xa = 0; xa < img.getTileWidth(); xa++) {
                        dest.setRGB(xa, ya, tmp.getRGB(xa, ya));
                        }
                 }

Kann mir jemand helfen?
 

KonradN

Super-Moderator
Mitarbeiter
Ich verstehe den ersten Ansatz von Dir nicht. Du schreibst in mehreren Threads jeweils ein Bild. Dieses hat aber die komplette Größe ... um dann am Ende in die temporären Bilder in das Ziel zu übertragen? Dabei überträgst Du aber das ganze Bild, also alle Bereiche und nicht nur den zuständigen Bereich, oder habe ich da auf die Schnelle etwas übersehen?

Generell kannst Du auf ein BufferedImage mit mehreren Threads zugreifen. Wenn jeder Thread einen eigenen Bereich hat und die Bereiche sich nicht überlappen, solltest Du kein Problem haben.

Was genau machst Du denn in dem "Threaded"? Du willst da ja sofort ein Ergebnis haben zum weiter arbeiten. Also entweder Du hast da keinen Thread oder Du arbeitest mit etwas weiter, obwohl der Thread im Hintergrund noch etwas macht.

Und ganz nebenbei: In der Schleife erzeugst Du in tmp erst ein BufferedImage nur um es sofort wieder wegzuwerfen (Du überschreibst die Referenz mit der Rückgabe vom Threaded Aufruf.
 

mr.kernel

Mitglied
Ich verstehe den ersten Ansatz von Dir nicht. Du schreibst in mehreren Threads jeweils ein Bild. Dieses hat aber die komplette Größe ... um dann am Ende in die temporären Bilder in das Ziel zu übertragen? Dabei überträgst Du aber das ganze Bild, also alle Bereiche und nicht nur den zuständigen Bereich, oder habe ich da auf die Schnelle etwas übersehen?
Aus den temporären Bildern soll nur der zuständige Bereich übertragen werden.
Mit der zweiten Variante funktioniert auch das zusammenführen, allerdings Pixel für Pixel.

Was genau machst Du denn in dem "Threaded"? Du willst da ja sofort ein Ergebnis haben zum weiter arbeiten. Also entweder Du hast da keinen Thread oder Du arbeitest mit etwas weiter, obwohl der Thread im Hintergrund noch etwas macht.

In Threaded wird der Filter auf den zuständige Bereich angewendet.
Auf das Ergebnis der Threads wird mit join gewartet und dann erst das Bild zusammengesetzt.

Und ganz nebenbei: In der Schleife erzeugst Du in tmp erst ein BufferedImage nur um es sofort wieder wegzuwerfen (Du überschreibst die Referenz mit der Rückgabe vom Threaded Aufruf.
Ich dachte ich Initialisiere erstmal ein leeres BufferedImage um es dann zu beschreiben.
Habs nun angepasst.
 

KonradN

Super-Moderator
Mitarbeiter
In Threaded wird der Filter auf den zuständige Bereich angewendet.
Auf das Ergebnis der Threads wird mit join gewartet und dann erst das Bild zusammengesetzt.
Das macht aber kein Sinn. Du startest einen Thread und wartest dann darauf, dass er sich beendet. Dann kannst Du das, was der Thread macht, auch direkt erledigen und sparst Dir den Aufwand.

Was Du machen müsstest, wäre die Threads alle zu starten und wenn alle Threads laufen, dann kannst Du auf alle warten und du hast die Parallelität, die Du willst.

Was Du aber z.B. machen kannst, ist einfach direkt mit dem BufferedImage in allen Threads zu arbeiten. Du hast also etwas wie:
Java:
BufferedImage target = ...; // Das Ziel-BufferedImage
int lineCount = ...; // Anzahl der Zeilen, die ein Thread bearbeiten soll
int threadCount = 4; // Anzahl der Threads

Thread[] threads = new Thread[threadCount];

for (int i = 0; i < threadCount; i++) {
    final int threadIndex = i;
    threads[i] = new Thread(() -> {
        int startLine = threadIndex * lineCount;
        int endLine = Math.min((threadIndex + 1) * lineCount - 1, target.getHeight());
        writeToBufferedImage(target, startLine, endLine);
    });
    threads[i].start();
}

for (int i = 0; i < threadCount; i++) {
    try {
        threads[i].join(); // Warten, bis alle Threads beendet sind
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt(); // Unterbrechung setzen, falls der Thread unterbrochen wurde
        e.printStackTrace(); // Optional: Stack-Trace ausgeben
    }
}

Das aber nur als kurze Skizzierung - ist halt im Forum entstanden und ist ungetestet und evtl. habe ich auf die Schnelle etwas übersehen ...

Da definierte Bereiche verwendet werden, kannst Du in writeToBufferedImage alles machen. Also auch gerne ein Graphics Objekt erzeugen um damit in das Bild zu malen. Wenn der Index wichtig ist, dann kannst Du den auch mitgeben. damit das richtige Bild gemalt wird.
 

Robert Zenz

Top Contributor
Ha, zufaellig hatte ich mich erst mit BufferedImage beschaeftigt.

Ein Bild soll möglich schnell, also Multithreaded und später auch mit SIMD optimiert gefiltert werden.
Bist du dann mit BufferedImage nicht ohnehin falsch? Weil ich glaube nicht dass man auf BufferedImage so ein paar CPU-Instruktionen anwenden kann.

Dabei sollen mehrere BufferedImage in eines geschrieben werden, wobei jedes der Einzelbilder nur einen Teil des gesamten Bildes enthält.
Sprich Teil1 - Zeile 0 bis 5, Teil2 - Zeile 5 bis 10 ...
Das waere dann das Beispiel fuer BufferedImage.getRGB und setRGB. Du ziehst die Pixel als int[] und setzt diese wieder auf dem finalen Bild. Einfacher wird es nicht mehr wirklich.

Java:
int[] partRgb = partImage.getRGB(
        0,
        0,
        partWidth,
        partHeight,
        null,
        0,
        partWidth;

finalImage.setRGB(
        offsetXOfPartImage,
        offsetYOfPartImage,
        partWidth,
        partHeight,
        partRgb,
        0,
        partWidth);

Wenn du das "parallelisieren" willst, wuerde das vermutlich so aussehen:

Java:
BufferedImage finalImage = createFinalImage();

for (int threadCounter = 0; threadCounter < 4; threadCounter++) {
    new Thread(() -> {
       BufferedImage partImage = getPartImageFromSomewhere();
    
       int[] partRgb = partImage.getRGB(
               0,
               0,
               partWidth,
               partHeight,
               null,
               0,
               partWidth;
  
       finalImage.setRGB(
               offsetXOfPartImage,
               offsetYOfPartImage,
               partWidth,
               partHeight,
               partRgb,
               0,
               partWidth);
      }).start();
}

Aber das so zu machen ist garantiert langsamer als wenn du es direkt machst (es sei denn du hast Bilder mit einer Groesze jenseits von Gut und Boese). Einen Thread zu starten ist teuer (mal abgesehen davon dass du nicht weiszt wann der endlich startet), sowas macht erst Sinn wenn du den Thread behalten kannst und dem immer wieder Arbeit zuschiebst, meiner Meinung nach. Oder wenn das holen der Einzelbilder irgendwie pro Aufruf teuer ist.

Falls du hier versuchst eine Videoverarbeitung zu bauen, waerst du vielleicht besser dran kein BufferedImage im ersten Schritt zu verwenden, sondern die "rohen" Daten selbst irgendwie zusammen zu stoeppeln (so fern moeglich, weil Bitmaps oder so).
 
Zuletzt bearbeitet:

mr.kernel

Mitglied
Dank dem Hinweis von @KonradN habe ich nun den Fehler gefunden, durch das überschreiben des neuen Bildes mit allen Pixeln aus dem Teilbildern (auch der nicht zuständigen Bereiche mit getGraphics().drawImage wurde mir das Bild immer unvollständig angezeigt. :cool:

Ha, zufaellig hatte ich mich erst mit BufferedImage beschaeftigt.


Bist du dann mit BufferedImage nicht ohnehin falsch? Weil ich glaube nicht dass man auf BufferedImage so ein paar CPU-Instruktionen anwenden kann.


Das waere dann das Beispiel fuer BufferedImage.getRGB und setRGB. Du ziehst die Pixel als int[] und setzt diese wieder auf dem finalen Bild. Einfacher wird es nicht mehr wirklich.

Java:
int[] partRgb = partImage.getRGB(
        0,
        0,
        partWidth,
        partHeight,
        null,
        partWidth;

finalImage.setRGB(
        offsetXOfPartImage,
        offsetYOfPartImage,
        partWidth,
        partHeight,
        partRgb,
        partWidth);

Wenn du das "parallelisieren" willst, wuerde das vermutlich so aussehen:

Java:
BufferedImage finalImage = createFinalImage();

for (int threadCounter = 0; threadCounter < 4; threadCounter++) {
    new Thread(() -> {
       BufferedImage partImage = getPartImageFromSomewhere();
     
       int[] partRgb = partImage.getRGB(
               0,
               0,
               partWidth,
               partHeight,
               null,
               partWidth;
   
       finalImage.setRGB(
               offsetXOfPartImage,
               offsetYOfPartImage,
               partWidth,
               partHeight,
               partRgb,
               partWidth);
      }).start();
}

Aber das so zu machen ist garantiert langsamer als wenn du es direkt machst (es sei denn du hast Bilder mit einer Groesze jenseits von Gut und Boese). Einen Thread zu starten ist teuer (mal abgesehen davon dass du nicht weiszt wann der endlich startet), sowas macht erst Sinn wenn du den Thread behalten kannst und dem immer wieder Arbeit zuschiebst, meiner Meinung nach.

Falls du hier versuchst eine Videoverarbeitung zu bauen, waerst du vielleicht besser dran kein BufferedImage im ersten Schritt zu verwenden, sondern die "rohen" Daten selbst irgendwie zusammen zu stoeppeln (so fern moeglich, weil Bitmaps oder so).

Das SIMD möchte ich auf den eigentlichen Filter(ungsprozess) anwenden, nicht auf das BufferedImage direkt.

Ich habe eine simple Bildbearbeitung und wollte diese jetzt parallelisieren und halt mit SIMD Befehlen nutzen.
 

mr.kernel

Mitglied
Das macht aber kein Sinn. Du startest einen Thread und wartest dann darauf, dass er sich beendet. Dann kannst Du das, was der Thread macht, auch direkt erledigen und sparst Dir den Aufwand.

Was Du machen müsstest, wäre die Threads alle zu starten und wenn alle Threads laufen, dann kannst Du auf alle warten und du hast die Parallelität, die Du willst.

Was Du aber z.B. machen kannst, ist einfach direkt mit dem BufferedImage in allen Threads zu arbeiten. Du hast also etwas wie:
Java:
BufferedImage target = ...; // Das Ziel-BufferedImage
int lineCount = ...; // Anzahl der Zeilen, die ein Thread bearbeiten soll
int threadCount = 4; // Anzahl der Threads

Thread[] threads = new Thread[threadCount];

for (int i = 0; i < threadCount; i++) {
    final int threadIndex = i;
    threads[i] = new Thread(() -> {
        int startLine = threadIndex * lineCount;
        int endLine = Math.min((threadIndex + 1) * lineCount - 1, target.getHeight());
        writeToBufferedImage(target, startLine, endLine);
    });
    threads[i].start();
}

for (int i = 0; i < threadCount; i++) {
    try {
        threads[i].join(); // Warten, bis alle Threads beendet sind
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt(); // Unterbrechung setzen, falls der Thread unterbrochen wurde
        e.printStackTrace(); // Optional: Stack-Trace ausgeben
    }
}

Das aber nur als kurze Skizzierung - ist halt im Forum entstanden und ist ungetestet und evtl. habe ich auf die Schnelle etwas übersehen ...

Da definierte Bereiche verwendet werden, kannst Du in writeToBufferedImage alles machen. Also auch gerne ein Graphics Objekt erzeugen um damit in das Bild zu malen. Wenn der Index wichtig ist, dann kannst Du den auch mitgeben. damit das richtige Bild gemalt wird.

Nein du hast nix übersehen und funktioniert besser als mein erster Versuch.
Ich bin fälschlicherweise davon ausgegangen dass das join erst nach dem letzten Thread wartet...

Mein erster Versuch war in etwa so schnell wie die Variante komplett ohne Threads.
Nun mit deinem Vorschlag und sinnvollen Threads etwa ein drittel schneller. 👍
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
CptK Funktionsgraphen effizient zeichnen und nur Teile von JPanel erneuern AWT, Swing, JavaFX & SWT 2
B Java scatterplot mit Sticks effizient erstellen! AWT, Swing, JavaFX & SWT 2
C 2D Simulation möglichst effizient (ggf. Transparenz) AWT, Swing, JavaFX & SWT 23
T Swing Mehrere Ausgaben in JTextArea AWT, Swing, JavaFX & SWT 2
H Mehrere Panels auf JFrame AWT, Swing, JavaFX & SWT 8
S Mehrere Tabellen Zellen gleichzeitig färben AWT, Swing, JavaFX & SWT 5
Apfelbaum2005 Swing JFrame mehrere JPanels mit unterschiedlichen Formen hinzufügen AWT, Swing, JavaFX & SWT 1
K JavaFX unterschiedliche (mehrere Fenster) in seperater Main Methode AWT, Swing, JavaFX & SWT 26
I Scene Builder - mehrere Seiten AWT, Swing, JavaFX & SWT 6
P Swing Mehrere JLabels mit ImageIcon in JPanel lesen AWT, Swing, JavaFX & SWT 1
schoel27 Mehrere JButtons sollen das gleiche Event auslösen AWT, Swing, JavaFX & SWT 2
Z GUI Forms - Mehrere Fenster in einem Projekt AWT, Swing, JavaFX & SWT 18
M mehrere jTextField untereinander AWT, Swing, JavaFX & SWT 1
N Bilder auf Button einfügen und mehrmals ändern (ein Button, mehrere ActionListener) AWT, Swing, JavaFX & SWT 2
B Swing Sudoku: Laden / Speichern von Zahlen aus/in mehrere JTextFields aus/in eine(r) Textdatei AWT, Swing, JavaFX & SWT 9
M JavaFX JavaFX in mehrere Controller AWT, Swing, JavaFX & SWT 21
R mehrere buttons mit forschleife kreieren und individuell bearbeiten AWT, Swing, JavaFX & SWT 1
N JavaFX 1 Listener für mehrere ChoiceBoxen AWT, Swing, JavaFX & SWT 3
N Textdatei GUI, Text in Textarea anzeigen mehrere Zeilen AWT, Swing, JavaFX & SWT 1
temi JavaFX Mehrere Views mit Stage.setScene() oder mit Scene.setRoot()? AWT, Swing, JavaFX & SWT 7
P Swing Mehrere JPanels auf ein JFrame hinzufügen? AWT, Swing, JavaFX & SWT 2
T Swing Tetraeder - mehrere Punkte verbinden? - Ansätze gesucht AWT, Swing, JavaFX & SWT 2
K JavaFX in mehrere Controller aufteilen AWT, Swing, JavaFX & SWT 29
K JavaFX in mehrere Controller aufteilen AWT, Swing, JavaFX & SWT 0
stroggi Swing Mehrere transparentes Objekte (Grafiken) über einem Bild (JLabel) darstellen AWT, Swing, JavaFX & SWT 4
K Mehrere Linien zeichnen AWT, Swing, JavaFX & SWT 8
J JavaFX - mehrere Views, Model durchreichen AWT, Swing, JavaFX & SWT 10
it_is_all Swing Mehrere JComboBoxen - wie die versch. Boxen mit ItemStateChange auslesen? AWT, Swing, JavaFX & SWT 3
M Swing Mehrere Textfelder mit ScrollBars - Größe der Felder AWT, Swing, JavaFX & SWT 0
W JavaFX Mehrere Klassen in ein TableView AWT, Swing, JavaFX & SWT 6
F AWT mehrere Panels in einem Frame AWT, Swing, JavaFX & SWT 17
L JavaFX Mehrere JavaFX Szenen mit einem Menü AWT, Swing, JavaFX & SWT 1
D Java FXML mehrere Fenster AWT, Swing, JavaFX & SWT 4
F JavaFX Mehrere Stages "managen" AWT, Swing, JavaFX & SWT 2
r4w Changelistener auf mehrere Textfelder AWT, Swing, JavaFX & SWT 5
H Swing + Paint: Mehrere Objekte zeichnen lassen AWT, Swing, JavaFX & SWT 3
S Swing Mehrere Modal-Dialoge übereinander AWT, Swing, JavaFX & SWT 5
T 2D-Grafik JFreeChart mehrere Y-Achsen AWT, Swing, JavaFX & SWT 2
C JavaFX mehrere Kreise nach Eingabeprozess ausgeben AWT, Swing, JavaFX & SWT 2
Thallius Swing Mehrere tausend "Panels" erstellen AWT, Swing, JavaFX & SWT 3
C Java FX Warnmeldung: Mehrere Fonts gehören derselben Familie und Stil AWT, Swing, JavaFX & SWT 2
J Mehrere JInternalFrame; GetValues AWT, Swing, JavaFX & SWT 1
JG12111989 mehrere Polyline-Objekte zeichnen AWT, Swing, JavaFX & SWT 3
LexeB4F JTable mehrere Zelle selektieren und inhalte Löschen.. Ideen gesucht AWT, Swing, JavaFX & SWT 1
V Tastatur KeyListener für mehrere Buttons AWT, Swing, JavaFX & SWT 1
K JavaFX Mehrere Cell Editors in einem TreeView Item AWT, Swing, JavaFX & SWT 2
KaffeeFan mehrere JTextField durchlaufen AWT, Swing, JavaFX & SWT 4
J Java -8 Action Listener für mehrere Buttons AWT, Swing, JavaFX & SWT 9
T Dynamisch mehrere Checkboxen anlegen AWT, Swing, JavaFX & SWT 2
G JavaFX Menü und mehrere Scenes AWT, Swing, JavaFX & SWT 16
R Swing Mehrere JTextFields mit einem Document Listener AWT, Swing, JavaFX & SWT 2
D Mehrere RadiButtons auswählar AWT, Swing, JavaFX & SWT 3
P Swing JTable mehrere Zeilen markieren AWT, Swing, JavaFX & SWT 1
M Mehrere Jpanel in einem JScrollPane (Layout) AWT, Swing, JavaFX & SWT 2
T JavaFX FXMLController für mehrere FXML? AWT, Swing, JavaFX & SWT 7
G mehrere Action-Abfolgen erfassen AWT, Swing, JavaFX & SWT 6
elischa JFrame über mehrere JPanel und Listener AWT, Swing, JavaFX & SWT 17
X Swing JPanel mehrere Ebenen zeichnen AWT, Swing, JavaFX & SWT 13
J Mehrere Hyperlinks "stilvoll" darstellen. AWT, Swing, JavaFX & SWT 1
G Mehrere Strings um Kreis zeichnen und positionieren AWT, Swing, JavaFX & SWT 0
S JavaFX Mehrere TreeTableView's synchron scrollen AWT, Swing, JavaFX & SWT 0
U Mehrere Oberflächeninstanzen seperat schließen AWT, Swing, JavaFX & SWT 5
J Rahmen um mehrere GUI Einzelteile AWT, Swing, JavaFX & SWT 2
S Layouts, mehrere Buttons nebeneinander AWT, Swing, JavaFX & SWT 2
M Mehrere Fenster innerhalb einer Application AWT, Swing, JavaFX & SWT 3
T Über mehrere Panel zeichnen AWT, Swing, JavaFX & SWT 2
M ActionListener für mehrere Klassen AWT, Swing, JavaFX & SWT 4
T [LWJGL] mehrere Displays? AWT, Swing, JavaFX & SWT 19
SexyPenny90 Mehrere Fenster AWT, Swing, JavaFX & SWT 2
M Handling 1 Fenster mehrere Panels AWT, Swing, JavaFX & SWT 2
Y Mehrere JSlider verlinken AWT, Swing, JavaFX & SWT 6
Java-Insel LayoutManager Ein GridBagLayout-Objekt für mehrere Panels? AWT, Swing, JavaFX & SWT 2
O Swing JLabel mehrere Zeilen AWT, Swing, JavaFX & SWT 2
P mehrere Rectangles per JButton AWT, Swing, JavaFX & SWT 9
B JToolBar dynamisch auf mehrere Zeilen erweitern AWT, Swing, JavaFX & SWT 2
Jats Zeichen auf mehrere JPanels AWT, Swing, JavaFX & SWT 7
G Mehrere Probleme mit Java's GUI AWT, Swing, JavaFX & SWT 6
G Mehrere Layoutprobleme AWT, Swing, JavaFX & SWT 2
Kenan89 JTable mehrere ListSelections AWT, Swing, JavaFX & SWT 2
M TextArea über mehrere Zeilen - wie Zeileanzahl abfragen? AWT, Swing, JavaFX & SWT 5
J Swing JDialog blokiert mehrere JFrames - soll aber nur den aufrufenden blockieren AWT, Swing, JavaFX & SWT 4
A mehrere Zeilen in GUi ausgeben AWT, Swing, JavaFX & SWT 2
N Mehrere Tasks nacheinander ausführen AWT, Swing, JavaFX & SWT 7
C SWT Mehrere Bilder in GUI laden AWT, Swing, JavaFX & SWT 5
propra Mehrere Objekte gleichzeitig verschieben AWT, Swing, JavaFX & SWT 7
M 2D-Grafik Mehrere Linien (nacheinander) übereinander Zeichnen AWT, Swing, JavaFX & SWT 6
M Mehrere JPanel nacheinander?! AWT, Swing, JavaFX & SWT 11
Furtano AWT mehrere Bilder in einen Frame zeichnen + Layout Manager AWT, Swing, JavaFX & SWT 10
K SWT Mehrere Einträge ins Clipboard legen AWT, Swing, JavaFX & SWT 2
C Swing Ein JFrame mehrere Ansichten AWT, Swing, JavaFX & SWT 8
C Swing Mehrere JSlider sollen aufeinander reagieren AWT, Swing, JavaFX & SWT 4
GUI-Programmer JFilechooser, mehrere Datein selektieren und Reihenfolge (2) AWT, Swing, JavaFX & SWT 8
S Mehrere JLists - Wie kennzeichnen? AWT, Swing, JavaFX & SWT 2
S Swing MVC Ein JFrame, mehrere JPanels AWT, Swing, JavaFX & SWT 6
J Mehrere JRadioButtons, aber nur 1 darf ausgewählt sein AWT, Swing, JavaFX & SWT 4
L Swing Mehrere Button die selbe Größe AWT, Swing, JavaFX & SWT 4
B AWT mehrere Fenster schließen AWT, Swing, JavaFX & SWT 8
I Wie mehrere JComboBoxen in Abhängigkeit einer anderen Box ändern? AWT, Swing, JavaFX & SWT 8
G mehrere JPanel in ein (vertikales) JScrollPane AWT, Swing, JavaFX & SWT 8
F Swing Mehrere Textfelder in Scrollpane einfügen und dann zum Scrollen bringen? AWT, Swing, JavaFX & SWT 4

Ähnliche Java Themen

Neue Themen


Oben