wake-up-neo.net

Wie MJPEG http-Stream von IP-Kamera zu analysieren?

Im Folgenden finden Sie den Code zum Abrufen von Live-Streams von einer IP-Kamera.

from cv2 import *
from cv2 import cv
import urllib
import numpy as np
k=0
capture=cv.CaptureFromFile("http://IPADDRESS of the camera/axis-cgi/mjpg/video.cgi")
namedWindow("Display",1)

while True:
    frame=cv.QueryFrame(capture)
    if frame is None:
        print 'Cam not found'
        break
    else:
        cv.ShowImage("Display", frame)
    if k==0x1b:
        print 'Esc. Exiting'
        break

Beim Ausführen des Codes erhalte ich folgende Ausgabe:

Cam not found

Wo gehe ich falsch? Auch, warum ist Frame None hier? Gibt es ein Problem mit der Konvertierung?

import cv2
import urllib 
import numpy as np

stream = urllib.urlopen('http://localhost:8080/frame.mjpg')
bytes = ''
while True:
    bytes += stream.read(1024)
    a = bytes.find('\xff\xd8')
    b = bytes.find('\xff\xd9')
    if a != -1 and b != -1:
        jpg = bytes[a:b+2]
        bytes = bytes[b+2:]
        i = cv2.imdecode(np.fromstring(jpg, dtype=np.uint8), cv2.CV_LOAD_IMAGE_COLOR)
        cv2.imshow('i', i)
        if cv2.waitKey(1) == 27:
            exit(0)   

editieren (Erklärung)

Ich habe gerade gesehen, dass Sie erwähnen, dass Sie C++ - Code haben, der funktioniert, wenn dies der Fall ist, funktioniert Ihre Kamera möglicherweise auch in python. Der obige Code analysiert den mjpeg-Stream manuell, ohne sich auf opencv zu verlassen , da in einigen meiner projekte die url von opencv nicht geöffnet wird, egal was ich gemacht habe (c ++, python).

Mjpeg über http ist multipart/x-mixed-replace mit Boundary Frame Info und JPEG-Daten werden nur binär gesendet. Sie müssen sich also nicht wirklich um HTTP-Protokollheader kümmern. Alle JPEG-Frames beginnen mit dem Marker 0xff 0xd8 Und enden mit 0xff 0xd9. Der obige Code extrahiert solche Frames aus dem http-Stream und decodiert sie nacheinander. Wie unten.

...(http)
0xff 0xd8      --|
[jpeg data]      |--this part is extracted and decoded
0xff 0xd9      --|
...(http)
0xff 0xd8      --|
[jpeg data]      |--this part is extracted and decoded
0xff 0xd9      --|
...(http)

edit 2 (aus mjpg Datei lesen)

In Bezug auf Ihre Frage zum Speichern der Datei kann die Datei mit der gleichen Methode mit sehr geringen Änderungen direkt gespeichert und wieder geöffnet werden. Zum Beispiel würden Sie curl http://IPCAM > output.mjpg Ausführen und dann die Zeile stream=urllib.urlopen('http://localhost:8080/frame.mjpg') so ändern, dass der Code zu diesem Code wird

import cv2
import urllib 
import numpy as np

stream = open('output.mjpg', 'rb')
bytes = ''
while True:
    bytes += stream.read(1024)
    a = bytes.find('\xff\xd8')
    b = bytes.find('\xff\xd9')
    if a != -1 and b != -1:
        jpg = bytes[a:b+2]
        bytes = bytes[b+2:]
        i = cv2.imdecode(np.fromstring(jpg, dtype=np.uint8), cv2.CV_LOAD_IMAGE_COLOR)
        cv2.imshow('i', i)
        if cv2.waitKey(1) == 27:
            exit(0)   

Natürlich speichern Sie eine Menge redundanter HTTP-Header, die Sie möglicherweise entfernen möchten. Oder wenn Sie zusätzliche CPU-Leistung haben, verschlüsseln Sie sie einfach zuerst nach h264. Wenn die Kamera jedoch einige Metadaten zu HTTP-Header-Frames wie Kanal, Zeitstempel usw. hinzufügt, kann es hilfreich sein, diese beizubehalten.

edit 3 (tkinter schnittstelle)

import cv2
import urllib 
import numpy as np
import Tkinter
from PIL import Image, ImageTk
import threading

root = Tkinter.Tk()
image_label = Tkinter.Label(root)  
image_label.pack()

def cvloop():    
    stream=open('output.mjpg', 'rb')
    bytes = ''
    while True:
        bytes += stream.read(1024)
        a = bytes.find('\xff\xd8')
        b = bytes.find('\xff\xd9')
        if a != -1 and b != -1:
            jpg = bytes[a:b+2]
            bytes = bytes[b+2:]
            i = cv2.imdecode(np.fromstring(jpg, dtype=np.uint8), cv2.CV_LOAD_IMAGE_COLOR)            
            tki = ImageTk.PhotoImage(Image.fromarray(cv2.cvtColor(i, cv2.COLOR_BGR2RGB)))
            image_label.configure(image=tki)                
            image_label._backbuffer_ = tki  #avoid flicker caused by premature gc
            cv2.imshow('i', i)
        if cv2.waitKey(1) == 27:
            exit(0)  

thread = threading.Thread(target=cvloop)
thread.start()
root.mainloop()
75
Zaw Lin

Beachten Sie bitte zunächst, dass Sie zuerst versuchen einfach die Videoaufnahmefunktionen von OpenCV verwenden sollten direkt, z. cv2.VideoCapture('http://localhost:8080/frame.mjpg')!

Das funktioniert gut für mich:

import cv2
cap = cv2.VideoCapture('http://localhost:8080/frame.mjpg')

while True:
  ret, frame = cap.read()
  cv2.imshow('Video', frame)

  if cv2.waitKey(1) == 27:
    exit(0)

Wie auch immer, hier ist die Lösung von Zaw Lin, die auf OpenCV 3 portiert wurde (nur die Änderung ist cv2.CV_LOAD_IMAGE_COLOR bis cv2.IMREAD_COLOR und Python 3 (String vs. Byte-Behandlung geändert plus urllib):

import cv2
import urllib.request
import numpy as np

stream = urllib.request.urlopen('http://localhost:8080/frame.mjpg')
bytes = bytes()
while True:
    bytes += stream.read(1024)
    a = bytes.find(b'\xff\xd8')
    b = bytes.find(b'\xff\xd9')
    if a != -1 and b != -1:
        jpg = bytes[a:b+2]
        bytes = bytes[b+2:]
        i = cv2.imdecode(np.fromstring(jpg, dtype=np.uint8), cv2.IMREAD_COLOR)
        cv2.imshow('i', i)
        if cv2.waitKey(1) == 27:
            exit(0)
34
bugmenot123

Hier ist eine Antwort mit dem Python 3 Anfragen -Modul anstelle von rllib.

Der Grund für die Nichtverwendung von urllib ist, dass eine URL wie http://user:[email protected]:port Nicht korrekt interpretiert werden kann.

Das Hinzufügen von Authentifizierungsparametern ist in urllib komplexer als im Anforderungsmodul.

Hier ist eine nette, prägnante Lösung mit dem Anforderungsmodul:

import cv2
import requests
import numpy as np

r = requests.get('http://192.168.1.xx/mjpeg.cgi', auth=('user', 'password'), stream=True)
if(r.status_code == 200):
    bytes = bytes()
    for chunk in r.iter_content(chunk_size=1024):
        bytes += chunk
        a = bytes.find(b'\xff\xd8')
        b = bytes.find(b'\xff\xd9')
        if a != -1 and b != -1:
            jpg = bytes[a:b+2]
            bytes = bytes[b+2:]
            i = cv2.imdecode(np.fromstring(jpg, dtype=np.uint8), cv2.IMREAD_COLOR)
            cv2.imshow('i', i)
            if cv2.waitKey(1) == 27:
                exit(0)
else:
    print("Received unexpected status code {}".format(r.status_code))
10
Varun Chatterji