首页 > 解决方案 > 将实时视频帧从用户/客户端(Android 应用程序、iPhone 应用程序、python)流式传输到 Flask API(服务器),然后返回到客户端

问题描述

我正在开发 Flask 中的对象检测 API,我想从客户端获取实时视频流,该视频流可能来自 Android 手机、iPhone 或仅来自在 Windows/Linux 上运行的 python 脚本。起初我尝试以下:

def processFrames():
    print('[DEBUG] call cv2.VideoCapture(0) from PID', os.getpid())
    camera = cv2.VideoCapture(0)
    while camera.isOpened():
        ret, frame = camera.read()
        if not ret:
            break
        else:
            frame = DetectObject(frame) 
            
            ret, buffer = cv2.imencode('.jpg', frame)
            frame = buffer.tobytes()
            yield (b'--frame\r\n'
                   b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')

@endpoints.route('/RealTime', methods=['GET','POST'])
def RealTime():
    return Response(processFrames(), mimetype='multipart/x-mixed-replace; boundary=frame')

但它不断给出错误:

[警告:1]全局/tmp/pip-req-build-13uokl4r/opencv/modules/videoio/src/cap_v4l.cpp(890)打开VIDEOIO(V4L2:/dev/video0):无法按索引打开摄像机

我意识到这是因为 OpenCV 试图打开服务器上的相机。然后我来到了这个解决方案: https ://stackoverflow.com/a/59998983/16396308

但我不知道如何收到来自:

emit('response_back', stringData)

[编辑]

请帮助,因为当我使用上面的解决方案时,通过邮递员发送了一个图像,这是我在服务器上的:

frame = secure_filename(file.filename)
sbuf = StringIO()
sbuf.write(frame)
b = BytesIO(pybase64.b64decode(frame))
pimg = Image.open(b)

将图像作为文件接收(暂时),但对于一张图像,我收到以下错误:

binascii.Error binascii。

错误:不正确的填充

对于不同的图像,我得到以下错误:

PIL.UnidentifiedImageError

PIL.UnidentifiedImageError:无法识别图像文件 <_io.BytesIO object at 0x7f3d9bbcf5e0>

[编辑 2]

我能够将视频从 python 脚本流式传输到远程机器。

客户端.py

def RT_Rec():
    camera = cv2.VideoCapture(0)
    try:
        while True:
            ret, frame = camera.read()
            content_type = 'image/jpeg'
            headers = {'content-type': content_type}
            url = "https://[REMOTEMACHINEIP]/RealTime"
            _, img_encoded = cv2.imencode('.jpg', frame)       
            response = requests.post(url, data=img_encoded.tobytes(), headers= headers)
            if b"[SUCCESS]" in response.content or b"[ERROR]" in response.content :
                print(response.content.decode('utf-8'))
                break
            else:
                nparr = np.frombuffer(response.content,np.uint8)
                img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
                # print(type(img))
                cv2.imshow("camera", img)
            if cv2.waitKey(1) & 0xFF == ord("q"):
                break
    except Exception as e:
        print(e)
    finally:
        camera.release()
        cv2.destroyAllWindows()

服务器.py

@endpoints.route("/RealTime",methods=["GET","POST"])
def realTime():
    if request.method == "POST":
        img = request.data
        nparr = np.fromstring(img,np.uint8)
        img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
        det,outImg = processFrame(img)
        if det:
            msg = "[SUCCESS] Processed"
            return msg
        _, img_encoded = cv2.imencode('.jpg', outImg)
        return img_encoded.tobytes()
    else:
        return "[ERROR] Invalid Request", 500

现在我想知道如何从 Android/iPhone 应用程序发送帧,以便服务器接收它们而不会出现任何错误。?

标签: pythonopencvflaskobject-detectionobject-detection-api

解决方案


您可以使用 SocketIO 获取用户提要,

from flask import Flask, render_template, request
...
@socketio.on('connect', namespace='/web')
def connect_web():
    print('[INFO] Web client connected: {}'.format(request.sid))

@socketio.on('disconnect', namespace='/web')
def disconnect_web():
    print('[INFO] Web client disconnected: {}'.format(request.sid))


@socketio.on('connect', namespace='/cv')
def connect_cv():
    print('[INFO] CV client connected: {}'.format(request.sid))


@socketio.on('disconnect', namespace='/cv')
def disconnect_cv():
    print('[INFO] CV client disconnected: {}'.format(request.sid))

这里有一些链接会派上用场:


推荐阅读