Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (ANSI-Standard) » Floyd-Steinberg: geht das nicht ein bisschen schneller?

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 <
000
20.02.2017, 18:43 Uhr
Yadgar



Hi(gh)!

Jetzt habe ich also (danke, Hans!) meinen Floyd-Steinberg-Filter einwandfrei implementiert und lasse ihn gerade per bash-Skript eine Sequenz von über 7000 Bildern bearbeiten... aber irgendwie kommt mir das alles ziemlich behäbig vor, was die Rechengeschwindigkeit angeht. Für 2000 Bilder (unkomprimierte TGAs, 533 x 400 Pixel) 69 Minuten, und das auf einem AMD-Hexacore mit 6 x 3,852 GHz... ließe sich da nicht noch einiges optimieren? Ich habe zum Beispiel das Gefühl, dass yip nur einen der sechs Prozessorkerne nutzt... wo finde ich (für mich verständliche!) Informationen zum Thema Multithreading mit C++?

Bis bald im Khyberspace!

Yadgar
--
Flagmaker - ein Programmier-Blog
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
20.02.2017, 21:03 Uhr
ao

(Operator)


Ich würds erstmal mit GNU Parallel versuchen. Parallelisiert nicht auf C++-, sondern auf bash-Ebene. So kannst du mit wenig Aufwand rausfinden, wieviel die Parallelisierung bringen kann.

Multithreading in C++ würde ich mit std::thread machen (ab C++11). Wenns ein älterer Standard sein muss, dann mit pthread.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
21.02.2017, 13:35 Uhr
ao

(Operator)


Nochmal in Ruhe nachgedacht:

Willst du die Bearbeitung EINES Bildes auf mehrere Kerne verteilen? Das setzt voraus, dass der Algorithmus parallelisierbar ist. Das trifft vielleicht auf manche Bildverarbeitungs-Algorithmen zu, aber sicher nicht auf alle, oder?

Oder willst du yip mehrfach parallel aufrufen und jedes Mal ein anderes Bild verarbeiten lassen? In dem Fall kannst du die Parallelisierung nicht innerhalb von yip lösen, sondern musst es auf der Skript-Ebene machen. Also nicht in C++.

Außerdem solltest du mal kritisch auf deinen Algorithmus gucken, ich beziehe mich auf den Code in dem Floyd-Steinberg-Thread von vor ein paar Tagen:

1. du rufst coldist zu oft auf. Du solltest das bisher gefundene Minimum speichern und nicht bei jedem Schleifendurchlauf neu berechnen. Solange die Palette nur zwei Farben (schwarz und weiß) enthält, ist das noch nicht tragisch, aber ich schätze, du willst auch mal mit größeren Paletten dithern.

2. die anschließende Fortpflanzung des Dither-Fehlers auf die Nachbarpixel ist eine Orgie von Int-Float-Konversionen: Die Multiplikation konvertiert implizit nach float, das Zurückspeichern im Pixel macht wieder int draus (bzw. short).


Zitat:
Ich habe erst die Klasse "pixel" vollständig von unsigned char nach short umgestellt;

Dadurch hast du beim Draufaddieren keine Über- und Unterläufe mehr, das war wahrscheinlich die Ursache für die Artefakte, die du anfangs hattest. Das hat die Ergebnisse schon mal wesentlich verbessert.

Was du aber nach wie vor hast: Du rechnest in float und speicherst in Ganzzahl, d.h. vor jeder Rechnung konvertierst du von short nach float und nach jeder Rechnung wieder zurück. Dadurch hast du jedesmal einen mehr oder weniger kleinen Rundungsfehler (je dunkler das Pixel, desto größer, relativ gesehen), der sich fortpflanzen und das Bild verfälschen kann. Obendrein ist diese Konvertiererei Zeitverschwendung, denn im nächsten Schleifendurchlauf wird sie ja wieder rückgängig gemacht.

Es ist zumindest mal den Versuch wert, ein Pixel aus drei float-Komponenten zu definieren, die Bilddaten beim Laden aus der Datei umzurechnen, alle Manipulationen in Fließkomma zu machen und erst am Ende zum Wegspeichern wieder Ganzzahldaten draus zu machen - wahrscheinlich wird das schneller, und das Ergebnis wird zumindest nicht schlechter.

3. Wenn du die Daten für t1 bis t4 schon hast, dann verwende sie doch und hol sie nicht nochmal ab:

C++:
      if (t1.red > -1)
      {
          img[r].at(c+1).get_all(triple);  // überflüssig, die Daten sind schon in t1
          newred = triple.red + dist.red*0.4375;  // triple ist überflüssig, benutz t1
          newgreen = triple.green + dist.green*0.4375;  // dito
          newblue = triple.blue + dist.blue*0.4375;  // dito
        img[r].at(c+1).set_all(mround(newred), mround(newgreen), mround(newblue));
      }
// für t2 bis t4 dasselbe.


Dieser Post wurde am 21.02.2017 um 13:39 Uhr von ao editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 <     [ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: