在PythonAnywhere上配置视频流Flask服务器托管

cclgggtu  于 2023-11-20  发布在  Python
关注(0)|答案(2)|浏览(115)

托管--> PythonAnywhere
工作:服务器从客户端接收图像并将其更新到网页。另一个客户端访问该网页并可以看到视频流。服务器不保存图像,它只是在接收图像时将其显示在网页上。
问题-->图像上传到服务器是顺利的,但只要我打开网页,从客户端上传的图像停止。如果有人访问网页,服务器无法接收图像
服务器代码

from flask import Flask, Response, render_template
from flask import request
import cv2
import numpy as np

app = Flask(__name__)

global current_frame
current_frame = None

def generate_frames():
    while True:
        if current_frame is not None:
            ret, buffer = cv2.imencode('.jpg', current_frame)
            if ret:
                frame_bytes = buffer.tobytes()
                yield (b'--frame\r\n'
                       b'Content-Type: image/jpeg\r\n\r\n' + frame_bytes + b'\r\n')

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/video_feed')
def video_feed():
    return Response(generate_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')

@app.route('/upload_frame', methods=['POST'])
def upload_frame():
    global current_frame
    frame = request.data
    nparr = np.fromstring(frame, np.uint8)
    current_frame = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
    return "Frame received and displayed"

if __name__ == '__main__':
    app.run('0.0.0.0')

字符串
客户端代码

import cv2
import requests
import numpy as np
import time

server_url = "http://danial880.pythonanywhere.com/upload_frame"

cap = cv2.VideoCapture(0)

while True:
    ret, frame = cap.read()

    if not ret:
        print("Failed to capture frame")
        break

    _, buffer = cv2.imencode('.jpg', frame)
    frame_bytes = buffer.tobytes()

    try:
        # Send the frame to the server
        response = requests.post(server_url, data=frame_bytes, headers={"Content-Type": "image/jpeg"})

        if response.status_code == 200:
            print("Frame uploaded successfully")
        else:
            print(f"Frame upload failed with status code {response.status_code}")
    except requests.exceptions.RequestException as e:
        print(f"Error: {e}")

    #cv2.imshow("Webcam Feed", frame)
    time.sleep(0.1)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()


我尝试的解决方案:使服务器异步

from flask import Flask, Response, render_template
from flask import request
import cv2
import numpy as np
import asyncio

app = Flask(__name__)

global current_frame
current_frame = None

async def generate_frames():
    while True:
        if current_frame is not None:
            ret, buffer = cv2.imencode('.jpg', current_frame)
            if ret:
                frame_bytes = buffer.tobytes()
                yield (b'--frame\r\n'
                       b'Content-Type: image/jpeg\r\n\r\n' + frame_bytes + b'\r\n')
        await asyncio.sleep(0.01)  # Add a small delay to reduce CPU load

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/video_feed')
def video_feed():
    return Response(generate_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')

@app.route('/upload_frame', methods=['POST'])
async def upload_frame():
    global current_frame
    frame = request.data
    nparr = np.fromstring(frame, np.uint8)
    current_frame = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
    return "Frame received and displayed"

if __name__ == '__main__':
    app.run()


但是在异步服务器之后,网页上没有显示任何图像。简单服务器显示的是收到的最后一帧。
我可以对服务器进行什么更改,以便我可以有一个流畅的流。

okxuctiv

okxuctiv1#

如果Flask太慢,为了测试,尝试其他处理并发请求的解决方案,如Eventletpip install eventlet)或Geventpip install gevent),并对标准库进行monkey-patch以使其成为非阻塞的。
对于Eventlet(使用monkey_patch):

import eventlet
eventlet.monkey_patch()

# rest of your code

if __name__ == '__main__':
    app.run('0.0.0.0')

字符串
对于Gevent(使用atch_all):

from gevent import monkey
monkey.patch_all()

# rest of your code

if __name__ == '__main__':
    app.run('0.0.0.0')


使用猴子补丁提高了流媒体速度,但不是很流畅。我在AWS LightSale上尝试过相同的服务器代码。还有其他方法可以改进吗?
如果使用Monkey修补程序后流媒体性能有所改善,但仍然不完全流畅,您可以尝试:

  • 优化视频流编码:在发送到服务器之前压缩帧以减小其大小。您可以在cv2.imencode中调整JPEG压缩级别,以在质量和性能之间找到平衡。-限制客户端捕获和服务器发送端的帧速率,以减少工作量。
  • 降低正在处理和传输的视频帧的分辨率。更高的分辨率会显著增加CPU和带宽的使用。
  • 在客户端侧实现缓冲以处理间歇性网络延迟并提供更平滑的观看体验。
  • 实现一个生产者-消费者队列来处理帧处理。这可以帮助管理帧流,并可能使处理更加平滑。

以下是如何实现帧速率限制和分辨率降低的示例:

# On the client side:
cap.set(cv2.CAP_PROP_FPS, 15)  # Limit the frame rate to 15 FPS
ret, frame = cap.read()
frame = cv2.resize(frame, (640, 480))  # Reduce the resolution if necessary

# On the server side:
# Implement a frame rate control in generate_frames function
import time
last_time = time.time()
while True:
    current_time = time.time()
    if current_time - last_time > 1.0 / 15:  # Target frame rate of 15 FPS
        last_time = current_time
        # Rest of the loop logic...


如果服务器从多个客户端接收请求,请考虑实施负载平衡。在AWS上,可以使用Elastic Load Balancing进行管理。
也可以尝试使用profile your server's performance来识别瓶颈。像用于CPU分析的cProfile和用于内存使用的memory_profiler这样的工具可以提供帮助。
请记住,网络速度和延迟可能是一个因素,特别是在涉及不同地理区域的情况下。与PythonAnywhere相比,AWS LightSail应该提供更好的网络性能,特别是如果您选择更靠近客户端的区域。
尝试不同配置的Web服务器和WSGI容器,如GunicornuWSGI与Nginx。这些服务器更能够处理并发连接,并且可以进行性能微调。
还可以考虑使用WebSocket在客户端和服务器之间建立持久连接,这更适合于实时数据传输。

jrcvhitl

jrcvhitl2#

您无法在PythonAnywhere Web应用程序中运行异步代码。

相关问题