Screenshot Farbmittelung von Rechtecken

9

Ich habe ein schnelles Python-Skript geschrieben, um die durchschnittliche Farbe von Rechtecken, die den Umfang meines Bildschirms umgeben, zurückzugeben. (Das Endziel ist es, RGB-LED-Streifen um meinen Monitor zu haben, für einen leuchtenden Effekt während Filmen - wie dies (youtube) , aber mehr Spaß, weil ich es selbst mache).

Ich verwende derzeit autopy , um den Bildschirm als Bitmap ("screenshot") zu erhalten Pixelwert und RGB & lt; - & gt; HEX-Konvertierungen

Vereinfachte Version:

%Vor%

Ich zeige dann die Blöcke mit matplotlib an: (dies ist konfiguriert als 5x5 Blöcke, Schritt = 1)

Das Problem ist die Geschwindigkeit der Implementierung - weil das für jedes Pixel in einem Block (2560 * 1600 Auflösung / 5 = 320 * 512 Block = 163.840 Pixel pro Block) und jedem Block um den Umfang (16 * 163.840) = 2.621.440 Schleifen). Insgesamt dauerte es 2,814 Sekunden bis zum Abschluss.

Wenn ich den Schrittwert erhöhe, wird er schneller, aber nicht genug: (Dies verwendet realistischere 15x10 Blöcke, die den Rahmen umgeben)

%Vor%

Das liegt daran, dass der Screenshot selbst ungefähr 0,070 Sekunden dauert - das bedeutet, dass ich auf 12,8 FPS beschränkt bin.

%Vor%

Fragen:

  • Gibt es eine schnellere Methode, einen Screenshot zu erstellen und Bereiche des Bildschirms zu mitteln?

    Ich mache mir keine Sorgen wegen der Genauigkeit, aber ich möchte diese Werte bei ungefähr 30 FPS, idealerweise schneller (20-30 ms), zurückgeben können, um einen seriellen Übertragungsaufwand zu ermöglichen. Bedenken Sie, dass meine Bildschirmauflösung 2560 * 1600 ist!

    Ich habe von Python Imaging Library (PIL) gehört, aber ich hatte noch keine Zeit, um in die Geschwindigkeit der ImageGrab Funktion noch, aber es sieht vielversprechend aus.

  • Kann ich Pixelwerte direkt von der GPU lesen?

  • Ein weiterer Gedanke - wie erkennt man am besten die obere / untere Kante eines Films? (Wenn das Seitenverhältnis Breitbild ist, gibt es schwarze Balken am oberen / unteren Rand des Screenshots und einige Rechtecke sind schwarz).

Verwenden von PIL's Grab () :

%Vor%

PIL - Größe ändern: (ChristopheD)

%Vor%

Hinweis: Dies ist eine Verbesserung gegenüber den oben erzielten Ergebnissen, aber wir sind immer noch auf 9 FPS oder 3 FPS mit vollem Anti-Aliasing beschränkt.

PIL - nächste Größe: (Mark Ransom)

%Vor%

Ergebnisse:

%Vor%

Viel schneller als das manuelle Looping mit autopy oben, aber wir sind immer noch auf ~ 9 FPS beschränkt (bei einem "Schritt" von 10).

Hinweis: Dies beinhaltet nicht die RGB zu HEX Umwandlung erforderlich

Kann jemand mit einer schnelleren Methode kommen - d. h. einen partiellen Screenshot machen? Soll ich etwas in C schreiben?

    
Alex L 18.05.2012, 14:20
quelle

3 Antworten

3

Verwenden Sie die Python-Imaging-Bibliothek. Aus den Dokumenten (im Image-Modul):

  

getcolors

     

im.getcolors () = & gt; eine Liste von (count, color) Tupeln oder None

     

im.getcolors (maxcolors) = & gt; eine Liste von (count, color) Tupeln oder None

     

(Neu in 1.1.5) Gibt eine unsortierte Liste von (Anzahl-, Farb-) Tupeln zurück, wobei die Anzahl die Anzahl ist, wie oft die entsprechende Farbe im Bild auftritt.

Das Image-Modul enthält auch eine crop () -Methode, mit der Sie jedes Rechteck in getcolors () einfügen können. Sie können daraus leicht einen gewichteten Durchschnitt ziehen.

Es sollte viel schneller sein, als die Schleife in Python manuell auszuführen. Ich bin mir nicht sicher, ob es schnell genug ist, um es in Echtzeit zu benutzen, aber du wirst einen dramatischen Geschwindigkeitsschub bekommen. Sie können den Screenshot auch einige Male pro Sekunde aufnehmen, da die Wahrscheinlichkeit hoch ist, dass das Senden von Signalen an die LEDs mit 60 fps gegenüber 10 fps nicht besonders auffällt. Betrachten Sie es nicht als "beschränkt auf 12,8 FPS", betrachten Sie es als "kann die LEDs nur einmal alle 5 Frames aktualisieren", was kein merklicher Unterschied sein sollte.

EDIT: Wenn Sie wirklich an einer weiteren Optimierung interessiert sind, finden Sie hier Der schnellste Weg, um einen Screenshot mit Python in Windows zu erstellen ist sehr hilfreich.

    
Robert Mastragostino 18.05.2012 14:57
quelle
1

Ein schneller Gewinn könnte sein, eine Operation resize (in PIL) zu verwenden (Sie können eine einfache Interpolation für die Geschwindigkeit verwenden) zu einem 5x5-Bild, anstatt die Regionen zu mitteln, z. B .:

%Vor%

Dies sollte ungefähr den gleichen Effekt ergeben wie die Arbeit mit der Mittelwertbildung selbst.

Nicht wirklich sicher über die Geschwindigkeit von PIL's ImageGrab (und wie es mit autopy verglichen wird), aber es ist einfach genug zu versuchen und es herauszufinden.

    
ChristopheD 18.05.2012 14:45
quelle
1

Um eine Größenänderung zu beschleunigen, können Sie dies in zwei Schritten tun. Verwenden Sie NEAREST für den ersten, um die Anzahl der Pixel auf die schnellste Weise zu reduzieren, und dann ANTIALIAS, um diese zu einem repräsentativen Sample zusammenzufügen. Es entspricht der Schrittgröße, die Sie zuvor mit PIL-Funktionen experimentiert haben.

%Vor%     
Mark Ransom 18.05.2012 16:40
quelle