Seite 1 von 2
Screenshot mal anders...
Verfasst: 20.06.2010 23:32
von Crawler
Hallo zusammen!
Neues Projekt, neue Probleme.

Ich schreibe momentan ein Progrämmchen, welches die resultierende (Misch-)Farbe des Bildschirminhalts errechnet und an die serielle Schnittstelle weitergibt. Ich will auch keinen Hehl draus machen, was das mal werden soll: ein Ambilight (wie bei den Fernsehern von Philipps).
Jedenfalls bin ich im Zuge der Programmierung auf die Funktion GetPixel_ gestoßen, die ich hier auch verwenden möchte. Allerdings ist das ganze dann doch recht zeitkritisch und rechenlastig, die Durchschnittswerte aller RGB-Bildpunkte zu berechnen. Gibt es dazu vielleicht schon Algorithmen, die mir die Arbeit erleichtern? Oder sollte ich um Rechenzeit zu sparen einfach nur einen 100 Pixel breiten Rand des Bildschirms berücksichtigen? Aber auch da fallen ja bei 1280x1024 etwa 420k Bildpunkte an...
Hier also meine Fragen, so konkret wie nur möglich formuliert:
a) Sollte ich die Berechnung in einem gesonderten Thread ausführen?
b) Gibt es Lösungsansätz für das geschilderte Mittelwertproblem?
c) Bringt es Geschwindigkeitsvorteile, Teilbereiche, etwa wie einzelne Kacheln, auszuwerten und diese dann zusammenzufassen?
Bin für alle Ideen und Denkanstöße dankbar!
Re: Screenshot mal anders...
Verfasst: 21.06.2010 01:30
von Dark
Hallo,
ich habe für meinen Messenger ein Modul geschrieben, welches den Screeninhalt als virtuelle Webcam verarbeitet. Dabei ist mir aufgefallen, das die GDI Befehle nicht unbedingt besonders schnell sind, und man schon bei 640*480 eine recht hohe CPU Auslastung erhält. Ich glaube das war bei einem Limit von 12 Frames pro Sekunde oder ähnlichem. Daher benutzte ich jetzt nur noch einen 320 * 240 Auschnitt, wo sich die Maus befindet, werde ggf. auch noch auf einen Screen Treiber umstellen.
Die Funktion GetPixel_() wäre in deinem Fall totaler Selbstmord. Der Prozessor müsste bei jedem Pixel mehrere Sprünge machen und eventuell sogar in den Kernel wechseln dafür. Das wäre
extrem langsam. Du musst das ganze Bild kopieren und brauchst du auch nur noch auf den Speicher des Bildes zugreifen was sehr viel schneller ist. Jedoch rate ich eigentlich ganz von der GDI API in diesem zusammenhang ab. Es gibt bei Windows so genannte Mirror Treiber, welche es einem normalen Programm ermöglichen, die Ausgabe der Grafikkarte direkt abzufangen. Diese sind sehr schnell, aber auch nicht einfach anzusteuern. An deiner Stelle würde ich mal einen Blick auf den Treiber von Ultra VNC werfen, dieser ist wirklich gut. Hier gibt es eine SDK für diesen:
http://www.uvnc.com/features/sdk.html. Jedoch ist diese natürlich für C/C++ und nicht für PureBasic.
mfg,
DarkPlayer
Re: Screenshot mal anders...
Verfasst: 21.06.2010 01:31
von X360 Andy
Mal abgesehen vom Speed....
Sollte man nicht lieber nur ein Bereich berechnen für die Licht ausgabe ?
Den ganzen Bildschirm finde ich doch extrem ...
An meinem Bild mal verdeutlicht
Ich würde ca. 20% der rechten Seite berechnen ( am besten noch proportional steigernd, so das die äußerste Pixel zahl/reihe 20% mehr zu sagen hat /zählt als die innerste Pixel reihe die für die Berechnung relevant ist ), das gleiche mit der linken Seite.
Das Ergebnis dürfte schneller und auch Harmonischer sein?
Re: Screenshot mal anders...
Verfasst: 21.06.2010 07:31
von Crawler
Erst mal schönen Dank an Dark, immerhin konnte das meine Performancebedenken bestätigen. Den Link werde ich mir mal in einer ruhigen Minute näher betrachten. Auch wenn aus der Minute Tage werden könnten...
Die Idee von X360 geht ja in etwa auf das ein, was ich anfangs beschrieb. Letztlich einen Rahmen erfassen, der ausgewertet wird. Nun hast du sogar schon die nächste Revision erkannt, zwei- bzw. dreiseitige Ausführung.

Re: Screenshot mal anders...
Verfasst: 21.06.2010 11:39
von NicTheQuick
Um den Mittelwert eines Images zu berechnen, brauchst du im Grunde nichts weiter tun als 'DrawImage(#DeinImage, 0, 0, 1, 1)' aufzurufen. Die Funktion wird dein komplettes Bild auf ein 1x1 großes Bild zusammenschrumpfen und dabei den Farbwert mitteln. Weiterhin kannst du dein Grundbild in so viele Teile zerstückeln wie du Prozessoren hast und jeden seinen Teil erledigen lassen.
Am schnellsten wäre natürlich die Benutzung von DirectX und 'ZoomSprite3D()' und 'DisplaySprite3D()'.
Re: Screenshot mal anders...
Verfasst: 21.06.2010 12:45
von bobobo
Re: Screenshot mal anders...
Verfasst: 21.06.2010 16:01
von KPA
Hi Crawler,
also wenn ich es direkt machen wollte, so würde ich anstelle GetPixel die Funktion DrawingBuffer verwenden um die Adresse des Bildschirmspeichers zu ermitteln um dann schnelleren Zugriff darauf zu haben z.B. mittels Pointer Variablen.
Re: Screenshot mal anders...
Verfasst: 21.06.2010 16:23
von Dark
KPA hat geschrieben:Hi Crawler,
also wenn ich es direkt machen wollte, so würde ich anstelle GetPixel die Funktion DrawingBuffer verwenden um die Adresse des Bildschirmspeichers zu ermitteln um dann schnelleren Zugriff darauf zu haben z.B. mittels Pointer Variablen.
Ich bin zwar nicht 100 prozentig damit vertraut, wie dieser Befehl intern arbeitet, jedoch kann man mit den regulären DirectX / OpenGL Befehlen nicht auf den Videospeicher auserhalb seines erstellten Screens zugreifen:
Beispiel: MSDN für OpenGL:
Für einen direkten Zugriff auf den Videospeicher müsstest du schon nen eigenen Treiber schreiben, welcher sich dann Zugriff auf den Videospeicher holt. Dafür müsste die Grafikkarte aber mindestens VESA Bios Extension (kurz VBE) 2.0 unterstützen. Zusätzlich müsste man aus dem Protected Mode in den Real Mode wechseln, um den passenden Interrupt aufzurufen können. Danach würdest du einen Speicherbereich (den sogennanten Framebuffer) erhalten, der direkt in die Grafikkarte gemapped ist. Ich musste das ganze mal für ein kleines OS zusammenbasteln, aber glaube hier ist der aufwand wohl eher nicht so passend

Bei 64 bit ist es sowieso unmöglich, da man da keinen 16 Bit Code ausführen kann.
mfg,
Dark
Re: Screenshot mal anders...
Verfasst: 22.06.2010 11:18
von KPA
Das Beispiel mittels VESA Standard und IRQ ist völlig veraltet. IRQ gibt es in diesem Sinne nicht mehr um BIOS Routinen aufzurufen. Eine Umschaltung in den Real Mode ist ebenfalls unter der Windows Kontrolle nicht mehr möglich. Dafür gibt es nun die API Aufrufe welche die IRQ und dessen Funktionen ersetzen. Diese API rufen wiederrum Treiber auf. Somit brauche ich auch keine Treiber neu schreiben oder entwerfen.
Ich würde sagen ihr schaut Euch mal das Beispiel DirectScreenDrawing.pb an. Da wird das direkte Schreiben eines Pixels mittels u.a. DrawingBuffer und Pointervariablen in den Speicher praktiziert.
Re: Screenshot mal anders...
Verfasst: 22.06.2010 12:26
von Crawler
Ich hätte ehrlich gesagt nicht gedacht, dass das Ganze so komplex wäre. Vielen Dank für die zahlreichen Wegweisungen, damit habe ich genug Stoff bis zum Sankt-Nimmerlein-Tag. Und zur Not kann ich dann doch auf die gepostete (Fertig-)Variante ausweichen, dazu müsste man dann nur den seriellen Datenstrom auswerten.