Moin,
habe letztens ein "Kunstwerk" gesehen das nichts anderes war als aus vielen kleinen Bildern/Teilbildern ein neues Bild zusammenzusetzen. Das lässt sich auch mit einem Skript ziemlich einfach erledigen.
Meine Methode ist folgendes:
- Teile Quellbild (Q), Zielbild (Z) und zusammengesetztes Bild (R) in Rechtecke der Größe P * P
- Wähle zufälliges Teilbild von Z
- Wähle aus den Teilbilgern von Q das Bild was am besten passt aus
- Lösche das gewählte Bild aus Q (man kann Teilbilder nur 1x nutzen)
- Setze das gewählte Bild an die richtige Stelle von R
- Solange bis keine Teilbilder von Q mehr übrig sind
Probleme:
- Ewig lange Laufzeit (und aus irgendwelchen Gründen gibt mein ASM manchmal nichts aus, wenn man zu schnell auf den Speicher zugreift, daher das Sleep(0) vor jedem Aufruf)
- Die letzten paar Teilbilder passen nicht gut, da in Q nur noch z.B. 5 übrig sind die aber alle nicht zu den letzten 5 Teilen aus Z passen.
- (Zumindest in jetziger Ausführung) müssen Q und Z exakt gleichgroß sein und Breite sowie Höhe muss durch P teilbar sein.
- Nicht optimiert, da geht geschwindigkeitstechnisch noch einiges, aber ich hatte keine Lust
Im Beispiel habe ich natürlich etwas geschummelt und zwei Bilder beigelegt die sich super ineinander umwandeln lassen weil sie gleich viel Schwarz und Weiß enthalten.
Falls jemand Ideen für einen besseren Algorithmus hat, oder genau das gleiche auch schonmal gebastelt hat kann es ja hier verlinken
Edit 20.10.2018:
Habe erstmal den Code aufgeräumt (und den Algorithmus klarer gemacht, sodass man jetzt viel leichter daran herumbasteln kann) und ein paar kleine Änderungen vorgenommen. Die Funktionalität ist vollständig unverändert (es wird nach wie vor der gleiche O(n²) schwere Algorithmus verwendet). Durch einige Optimierungen/Fehlerbeseitigungen (DANKE an Andy für seinen xmm0 Tip) konnte ich ca. 30% mehr Tempo rausholen (statt 15s braucht das Skript nun nur noch 11s).
Beim nächsten Mal wird der Algorithmus selbst angegangen, habe da schon einige gute Ideen die eine n^(3/2) Komplexität erreichen könnten. Ausprobieren hat gezeigt, die Laufzeit damit ca. 10-15x kürzer ist (für das kleine Testbild), bei großen Bildern ist da natürlich weeesentlich mehr drin, allerdings bin ich mit dem Ergebnis noch nicht zufrieden.
Wer es ausprobieren will kann in Zeile 98 und 102 das $iUBound_SrcLinear durch Ceiling($iUBound_SrcLinear^0.5) ersetzen, damit wird nicht mehr allzuviel verglichen, das Resultat leidet aber deutlich. Andere Exponenten wie z.B. 0.8 ergeben nahezu das gleiche Ergebnis bei ca. 1/3 Laufzeit, da geht also was.
Meine Hoffnung ist, dass zufälliges versuchen (anstatt lineares) ein nahezu identisches Ergebnis liefert wie die Ursprungsfunktion, aber 10x schneller läuft.) Zuletzt kommt noch eine Fehlerkorrektur die ich in Post3 schon angerissen habe, damit sollten die Resultätbilder weniger störende "offensichtlich falsche" Rechtecke mehr haben.
Weiterhin halte ich vom Vergleich der Durchschnittsfarbe nicht viel, das würde zwar den ASM Teil beschleunigen (der sowieso schon schnell ist). Habe ausprobiert, dass eine Verkleinerung des Bildes von 512x512 auf 256x256 bei gleicher Zerlegung (also gleicher Anzahl) ca. 10% mehr Tempo bringt. Man könnte intern das Bild auf 1/x herunterskalieren um so nochmal ca. 50% rauszuholen, aber bei 1x1 Pixel vergleichen leidet die Genauigkeit extrem, der Trick soll ja sein dass die Teilbilder auch die Form ganz gut wiederspiegeln. Für einen "ersten Vergleich" kann man den 1px Vergleich ggf. heranziehen und wenn man sieht, dass das Teil sowieso nicht passt direkt zum nächsten wandern als einen "richtigen" Vergleich zu starten.
Edit 24.10.2018:
Sehr viel Bastelei später und sehr viele Erklärungen (die im Code stehen) später hat sich ergeben, dass man über soetwas wie "Qualitätsschalter" nicht drum herumkommt. Man muss irgendwo einstellen können was man haben will. Dafür gibt es jetzt eine ganze Palette verschiedene Sachen:
- iPixelsize - Kennt man, in diese Stückchen wird das Bild zerlegt. Zukünftig soll das noch in W und H geändert werden damit es nicht immer gleichseitige Vierecke sein müssen
- bMultipleds- False/True - Man kann nun erlauben Teile doppelt zu verwenden. Bei den meisten Bildern ist das Sinnvoll
- iShuffleCount - Intern wird sehr viel gewürfelt. Was das bringt genau zu erklären sprengt den Rahmen, daher iShufflecount ist die Obergrenze für erlaubte Mehrfachvorkommen, falls bMultiples = true, und auch ansonsten bedeutet "ab und zu mal Würfeln" bessere Ergebnisse. Zu viel würfeln ist aber sinnlos, es sollte sich so im Rahmen 4 bis 64 bewegen, je nach Anzahl Teilbilder.
- fExponent - Hier ist der Hauptgeschwindigkeitsschalter, er bestimmt wie viele Vergleiche durchgeführt werden. Bei z.B. e = 0.5 wird in jedem Durchlauf jedes Bild nur mit Sqrt(n) Teilbildern verglichen, sodass man damit von der n² Komplexität herunterkommt. Ist dieser Wert 1 wird Brute Force ALLES durchprobiert.
- iCorrectionTime - Nachdem das Bild fertig ist werden gezielt Teile mit schlechter Abweichung so vertauscht, dass die Gesamtabweichung sinkt. Leider gibt es dafür kein gutes Maß "wie oft" man das machen muss (oder mir ist keines eingefallen), daher ist das ein Multiplikator. Bei Time = 1 wird die gleiche Zeit die der Zusammensetzalgo gebraucht hat erneut für Korrekturen aufgewendet. Hier kann sicherlich noch viel optimiert werden, aber es funktioniert erstmal.
Kurz zusammengefasst gibt es Qualitätsprofile: low (Ergebnis ist besser als das best mögliche Ergebnis des vorherigen Algo und ca. 7x schneller), mid (ca. 3x schneller als vorher), high (vergleichbar schnell wie der vorherige, aber wesentlich besseres Ergebnis), max (Brute Force, langsam, wählt ÜBERALL das best passende Teil)
Mal schauen wann ich Lust habe weiterzubasteln, have fun
(wer läd eigentlich immer die alten Dateien herunter, die sind eigentlich nur zum Vergleich da damit man sieht was sich verändert hat^^)
lg
M