如何parsing来自IP摄像头的mjpeg httpstream?

下面给出的是从IP摄像机获取直播stream的代码。

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 

在运行代码时,我得到的输出是:

 Cam not found 

我哪里错了? 另外,为什么在这里没有框? 转换有问题吗?

 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) 

编辑(解释)

我刚刚看到你提到你有c ++代码正在工作,如果是这样的话,你的相机也可以在python中工作。 上面的代码手动parsingmjpegstream而不依赖于opencv,因为在我的一些项目中,无论我做了什么(c ++,python),url都不会被opencv打开。

http上的Mjpeg是多部分/ x混合 – 用边框信息replace,jpeg数据只是以二进制forms发送。 所以你并不需要关心http协议头。 所有jpeg帧以标记0xff 0xd8开始并以0xff 0xd8结束。 所以上面的代码从httpstream中提取这样的帧,并逐一解码它们。 如下所示。

 ...(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) 

编辑2(从mjpg文件中读取)

关于你保存文件的问题,是的,文件可以直接保存和重新打开使用相同的方法,只需很小的修改。 例如,你会做curl http://IPCAM > output.mjpg ,然后改变线路stream=urllib.urlopen('http://localhost:8080/frame.mjpg')以便代码变成这个

 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) 

当然,你正在保存大量冗余的http头文件,你可能想要删除它们。 或者如果你有额外的CPU功率,也许只需要编码到H.264。 但是,如果相机正在添加一些元数据到HTTP头帧,如频道,时间戳等,那么保留它们可能是有用的。

编辑3(tkinter接口)

 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() 

首先,请注意,您应该先尝试直接使用OpenCV的video捕捉function,例如cv2.VideoCapture('http://localhost:8080/frame.mjpg')

这对我来说很好:

 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) 

无论如何,这里是Zaw Lin的解决scheme移植到OpenCV 3(只改变是cv2.CV_LOAD_IMAGE_COLORcv2.IMREAD_COLOR和Python 3(string与字节处理改变加上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) 

这是一个使用Python 3 请求模块而不是urllib的答案。

不使用urllib的原因是它不能正确解释一个URL,如http://user:pass@ipaddress:port

在urllib中添加validation参数比请求模块更复杂。

这是一个使用请求模块的简洁明了的解决scheme:

 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)) 

我有同样的问题。 没有请求或urllib的解决scheme:只需添加用户和密码的凸轮地址,使用VideoCapture,如下所示:

例如

cv2.VideoCapture(' http:// user:password@XXX.XXX.XXX.XXX/video ')

使用IPWebcam为Android。