使用OpenCV(Python)从Flask服务器读取MJPEG流

Ara*_*ion 5 python opencv mjpeg flask

我正在使用Flask和flask-restful生成一个MJPEG流.出于原因,我想在另一个Python程序中捕获此流,我使用OpenCV(3).问题是请求的第一帧进展顺利.另一方面,未正确接收请求的第二帧(延迟之后),并抛出错误:

[mpjpeg @ 0000017a86f524a0] Expected boundary '--' not found, instead found a line of 82 bytes
Run Code Online (Sandbox Code Playgroud)

多次.

我相信这是因为框架的边界是手动设置的.我将把违规代码放在下面.

MJPEG流生成:

## Controller for the streaming of content.
class StreamContent(Resource):
    @classmethod
    def setVis(self, vis):
        self.savedVis = vis

    def get(self):
        return Response(gen(VideoCamera(self.savedVis)),
                        mimetype='multipart/x-mixed-replace; boundary=frame')


## Generate a new VideoCamera and stream the retrieved frames.    
def gen(camera):
    frame = camera.getFrame()
    while frame != None:
        yield (b'--frame\r\n'
               b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')
        time.sleep(0.07)
        frame = camera.getFrame()

## Allows for the reading of video frames.
class VideoCamera(object):
    def __init__(self, vis):
        #object we retrieve the frame from.
        self.vis = vis

    ## Get the current frame.
    def getFrame(self):
        image = self.vis.mat_frame_with_overlay
        # We are using Motion JPEG, but OpenCV defaults to capture raw images,
        # so we must encode it into JPEG in order to correctly display the
        # video/image stream.
        ret, jpeg = cv2.imencode('.jpg', image)
        return jpeg.tobytes()
Run Code Online (Sandbox Code Playgroud)

MJPEG流检索:

"""
Get a single frame from the camera.
"""        
class Image(Resource):
    def get(self):
        camera = VideoCamera()
        return Response(camera.getSingleFrame(), mimetype='image/jpeg')

"""
Contains methods for retrieving video information from a source.
"""
class VideoCamera(object):
    def __del__(self):
        self.video.release()

    @classmethod
    def setVideo(self, video):
        self.video = video

    ## Get the current frame.
    def getSingleFrame(self):
        self.startVideoFromSource(self.video)
        ret, image = self.video.read()
        time.sleep(0.5)
        ret, image = self.video.read()
        # We are using Motion JPEG, but OpenCV defaults to capture raw images,
        # so we must encode it into JPEG in order to correctly display the
        # video/image stream.
        ret, jpeg = cv2.imencode('.jpg', image)
        self.stopVideo()
        return jpeg.tobytes()

    def stopVideo(self):
        self.video.release()
Run Code Online (Sandbox Code Playgroud)

Rub*_*las 7

更改帧生成器对我有用:

yield (b'--frame\r\n'
       b'Content-Type:image/jpeg\r\n'
       b'Content-Length: ' + f"{len(frame)}".encode() + b'\r\n'
       b'\r\n' + frame + b'\r\n')
Run Code Online (Sandbox Code Playgroud)


Ara*_*ion 1

对于阿纳巴德(和其他人):

噢,这个问题已经有一段时间了。如果我没记错的话,简短的回答是:不,我从来没能让它正常工作。

多个程序同时以这种方式访问​​相机(当多次向 API 发送请求时,多个线程开始读取相机),这是相机无法处理的。正确处理此问题的最佳方法(在我看来)是在其自己的线程上的单独类中读取相机,并为 API 使用观察者模式。每当客户端发出读取相机的新请求时,观察者就会在新帧可用后发送它们。

这解决了相机被多个类实例/线程访问的问题,这就是这不起作用的原因。解决这个问题,它应该可以正常工作。