@crea: Deine Beschreibung ist ein bisschen zu allgemein um da etwas konkretes drauf Antworten zu können. Ganz generell müsstest Du halt statt die einzelnen Frames zu lesen und an eine Liste anzhängen, zum Beispiel eine Generatorfunktion schreiben die an stelle des Anhängens den Frame per ``yield`` liefert.
Die Frage ist natürlich auch ob die Weiterverarbeitung die Du machst mit einzelnen Frames auskommt.
Memory-Error
@crea:
Die Idee dahinter ist nichts weiter, als die Daten in sequentielle Häppchen zu zerlegen. Die Teilsequenzen sind dann klein genug, um in den Speicher zu passen. Pythons Generatoren sind eine syntaktisch elegante Form der "Häppchenbereitstellung" über eine Art Koroutine.
Ob das in Deinem speziellen Fall möglich ist, hängt davon ab, ob Du alle Daten für alle Bearbeitungsschritte brauchst. Um das einschätzen zu können, ist Deine Problembeschreibung zu allgemein.
Edit: zu langsam
Die Idee dahinter ist nichts weiter, als die Daten in sequentielle Häppchen zu zerlegen. Die Teilsequenzen sind dann klein genug, um in den Speicher zu passen. Pythons Generatoren sind eine syntaktisch elegante Form der "Häppchenbereitstellung" über eine Art Koroutine.
Ob das in Deinem speziellen Fall möglich ist, hängt davon ab, ob Du alle Daten für alle Bearbeitungsschritte brauchst. Um das einschätzen zu können, ist Deine Problembeschreibung zu allgemein.
Edit: zu langsam
Im Endeffekt brauche ich alle Daten für die weitere Bearbeitung, ja.
Ich hatte mir vorgestellt, etwas ähnliches in Python realisieren zu können, wie es in Matlab möglich ist: Eine mehrdimensionales Array, Breite x Höhe x Frames, aus welchen ich dann die entsprechenden Intensitätswerte über die Zeit für verschiedene ROIs extrahieren kann.
Also, ich versuch's mal genauer: Ich möchte ein Video einlesen, in irgendeiner Form interessante Regionen auswählen (per Binning oder manuelle Auswahl eines ROI), die Intensitätsänderung an dieser Stelle/diese Stellen über die Zeit auftragen und eine Fourieranalyse (für den Anfang) darauf anwenden.
Wie ich das umsetzen will? Das Video per OpenCV lesen, die Frames in ein Array übergeben (MemoryError), dann meine Werte in dieser Form mit Numpy weiter bearbeiten/auswerten, für den Anfang per Fourier.
Wieso ich das nicht in Matlab mache, wenn es in Matlab doch möglich ist? Es existiert ein Python-Programm eines Kollegen zu einer weiteren Analyse, welche ich auf meine Daten später anwenden will und ich möchte den oben beschriebenen Prozess in Python umsetzen, damit ich beide Teilanalysen am Ende in einem Programm zusammenführen kann.
Meine Python-Recherche hat bisher ergeben, dass es diverse Möglichkeiten zum Image-Processing, also Handling von einzelnen Frames gibt, allerdings habe ich noch keine elegante Lösung zur Bearbeitung eines kompletten Videos gefunden. Eine Option wäre natürlich, mein Video in einzelne Images zu zerlegen, bevor ich ein Python-Programm drauf loslasse, ich fände es aber schöner, wenn ich meine AVIs direkt verarbeiten könnte, ohne getrennte Vorbehandlung. Falls das nicht geht, würde ich das Video durch Python in einzelne pngs oder so zerlegen und speichern lassen, bevor ich dann die einzelnen png bearbeite.
Ich hatte mir vorgestellt, etwas ähnliches in Python realisieren zu können, wie es in Matlab möglich ist: Eine mehrdimensionales Array, Breite x Höhe x Frames, aus welchen ich dann die entsprechenden Intensitätswerte über die Zeit für verschiedene ROIs extrahieren kann.
Also, ich versuch's mal genauer: Ich möchte ein Video einlesen, in irgendeiner Form interessante Regionen auswählen (per Binning oder manuelle Auswahl eines ROI), die Intensitätsänderung an dieser Stelle/diese Stellen über die Zeit auftragen und eine Fourieranalyse (für den Anfang) darauf anwenden.
Wie ich das umsetzen will? Das Video per OpenCV lesen, die Frames in ein Array übergeben (MemoryError), dann meine Werte in dieser Form mit Numpy weiter bearbeiten/auswerten, für den Anfang per Fourier.
Wieso ich das nicht in Matlab mache, wenn es in Matlab doch möglich ist? Es existiert ein Python-Programm eines Kollegen zu einer weiteren Analyse, welche ich auf meine Daten später anwenden will und ich möchte den oben beschriebenen Prozess in Python umsetzen, damit ich beide Teilanalysen am Ende in einem Programm zusammenführen kann.
Meine Python-Recherche hat bisher ergeben, dass es diverse Möglichkeiten zum Image-Processing, also Handling von einzelnen Frames gibt, allerdings habe ich noch keine elegante Lösung zur Bearbeitung eines kompletten Videos gefunden. Eine Option wäre natürlich, mein Video in einzelne Images zu zerlegen, bevor ich ein Python-Programm drauf loslasse, ich fände es aber schöner, wenn ich meine AVIs direkt verarbeiten könnte, ohne getrennte Vorbehandlung. Falls das nicht geht, würde ich das Video durch Python in einzelne pngs oder so zerlegen und speichern lassen, bevor ich dann die einzelnen png bearbeite.
-
BlackJack
@crea: Ich bin ein bisschen verwirrt, wenn Du einzelne PNGs verarbeiten kannst, dann kannst Du doch auch direkt die Frames aus dem Video verarbeiten und bräuchtest nicht erst PNGs erstellen.
Die Frage von jerch und mir nach dem Zugriff auf *alle* Daten bezieht sich darauf, ob Du quasi *gleichzeitig* den Zugriff auf alle Daten benötigst, nicht ob während der Verarbeitung *insgesamt* alle Daten mal angefasst werden.
Hast Du ein Gefühl für den Speichebedarf, also hat Du Dir den Speicherbedarf für die reinen Pixeldaten eigentlich schon mal ausgerechnet für die Daten, die Du verarbeiten möchtest? Bekommst Du tatsächlich bei der Umwandlung von *einem* Frame einen `MemoryError`‽
Wenn Du die Daten in ein anderes Format überführst, würde ich HDF5, zum Beispiel mit dem PyTables-Modul, empfehlen. Das Format ist für grosse mehrdimensionale Datenmengen gedacht und wird unter anderem von der NASA für Satellitenbilder und ähnlichem verwendet.
Die Frage von jerch und mir nach dem Zugriff auf *alle* Daten bezieht sich darauf, ob Du quasi *gleichzeitig* den Zugriff auf alle Daten benötigst, nicht ob während der Verarbeitung *insgesamt* alle Daten mal angefasst werden.
Hast Du ein Gefühl für den Speichebedarf, also hat Du Dir den Speicherbedarf für die reinen Pixeldaten eigentlich schon mal ausgerechnet für die Daten, die Du verarbeiten möchtest? Bekommst Du tatsächlich bei der Umwandlung von *einem* Frame einen `MemoryError`‽
Wenn Du die Daten in ein anderes Format überführst, würde ich HDF5, zum Beispiel mit dem PyTables-Modul, empfehlen. Das Format ist für grosse mehrdimensionale Datenmengen gedacht und wird unter anderem von der NASA für Satellitenbilder und ähnlichem verwendet.
Den Speicherbedarf habe ich noch nicht ausgerechnet. Allerdings macht folgendes Skript bei der Verarbeitung von z.B. 180 Frames keine Probleme, wohl aber bei 1800. Und der Fehler tritt bei der Erstellung des finalen Arrays auf: frames = np.array(frames).
Es spricht nichts dagegen, dass ich den u.g. Prozess zerlege...D.h. ich brauche erst alle Daten nachdem ich o.g. Array erstellt habe, hatte aber gehofft, dass sich das Problem anders lösen lässt.
Es spricht nichts dagegen, dass ich den u.g. Prozess zerlege...D.h. ich brauche erst alle Daten nachdem ich o.g. Array erstellt habe, hatte aber gehofft, dass sich das Problem anders lösen lässt.
Code: Alles auswählen
import cv2
import numpy as np
capture = cv2.cv.CaptureFromFile('20120810-hl1-0.12s-10min-sample2of2-250mul-0002test.avi')
frames = []
for i in range(180):
img = cv2.cv.QueryFrame(capture)
tmp = cv2.cv.CreateImage(cv2.cv.GetSize(img),8,3)
cv2.cv.CvtColor(img,tmp,cv2.cv.CV_BGR2RGB)
frames.append(np.asarray(cv2.cv.GetMat(tmp)))
frames = np.array(frames)Solltest Du aber: 1800-Frames in Standardauflösung machen ungefähr 2GB. Das np.array verdoppelt den Speicherbedarf nochmales, weil alle Frames in ein neues Array kopiert werden müssen. Diverse Operationen auf solchen Matrizen können den benötigten Platz vervielfachen, da Zwischenergebnisse gebraucht werden, usw.crea hat geschrieben:Den Speicherbedarf habe ich noch nicht ausgerechnet.
Generatoren werden meist so implementiert, dass man eine Schleife baut und mit jedem Iterationsschritt ein Element ausgibt. Etwa so:
Sinnvollerweise tut man natürlich vorab irgendwas mit `item` bevor man es ausgibt.
Eine mögliche Nutzung kann dann sein:
Dabei wird dann jeweils ein neuer Iterationsschritt begangen und das zurückgegebene Element in einer wie auch immer gearteten Weise verwendet. Es wird also zwischendurch keine Liste mit (sagen wir mal) 2 Mio Items erstellt, sondern es wird wirklich nur schrittweise die Funktion mit den einzelnen Elementen gefüttert, ohne dass diese als Ganzes im Speicher gehalten werden müssten.
`yield` ist halt der Moment, in dem das `item` "ausgespuckt" wird.
Beachte, dass solche Funktionen keine Ausgabe mehr als `return` zurückgeben dürfen. Ein blankes `return` ist möglich, die Rückgabe eines speziellen Wertes mittels `return` jedoch nicht.
Falls du dich fragst, wann die Funktion fertig ist (terminiert): Das tut sie, sobald kein `yield` Statement mehr angegeben ist. Häufig also, sobald die `for`-Schleife komplett durchlaufen wurde.
Falls das Prozedere relativ trivial ist, geht auch eine noch direktere Anwendung. Beispiel:
...würde alles in Großbuchstaben schreiben. Bitte übergib in dem Fall keine Liste bzw List Comprehension, da dies den besagten Vorteil wieder kaputt machen würde. Die gerade gezeigte Form funktioniert bei jeder beliebigen Funktion, solange kein zweites Argument erforderlich ist. Das Ganze wird damit also recht lesbar.
Jedoch scheint es bei dir etwas komplizierter zu sein, sodass ich eine Funktion (ähnlich wie ganz oben gezeigt) empfehlen würde. Man kann zwar vieles auch in der im letzten Snippet gezeigten Form ausdrücken, jedoch landet man dann schnell bei Mehrfach-Verschachtelungen, was der Leserlichkeit des Codes oft nicht unbedingt zuträglich ist.
Code: Alles auswählen
def iter_items():
for item in items:
yield itemEine mögliche Nutzung kann dann sein:
Code: Alles auswählen
list(iter_items())
# oder:
" ".join(iter_items())`yield` ist halt der Moment, in dem das `item` "ausgespuckt" wird.
Beachte, dass solche Funktionen keine Ausgabe mehr als `return` zurückgeben dürfen. Ein blankes `return` ist möglich, die Rückgabe eines speziellen Wertes mittels `return` jedoch nicht.
Falls du dich fragst, wann die Funktion fertig ist (terminiert): Das tut sie, sobald kein `yield` Statement mehr angegeben ist. Häufig also, sobald die `for`-Schleife komplett durchlaufen wurde.
Falls das Prozedere relativ trivial ist, geht auch eine noch direktere Anwendung. Beispiel:
Code: Alles auswählen
" ".join(item.upper() for item in items)Jedoch scheint es bei dir etwas komplizierter zu sein, sodass ich eine Funktion (ähnlich wie ganz oben gezeigt) empfehlen würde. Man kann zwar vieles auch in der im letzten Snippet gezeigten Form ausdrücken, jedoch landet man dann schnell bei Mehrfach-Verschachtelungen, was der Leserlichkeit des Codes oft nicht unbedingt zuträglich ist.
Dein Code von oben (ungetestet) in "yield-Form" übertragen:
Obligatorisch sei erwähnt, dass man normalerweise den Code, der jetzt auf Modulebene liegt, besser in eine `main()`-Funktion verlagern sollte. Und die explizite Angabe von `cv2` habe ich weggelassen, da (bei mir zumindest) auch der Direktzugriff auf `cv` funktioniert. Im Übrigen würde ich empfehlen, das `cv`-Interface überhaupt nicht mehr zu benutzen und stattdessen gänzlich auf `cv2` zu setzen. Dies hat unter anderem den Vorteil, dass dir direkt Numpy-Arrays zurückgeliefert werden und du dir folglich die nötige Konvertierung ersparen kannst, um darauf zu arbeiten. Zudem wird es nur eine Frage der Zeit sein bis die Entwicklung der alten `cv`-Schnittstelle eingestellt wird und man dann eh früher oder später wechseln muss.
EDIT: Hier mal eine `cv2`-Version (hoffe mal, es funktioniert so):
EDIT2: Ich merke gerade, dass `np.array` als Datentyp in Numpy nicht möglich ist. Dann müsste mal jemand ran, der sich besser mit Numpy auskennt als ich. Ich denke aber, die Idee, die ich vermitteln wollte, ist trotzdem klar.
Code: Alles auswählen
import cv
import numpy as np
def get_frame_iter(capture, num_frames):
for dummy in xrange(num_frames):
frame = cv.QueryFrame(capture)
new_img = cv.CreateImage(cv.GetSize(frame), 8, 3)
cv.CvtColor(frame, new_img, cv.CV_BGR2RGB)
yield np.array(cv.GetMat(new_img))
filename = '20120810-hl1-0.12s-10min-sample2of2-250mul-0002test.avi'
capture = cv.CaptureFromFile(filename)
frames = np.fromiter(get_frame_iter(capture, 180), np.array)EDIT: Hier mal eine `cv2`-Version (hoffe mal, es funktioniert so):
Code: Alles auswählen
import cv2
import numpy as np
def get_frame_iter(capture):
while True:
success, frame = capture.read()
if not success:
break
yield cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
def get_frames(filename, num_frames=-1):
capture = cv2.VideoCapture(filename)
return np.fromiter(get_frame_iter(capture), np.array, num_frames)
filename = '20120810-hl1-0.12s-10min-sample2of2-250mul-0002test.avi'
frames = get_frames(filename, 180)