Open CV und Ringbuffer

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
FZAG
User
Beiträge: 19
Registriert: Samstag 13. April 2013, 13:29

Hallo kann mir jemend einen Tipp geben wie ich mit Open CV einen Richbuffer realisiere?

Ziel ist es eine Webcam Aufzuzeichnen, dazu müssen noch gewisse Informationen eingeblendet werden und diese sollen in einen Speicher geschrieben werden der eine definierte Länge hat, so sind immer die letzten x-Sekunden im Speicher vorhanden, und bei einem Ereigniss sollen diese dann in ein MPEG oder AVI-File geschrieben werden.

Grüsse

Thomas
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Du könntest collections.deque() benutzen. Es gibt hier einen ähnliches Thread zum Thema "Ringbuffer". Das `deque`-Snippet wurde dort in diesem Beitrag untergebracht, falls es dir hilft.

Im Grunde musst du ja nur wissen bzw errechnen, wieviele Frames / Bilder in den letzten x Sekunden aufgezeichnet wurden. Diese Zahl wäre die Größe des Deques (Übergabe möglich nach dem Schema `deque(maxlen=anzahl_frames)`, siehe oben verlinkte Doku). Um das Rauswerfen veralteter Daten und dem effizienten Nachschieben von neuen Bildern wird sich dann die Deque-Implementierung von selber kümmern - zumindest solange du sie fleißig mit Nachschub versorgst. ;)

EDIT: Naheliegenderweise solltest du dein Vorhaben auch mittels Threads implementieren. Ein Thread kümmert sich um das kontinuierliche Schreiben der Frames in den Buffer. Der andere wartet auf das bestimmte Ereignis und schreibt dann den Pufferinhalt in die Datei - oder stößt das Schreiben zumindest an, damit er schnell wieder in "Wartestellung" gehen kann. Beim Schreiben in die Datei müsstest du in einer Schleife `len(dein_deque)` mal ein `.popleft()` auf dem Deque anwenden, um alle Daten der letzten x Sekunden zu erhalten. Das `len()` sorgt dafür, dass du die tatsächliche Anzahl an Elementen (hier: Frames oder was auch immer) erhältst, denn es könnte ja sein, dass die Deque noch nicht komplett befüllt ist.
Zuletzt geändert von snafu am Samstag 22. Juni 2013, 15:16, insgesamt 1-mal geändert.
FZAG
User
Beiträge: 19
Registriert: Samstag 13. April 2013, 13:29

OK das ist das ich machen möchte nur wie krieg ich die Bilder (Frames) in das Deque?

ich kriege folgende Fehlermeldung dabei wenn ich das Frame schreiben möchte:


ringbuffer.extend(frame)
TypeError: 'cv.iplimage' object is not iterable

das Frame generiere ich mit:

frame = cv.QueryFrame(capture)

grüsse

Thomas
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

FZAG hat geschrieben:OK das ist das ich machen möchte nur wie krieg ich die Bilder (Frames) in das Deque?
Bitte lies die Doku. Das geht mit `.append()`. Ich suche hier keine Links zusammen, nur damit du trotzdem auf doof rumprobierst. Nicht böse gemeint, aber sowas mag ich nicht. Wenn du Probleme mit der Doku (z.B. wegen Englisch) hast, dann sag's ruhig. Aber Trial-and-Error ist bei sowas echt Mist.

EDIT: Sorry, `.extend()` hast du vermutlich über die Doku rausgekriegt. War jetzt etwas überreagiert. Wie gesagt, du musst nach und nach die Elemente einfügen, da `cv.QueryFrame()` immer nur einen Frame zurückgibt. Ich hatte im vorherigen Beitrag auch schon ein Edit gemacht, was dir helfen könnte. :)
FZAG
User
Beiträge: 19
Registriert: Samstag 13. April 2013, 13:29

snafu hat geschrieben:
FZAG hat geschrieben:OK das ist das ich machen möchte nur wie krieg ich die Bilder (Frames) in das Deque?
Bitte lies die Doku. Das geht mit `.append()`. Ich suche hier keine Links zusammen, nur damit du trotzdem auf doof rumprobierst. Nicht böse gemeint, aber sowas mag ich nicht. Wenn du Probleme mit der Doku (z.B. wegen Englisch) hast, dann sag's ruhig. Aber Trial-and-Error ist bei sowas echt Mist.

EDIT: Sorry, `.extend()` hast du vermutlich über die Doku rausgekriegt. War jetzt etwas überreagiert. Wie gesagt, du musst nach und nach die Elemente einfügen, da `cv.QueryFrame()` immer nur einen Frame zurückgibt. Ich hatte im vorherigen Beitrag auch schon ein Edit gemacht, was dir helfen könnte. :)

Danke ja habe es bemerkt mitt append solte es gehen, und das mit dem Frame habe ich rausgekriegt, ja war vieleich zu voreilig mein Text, sorry

Danke trotzdem
FZAG
User
Beiträge: 19
Registriert: Samstag 13. April 2013, 13:29

Nun muss ich nur noch das rechte Format von Opencv zurückerhalten

mit cv,QueryFrame erhalte ich: <iplimage(nChannels=3 width=640 height=480 widthStep=1920 )>

mit cvGrabFrame erhalte ich "1"

Danke kontaktiere mal das Handbuch

ansonsten funktioniert das Abfüllen des Deques
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Falls du's noch nicht weißt: Mittels `cv.GetCaptureProperty(capture, cv.CV_CAP_PROP_FPS)` kannst du die Framerate der Kamera erhalten, was ja für die Berechnung durchaus wichtig sein kann.

Übrigens würde ich das moderne `cv2`-Interface empfehlen. Habe mal (ungetestet) einen kleinen Wrapper für die wichtigsten Funktionen gebastelt:

Code: Alles auswählen

import cv2

class Camera(object):
    def __init__(self, device=0):
        self._capture = cv2.VideoCapture(device)
        if not self.is_connected():
            raise IOError('Failed to open device')

    def is_connected(self):
        return self._capture.isOpened()

    def get_frame(self):
        success, frame = self._capture.read()
        if not success:
            raise IOError('Failed to read frame')
        return frame

    @property
    def framerate(self):
        fps = cv2.cv.CV_CAP_PROP_FPS
        return self._capture.get(fps)

    def disconnect(self):
        self._capture.release()
FZAG
User
Beiträge: 19
Registriert: Samstag 13. April 2013, 13:29

Danke für die Tipps,

mit CVCapture erhalte ich wenn ich richtig interpretiert habe den Pointer auf das Bild, Dieses ist jedoch später nicht mehr abrufbar, Ist irgendwo die Buffergrösse des CV Moduls einstellbar oder wie kann ich da ein Biuld in einem verwendbaren Format zurückerhalten? so dass ich es in den Ringspeicher kriege?


mit dem save Modul gebe ich ja den Anmen an, oder gibt es einen Trick diesen in eine Variable zu legen?

Irgendwie fehlt mir monemtan der klick im Kopf, sorry

Danke

Thomas
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Naja, ich kann's hier nicht testen, sondern habe mir die Klasse aus der Doku "blind" zusammengestellt. Hast du denn das `cv`- oder das `cv2`-Interface benutzt? Zu ersterem heißt es:
Note: OpenCV 1.x functions cvRetrieveFrame and cv.RetrieveFrame return image stored inside the video capturing structure. It is not allowed to modify or release the image! You can copy the frame using cvCloneImage() and then do whatever you want with the copy.
Da lese ich zwar nicht direkt was von Pointern raus, aber die Restriktion, dass nichts direkt am Frame verändert werden darf, könnte ja darauf hindeuten, dass deine Schwierigkeiten möglicherweise dort ihren Ursprung haben.

Versuch's doch wirklich mal mit dem neueren Interface. :)
FZAG
User
Beiträge: 19
Registriert: Samstag 13. April 2013, 13:29

Ich habe momentan noch CV 2.1 installiert.

werde demnach mal 2.4 installieren, habe es runtergeladen,

was gibt es zu beachten bei der Installation?

So wie ich es verstanden habe bleibt das Bild im CV drin und es werden lediglich die Informationen verarbeitet und weitergegeben.

Werde heute mal Experimentieren


Danke
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Hm, ich will nicht nervig erscheinen, aber es geht wirklich darum, ob du `cv` oder `cv2` *importierst* und dann auch die entsprechend anders benannten Methoden (siehe mein Doku-Link) verwendest. Installiert sein müsste bei den meisten heutzutage sowieso CV 2.x. Aber ich bin jetzt auch nicht sooo der CV-Experte. Ich dachte mir nur, wenn es doch einen Warnhinweis bezüglich 1.x gibt, dass dann in 2.x die Bilder komplett unabhängig von CV-Interna sind.
thomasgull
User
Beiträge: 48
Registriert: Samstag 2. Februar 2013, 18:52

Momentan CV
FZAG
User
Beiträge: 19
Registriert: Samstag 13. April 2013, 13:29

The methods/functions combine VideoCapture::grab() and VideoCapture::retrieve() in one call. This is the most convenient method for reading video files or capturing data from decode and return the just grabbed frame. If no frames has been grabbed (camera has been disconnected, or there are no more frames in video file), the methods return false and the functions return NULL pointer.

Wenn ich das jetzt richtig verstehe kommt immer eine Pointeradresse?

ansonsten müsste ja das Ausgabeformat auch bekannt sein
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Wäre ja nicht ganz abwegig, wenn Frame-Anfragen erstmal nur Zeiger zurückliefern, da Frames als "richtige" Bilder abgelegt ja recht schnell viel Speicherplatz verbrauchen können - auch wenn ich persönlich das jetzt nicht so aus der Doku rausgelesen hab. Naja, dann musst du halt überlegen, ob du jeden Frame in deinen Ringpuffer tatsächlich reinkopierst und bei Rauswurf aus dem Ringpuffer Pythons Garbage Collection automatisch die rausgeworfenen Bilddaten löschen lässt oder ob du vorab entscheidest, ob eine Kopie mit den echten Bilddaten behalten werden soll oder ob du den Frame gleich verwirfst.
FZAG
User
Beiträge: 19
Registriert: Samstag 13. April 2013, 13:29

ich brauche einfach einen speicher der ca 10 sekunden der Vergangenheit beinhaltet. und bei einem ereigniss rausschreibt

alternativen wären PIL, aber bin ich noch nicht im Klaren wie ich ein Strem daraus mache und die Framerate
oder G-Stream wobei ich da nicht weiss ob man Texte und so einfügen kann
Antworten