首页 > 解决方案 > Python Flask 仅在浏览器中显示从 OpenCV 流式传输的实时视频中的一帧

问题描述

我遇到了一个奇怪的问题,因为这是昨晚工作的,据我所知,我没有进行任何更改。因此,我通过与远程机器的套接字连接从我的树莓派获得了 opencv 流。然后,我计划将其传递到烧瓶中,以将其显示在用户可以查看实时提要的网页上。

客户端.py

import cv2
import io
import socket
import struct
import time
import pickle
import zlib

client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(('ec2 instance id', 8089))
connection = client_socket.makefile('wb')

cam = cv2.VideoCapture(0)

cam.set(3, 320);
cam.set(4, 240);

img_counter = 0

encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 90]

while True:
    ret, frame = cam.read()
    result, frame = cv2.imencode('.jpg', frame, encode_param)
#    data = zlib.compress(pickle.dumps(frame, 0))
    data = pickle.dumps(frame, 0)
    size = len(data)


    print("{}: {}".format(img_counter, size))
    client_socket.sendall(struct.pack(">L", size) + data)
    img_counter += 1

cam.release()

现在这是我的代码变得有点混乱的地方,当谈到 python 时,我并不是最好的。我知道下面的这个套接字代码可以分成不同的类和东西。

服务器.py

from flask import Flask, render_template, Response
from flask import make_response
import cv2
import socket
import sys
import cv2
import pickle
import numpy as np
import struct ## new
import zlib
app = Flask(__name__)

@app.route('/')
def index():
    """Video streaming home page."""
    return render_template('index.html')


def gen():
    """Video streaming generator function."""
    HOST=''
    PORT=8089

    s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    print('Socket created')

    s.bind((HOST,PORT))
    print('Socket bind complete')
    s.listen(10)
    print('Socket now listening')

    conn,addr=s.accept()
    data = b""
    payload_size = struct.calcsize(">L")
    print("payload_size: {}".format(payload_size))
    while True:
        while len(data) < payload_size:
            print("Recv: {}".format(len(data)))
            data += conn.recv(4096)

        print("Done Recv: {}".format(len(data)))
        packed_msg_size = data[:payload_size]
        data = data[payload_size:]
        msg_size = struct.unpack(">L", packed_msg_size)[0]
        print("msg_size: {}".format(msg_size))
        while len(data) < msg_size:
            data += conn.recv(4096)

        frame_data = data[:msg_size]
        data = data[msg_size:]

        frame=pickle.loads(frame_data, fix_imports=True, encoding="bytes")
        frame = cv2.imdecode(frame, cv2.IMREAD_COLOR)
        #vc = cv2.VideoCapture(frame)
        #below I am looping through frame and converting them back to byptes
         so I can display them in the browser as an image 

        for data1 in frame:
            data1 = cv2.imencode('.jpg', frame)[1].tobytes()
            yield (b'--frame\r\n'
                   b'Content-Type: image/jpeg\r\n\r\n' +data1+ b'\r\n\r\n')



@app.route('/video_viewer')
def video_feed():

    return Response(gen(),
                    mimetype='multipart/x-mixed-replace; boundary=frame')

if __name__ == '__main__':
    app.run(host='0.0.0.0', debug=True, threaded=True)

现在,当我运行这些时,只会向我显示一个图像,而不是不断地输入图像。就像我说的这种方法昨晚确实有效。我的猜测是我的循环有问题?for data1 in the frame:. 为写得不好的套接字代码道歉。任何正确方向的帮助将不胜感激。

收到第一个图像帧后,烧瓶的输出会创建一个新的获取请求,该请求会停止实时提要

收到第一个图像帧后,烧瓶的输出会创建一个新的获取请求,该请求会停止实时提要

标签: pythonpython-3.xopencvflask

解决方案


推荐阅读