ich probiers erst gar ned aus, mein rechner ist schon bei deinem knäckebrot ääh mnadelbrot dingen in die knie gegangen
der algorythmus würd mich aber auch intressieren, und auch eine performance optimierte version von dem dingen![]()
ich probiers erst gar ned aus, mein rechner ist schon bei deinem knäckebrot ääh mnadelbrot dingen in die knie gegangen
der algorythmus würd mich aber auch intressieren, und auch eine performance optimierte version von dem dingen![]()
--
cats are not characteristically disposed toward voluntary aerobic exercise
Ahja, beim Laden muss er die unwichtigsten Linien natürlich genauso berechnen. Ich kann aber zumindest einen Vorher-Nachher-Vergleich zur Verfügung stellen:
Vorher - NachherUm das Ganze effizienter zu machen wäre es auch möglich, eine Funktion einzubauen, die das Bild gleich um eine vorgegebene Anzahl an Pixeln verkleinert, das wäre zumindest etwas schneller.
(Keine Ahnung, warum ich gerade das Bild nehme - wie ich's mich gefragt habe, war ich schon halb fertig. <__<')
Daei war das noch das Schnellste! o_O'
Irgendwie scheine ich echt ein Problem mit der Performance meiner Programme zu haben, aber vielleicht hilft meine diessemestrige Vorlesung "Effiziente Programme" ja was. ^^''
Eine performanceoptimierte Version lasse ich jetzt mal als Fleißaufgabe im Raum stehen, da ich - zumindest atm - echt keine Idee habe, was man da noch drehen könnte. <__< Bzw. höchstens eine sehr vage Idee, nämlich die, dass man die geringgewichtigsten Wege nach dem Verkleinern irgendwie von denen vorm Verkleinern ableiten können müsste. Aber ganz so einfach klappt das leider nicht, da müsste man einige Überlegungen anstellen, damit das zumindest halbwegs optimal bleibt.Zitat
Aber der Algorithmus ist ebenso simpel wie hardwarefressend:
Wenn ein neues Bild geladen wird (und halt leider auch, wenn das Bild verkleinert wird, da sich dann halt doch einiges ändert) wird erstmal von jedem Pixel das "Gewicht" bestimmt, also wie wichtig er für das Bild ist (computeWeights(), welches für jeden Pixel computeWeight() aufruft). Dies passiert, in dem jeweils die Differenz zwischen den R-, G- und B-Anteilen zu allen vier umliegenden Pixeln addiert wird. Bei den Pixeln am Rand (die ja keine vier angrenzenden haben) wird zusätzlich noch eine Normierung durchgeführt.
Dann kommt das Hardwarefressende: sowohl für die horizontale Richtung, als auch für die vertikale, muss der Weg mit dem geringsten Gesamtgewicht gefunden werden (computeLeastImportant***alLine()). (Ich erklär's hier für den horizontalen Weg.) Um den geringgewichtigsten Weg zu ein und demselben Pixel nicht mehrmals zu berechnen, wird dabei jeweils eine Spalte (also gleiche x-Koordinaten) berechnet. Der geringgewichtigste Weg zu einem Pixel der aktuellen Spalte berechnen sich dann aus dem Gewicht des Wegs zu demjenigen der drei vorigen Pixel (also (x-1, y-1), (x-1, y) und (x-1, y+1)), dessen Weg das geringste Gewicht hat, plus dem Gewicht des aktuellen Pixels. Die Wege werden dabei als verlinkte Listen gespeichert, und da die Wege zu den beiden unteren der vorigen Pixel noch für den nächsten Pixel der Spalte gebraucht werden, muss diese Liste praktisch jedes Mal geklont werden (außer wenn der geringgewichtigste Weg der zum obersten vorigen Pixel (x-1, y-1) ist) - Performance ade!
Wenn man in der letzten Spalte angekommen ist wird dann der Weg mit dem geringsten Gewicht gespeichert. Damit wäre dann das Bild zumindest schon erfolgreich geladen (kein Wunder, wenn da viele PCs schon aufgeben).
Wenn dann tatsächlich das Bild um einen Pixel niedriger werden soll, wird dieser geringgewichtichtigste Weg Spalte für Spalte abgegangen und jeweils der Pixel rausgenommen, der in diesem Weg liegt. Da das Bild aber Array-mäßig gespeichert wird, damit auf die Pixel schnell per Index zugegriffen werden kann, dauert das auch nicht gerade kurz, da alle unter diesem Pixel liegenden Pixel nach oben verschoben werden müssen. Eine kleine Optimierung dabei ist, dass je nach der Position des ersten Pixels entweder die über oder die unter dem aktuellen Pixel liegenden Pixel verschoben werden, aber das bringt wohl nur in Extremfällen mehr als ein paar Prozent.
Das entstehende Bild wird dann vertikal um einen Pixel gekürzt und zurückgegeben, und natürlich die Gewichte und unwichtigsten Wege neu berechnet.
@ DFYX: Setz' deine Ideen halt auch mal um, dann können wir ja schauen, ob's bloß meine Unfähigkeit oder doch die Schwierigkeit des Problems war. ^^''
--A human is a system for converting dust billions of years ago into dust billions of years from now via a roundabout process which involves checking email a lot.
Geändert von drunken monkey (25.09.2007 um 11:43 Uhr)
Dem Programm fehlt ein Statusbalken, der anzeigt, was es gerade tut. Dann würde man sich auch nicht wundern, warum das Bild nicht geladen wird...
Gute Idee!
Allerdings habe ich das gerade versucht, aber ziemliche Probleme gehabt, Swing dazu zu bringen, den angezeigten Text zu korregieren, bevor die Aktion abgeschlossen ist. Mittels repaint() kann man das nur in die EventQueue einreihen, aber die wird erst abgearbeitet, sobald nichts anderes mehr läuft. Und wenn man's mit update() macht (was man nicht soll), kommt plötzlich eine Exception beim Erstellen des Bilds.
Aber falls jemand weiß, wie man das machen könnte, kann's derjenige ja einbauen. Als Starthilfe kann man das hier verwenden, einfach alle Vorkommnisse von "// Repaint status label" ersetzen.
--A human is a system for converting dust billions of years ago into dust billions of years from now via a roundabout process which involves checking email a lot.
Mein erster Gedanke wäre da Multithreading - du läßt das Bild in einem separaten Thread durchrechnen, der sich dann irgendwann zurückmeldet. Wenn du Anzeige- und Berechnungslogik voneinander trennst können sie sich nicht (ganz so leicht) gegenseitig auf die Füße treten.
Geändert von Jesus_666 (25.09.2007 um 15:02 Uhr)
OK, verstehe was du meinst. Vielleicht versuche ich das ja demnächst mal, müsste man aber einiges ändern...
Edit: Habe es jetzt probiert, aber das Problem bleibt bestehen. Anscheinend sind BufferedImages nicht thread-safe. :-/ Oder ich hab' was falsch gemacht, mit Threads arbeite ich zu selten. <__<
Jedenfalls kommt jetzt jedes Mal, wenn ich jetzt das Bild verkleinern will, eine Exception von Zeile 315/334/369/388, besagend, dass der image type 0 unbekannt ist. Wie man sich leicht an den entsprechenden Stellen vergewissern kann, kann das Problem kaum in normaler Weise entstehen. Entsteht anscheinend bloß, wenn man vom falschen Thread in Swingkomponenten rumpfuschen will.
Falls jemand meinen Versuch begutachten will: hier bitte.
Geändert von drunken monkey (25.09.2007 um 22:51 Uhr)