小编典典

如何从IP摄像机解析mjpeg http流?

python

下面给出的是用于从IP摄像机获取实时流的代码。

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

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


阅读 357

收藏
2020-12-20

共1个答案

小编典典

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中运行。上面的代码无需依赖opencv即可手动解析mjpeg流,因为在我的某些项目中,无论我做什么(c
,python),URL都不会被opencv打开。

通过http的Mjpeg是具有边界帧信息的multipart / x-mixed-
replace,而jpeg数据只是以二进制形式发送。因此,您实际上不需要关心HTTP协议标头。所有jpeg帧均以marker开头,以0xff 0xd8结尾0xff 0xd9。因此,以上代码从http流中提取了此类帧,并对其进行了逐一解码。像下面一样。

...(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功能,则可以先编码为h264。但是,如果摄像机将一些元数据添加到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()
2020-12-20