HQx, EPx, xBR... Grafikinterpolation !

  • Moin,

    "Alter Inhalt - 12.6.12"


    Schon vor einiger Zeit bin ich über Folgendes gestolpert auf der Suche nach einer ordentlichen Interpolationsmethode:

    http://en.wikipedia.org/wiki/Hqx

    Wie es aussieht liegt das Projekt HQx auf Eis, während andere ähnliche Projekte noch weiterentwickelt werden.
    Ein kleines Grafikprogramm beherrscht alle aktuell verfügbaren interpolationsmethoden dieser Art und viele Andere:

    http://en.wikipedia.org/wiki/Hqx

    Was mich daran fasziniert ist, dass die Grafiken im Nachhinein noch komplett verändert werden können. Man kann also (was mir sehr entgegenkommt) in AutoIt ein winziges Spielchen schreiben (Vorteil, da AutoIt + Große Grafiken = Langsam) und ihm anschließend einen Flash ähnlichen Look verpassen.

    Angeblich soll das sogar in Echtzeit funktionieren. (so im Bereich < 3ms schätze ich). Dann könnte man den Filter praktisch direkt vor die Ausgabe im GUI schalten.

    Ich tue mich leider schwer diese Filter in AutoIt zu nutzen.
    Ideal wäre eine Anbindung über einen standard DllCall. (mit hdc1, hdc2 oä).

    Hat da jemand eventuell ein Paar Tipps wie man das bewerkstelligen kann ?
    Nur das rohe Downloaden der dll bringt mich irgendwie nicht weiter^^
    Außerdem brauche ich ja auch nur einen einzigen Filter (xBR 3x) und nicht alle 50.

    Beispiel für 3x Zoom

    [Blockierte Grafik: http://i.imgur.com/EJQlp.png]
    [Blockierte Grafik: http://i.imgur.com/js5cv.png]


    Edit:

    Hab jetzt auch mal Quellcode gefunden.
    https://github.com/libretro/commo…ter/xBR/3xBR.cg
    https://github.com/libretro/commo…BR/3xBR-v2.1.cg

    Es gibt doch bestimmt jemanden der damit was anfangen kann.
    Optimal wäre eine Übersetzung in ASM. Ansonsten geht natürlich auch C++

    Wenn alles schief geht muss eine Funktion selbst geschrieben werden.
    Die wird dann aber eher schlecht und langsam als recht und schnell.

    &quot;Nicht ganz so alter Inhalt - 16.6.12&quot;

    Nach einigem Suchen und durchfragen habe ich den Quellcode (in C++) erhalten.
    DEV C++ habe ich installiert (um die .dev Projekte zu öffnen).

    Das Kompillieren zu einer Dll war auch (nach kleinen Modifikationen) erfolgreich.

    Jetzt brauche ich noch Infos wie ich den DllCall ausführe.
    Es werden irgendwelche Parameter/Structs und sonstiges benötigt.
    Ich kenne mich mit C++ aber nicht genug aus um herauszufinden wie ich was wo übergeben muss.

    Gefundene in AutoIt nutzbare Funktionen:
    - RenderPluginGetInfo
    - RenderPluginOutput

    Erstere ließ sich leicht in AutoIt einbauen.
    Der DllCall war simpel, keine Parameter und die Ausgabe klar.

    Die Funktion steckt also im 2ten Call.
    Dazu wird eine umfangreiche Dllstruct benötigt.

    Der Aufbau der Struct konnte man dem DllHeader entnehmen.
    Leider schmiert AutoIt beim Aufruf ab.

    Das liegt vermutlich daran, dass ich bei einigen Parametern den Sinn noch nicht gefunden habe und nicht weiß welche Werte eingetragen werden müssen.

    Schaut mal bitte jemand der C++ besser kennt als ich drüber wo der Fehler im Aufruf ist ?
    Die Dll ist korrekt kompilliert worden. Ansonten würde die erste Funktion nicht funktionieren. Und die geht Problemlos.

    Anbei ist:
    - Quellclode von 3xBR
    - Testskript

    Wichtige Zeilen:
    49 - Aufruf der Dll Info Funktion
    52 - Aufruf der Vergrößerungsfunktion
    52ff - Aufbau der Vergrößerungsfunktion. Hier brauche ich Hilfe von jemandem der C++ kennt.


    17.6.12
    Sooo...
    Wo ein Wille ist, ist auch ein Weg scheint es.

    Es ist zwar (wie immer) alles wesentlich komplizierter als man es gerne hätte, aber es geht wenigstens.

    Der Filter funktioniert erstens mit total seltsamen Parametern (die man sich auch in der Dll berechnen könnte),
    und benötigt 2tens 16Bit Grafik (555 oder 565) wie wir sie von den guten alten Zeiten her kennen.

    Also müssen Konvertierungsfunktionen her.
    Zum Testen der Dll habe ich diese beiden (von 32Bit -> 16Bit und zurück) provisorisch in AutoIt realisiert.
    Das Durchlaufen der Schleifen und der im Prinzip sehr hardwarenahe Bitshift fressen aber unglaubliche Zeiten^^

    eine ASM Version (die das in 1ms statt 1s packt) ist bereits in Arbeit.
    Anschließend gehts ans optimieren.

    Im Anhang:
    Ein Ordner mit allem möglichen seltsamen Zeug.
    Startet man die Vergrößern.au3 kann man erste Resultate sehen.

    Falls es bei jemandem nicht funktioniert, bitte melden.
    Ich bin noch auf Fehlersuche. Das ist alles noch etwas wackelig. Und im Endeffekt soll es ja überall laufen.


    Edit:
    Die erste ASM gestützte Version ist fertig.
    Und es wurde im Code etwas aufgeräumt.

    lg
    Mars

  • OT:
    Also erstmal: WTF -> Das sieht ja echt genial vergrößert aus !
    Quasi so als wäre aus der 8-Bit eine HD-Grafik geworden :D

    T:
    Keine Idee, leider, aber ne Frage:
    Kann man damit auch Bilder vergrößern und so Schrift lesbar machen, die relativ klein ist ?
    MfG

    Es gibt sehr viele Leute, die glauben. Aber aus Aberglauben.
    - Blaise Pascal

  • Diese Filter sind für Pixelgenaue Grafik ausgelegt.
    d.h. ein Foto wird mit einem Sinc(oä) Filter besser aussehen als mit einem dieser Filter.
    (Habe testweise mal ein Foto damit vergrößert. Das Resultat ist, dass im Prinzip kaum etwas anderst ist als eine Nearest Interpolation. Nur Kanten sehen etwas komisch aus.)

    Kleine Schrift kann man "verbessern" wenn sie Pixelgenau gesetzt ist (z.B. 5x5px schrift ist gut lesbar nach dem Vergrößern, manches wird aber verschluckt...). Ist die Schrift aber auf einem Foto wird das nichts nützen.

    [Blockierte Grafik: http://i.imgur.com/xjaPo.png]
    [Blockierte Grafik: http://i.imgur.com/kHhXA.png]

    Ich suche immernoch eine Möglichkeit diese Filter int AutoIt zu nutzen.

    lg
    M

  • Moin,

    Hab oben nochtmal 2 Links eingefügt.
    Dort sieht man den Quelltext der Interpolationsmethode die ich suche.

    Leider bin ich mit der Interpretation des Quellcodes etwas überfordert.
    Für jemanden der C++/C kann sollte das aber ein Kinderspiel sein.

    In C++ habe ich selbst schon gaanz kleine Kleinigkeiten programmiert, und der Code sieht so ähnlich aus^^

    Das was in den Links zu finden ist brauche ich als Dll.
    Mögliche Parameter sind: hDC, ptr, Maße (alles vorhanden von beiden Bitmaps)
    Ziel ist ein Zoomfaktor von 3 mithilfe dieser Interpolationsmethode.

  • Deswegen hab ich es gepostet.
    Damit jemand den Fehler im CllCall findet.

    Der Quellcode liegt vor, Die Dll liegt vor, Das Skript liegt vor.
    Der Fehler entzieht sich dennoch meiner Sicht.

  • Hi, hab jetzt mal im Netz gesucht, aber ausser irgendwelchen broken Links nichts gefunden, was auch nur ansatzweise wie eine Beschreibung der DLL aussieht.
    Auch Beispielcode ist nicht zu finden....
    Funktionieren wird es wohl, allerdings habe ich keine Lust, komplette NES/SEGA-Emulatoren downzuloaden und durchzuscannen....

  • Das habe ich gestern (ok Heute um 2 Nachts) auch gemerkt.
    Das macht aber keinen Unterschied. (Irgendwie funktioniert eine Funktion (inzwischen) wenn sie es denn tut mit cdecl und ohne)

    Habe jetzt (nach einem kurzen Austausch mit dem Hersteller dieses Filters) das Problem gefunden.
    Das Problem lag im "Pitch" Wert.

    Dieser Wert muss das 2Fache der Breite des Bildes haben (4x geht auch manchmal^^). Sonst schmiert es ab. (Warum der nicht intern berechnet wird weiß ich nicht)

    Mit viel Liebe habe ich nun folgendes aus dem Filter holen können:

  • Hi,
    die RGBA8888 nach RGB565 hatte ich in Deskstream und auch im Steganographie-Script benutzt.
    Der Asm-Code für ein Pixel:

    [autoit]

    _("and eax,0xFFFFFF") ;nur RRGGBB
    _("shr eax,3") ;R an Grenze zu ax schieben
    _("shl ax,3") ;G an die rechte seite von R schieben
    _("shr eax,2") ;RG an Grenze zu al schieben
    _("shl al,2") ;B rechts ans RG schieben
    _("shr eax,3") ;RGB steht nun in 16Bit

    [/autoit]


    das 32Bit ARGB steht in EAX, nach dem Bitgeschiebe steht 565 in AX^^

    /Edit/ hups, beinahe die Umkehrfunktion vergessen^^

    [autoit]


    _("movzx eax,word[adresse]") ;nur die untersten 16 bit holen
    _("shl eax,5") ;565
    _("shr ax,3") ;
    _("shr al,2") ;
    _("shl eax,3") ;ARGB

    [/autoit]


    Das sollte sich per inline-asm in den C++-Code reinbringen lassen^^

    ciao
    Andy


    "Schlechtes Benehmen halten die Leute doch nur deswegen für eine Art Vorrecht, weil keiner ihnen aufs Maul haut." Klaus Kinski
    "Hint: Write comments after each line. So you can (better) see what your program does and what it not does. And we can see what you're thinking what your program does and we can point to the missunderstandings." A-Jay

    Wie man Fragen richtig stellt... Tutorial: Wie man Script-Fehler findet und beseitigt...X-Y-Problem

    4 Mal editiert, zuletzt von Andy (18. Juni 2012 um 06:25)


  • Das sollte sich per inline-asm in den C++-Code reinbringen lassen^^

    Dann muss man aber die ganze Schleife, die das Bild konvertiert, in assembler schreiben.
    Da der Compiler bei inline-assembler nicht weiß, wie er den Code davor und danach optimieren darf, geht oft Geschwindigkeit verloren. Für so kleine Funktionen lohnt sich das oft nicht.

  • Zitat

    Dann muss man aber die ganze Schleife, die das Bild konvertiert, in assembler schreiben.

    Naja, dann wird der Code eben 5 Zeilen länger....
    Ich würde jedenfalls, wenn ich eine DLL schreibe, auch die Konvertierungsfunktionen in diese DLL packen.
    Also ARGB8888 -> RGB565 und wieder umgekehrt.
    Die sicherlich bessere Alternative ist aber, den C++-Code so umzuschreiben, dass auch ARGB8888 damit funktioniert...
    Ich vermute mal, sooo schwer wird das nicht sein, gerade im Gegenteil, das Bitgeschiebe fällt komplett weg!

  • Es mag sein, dass man die DLL ummodeln kann.
    Der ersteller der DLL hat mir aber mitgeteilt, dass durch eine Umwandlung von 565 zu 8888 erhebliche Performanceeinbußen entstehen. (er wirds wissen, weil er den Code geschrieben hat)

    Gründe dafür sind:
    Viele Vatiablen sind zurzeit 16Bit Variablen und können nach dem Kompillieren parallel verarbeitet werden. (durch 32Bit Variablen fällt diese optimierungsmöglichkeit für den compiler weg)
    Einige Funktionen sind per #Define deklariert und funktionieren in der Form nur mit 16Bit Variablen. Eine Andere Form würde den Rechenaufwand stark erhöhen. (ich kenne mich mit dem unterschied in C++ zwischen per #Define deklarierten Funktionen und anderweitig deklarierten Funktionen nicht aus)
    Sonstige die ich nicht verstehe.

    Meine jetzige (absolut unoptimierte) Funktion braucht ca. 5x so lange wie ein StretchBlt.
    - Es werden aber noch einige Puffer andauernd erzeugt und gelöscht.
    - Der ASM arbeitet nur in 16Bit Schritten (wird noch auf 32/64/128 erhöht, je nach Aufwand).
    - Die Dll ist ohne jegliche Optimierungen davon gekommen. Einige überflüssige Berechnungen können entfernt werden. (Code speziell für für 555 z.B.)

    Ich habe das Skript auch mal etwas aufgeräumt (und unterteilt in Ordnern, sodass nicht alles durcheinanderfällt).

    Aktualisierung im ersten Post folgt gleich.

  • eins ist mir noch aufgefallen, wenn man schon stretchblt nutzt, dann sollte auch der (schlechte) GDI-Filter eingesetzt werden, dafür vor dem Stretchblit den Modus setzen

    [autoit]

    local $hDLL_GDI32=dllopen("gdi32.dll")
    DllCall($hDLL_GDI32, "int", "SetStretchBltMode", "dword", $hDC_Buf, "int", 4)
    DllCall($hDLL_GDI32, "int", "SetStretchBltMode", "dword", $hDC_Img, "int", 4)

    [/autoit]

    und somit egalisiert sich auch der Zeitunterschied....
    Aber die Qualität von xBR ist WESENTLICH besser :thumbup: