[OpenCV DNN] Flask Video Surveillance Target Detection Tutorial 05

Welcome to the "OpenCV DNN @ Youcans" series, which is being updated continuously


This series starts from scratch and explains in detail the use of the Flask framework to build a web application for the OpenCV DNN model.

This section introduces how to build a streaming media server with Flask, and send a request to the server to play local video files.


3.5 The browser plays the video file on the video server

This routine uses the Flask framework to build a video streaming server, reads local video files through OpenCV, and sends a request to the server to play the video stream.

The framework of this project is the same as cvFlask04, the main difference is to obtain the video file path name from the webpage and use OpenCV to read the video file.


cvFlask05 project file tree

Create a new Flask project. The file tree of the cvFlask05 project is as follows.

---文件名\
    |---templates\
    |    |---index2.html
|--- cvFlask05.py
|--- vedio_01.mp4

cvFlask05 project program file

The task logic is implemented by the Python program file cvFlask05.py, and the complete code is as follows.

# cvFlask05.py
# OpenCV+Flask 图像处理例程 05
# 通过浏览器播放视频服务器上的视频文件
# Copyright 2023 Youcans, XUPT
# Crated:2023-4-30

# coding:utf-8
from flask import Flask, Response, render_template, request
import cv2

app = Flask(__name__)

# 定义视频流类
class VideoStream:
    def __init__(self, source):  # 传入视频源
        self.video_capture = cv2.VideoCapture(source)  # 使用视频文件

    def get_frame(self):
        success, frame = self.video_capture.read()  # 读取视频帧
        if not success:
            return None
        ret, buffer = cv2.imencode('.jpg', frame)  # 编码为 jpg 格式
        frame_byte = buffer.tobytes()  # 转换为 bytes 类型
        return frame_byte

    def __del__(self):
        self.video_capture.release()  # 释放视频流

# 视频流的网页 HTML 模板
@app.route('/')
def index():
    return render_template('index2.html')

# 生成视频流的帧
def gen_frames(video_source):
    video_stream = VideoStream(video_source)  # 从视频文件获取视频流
    while True:
        frame = video_stream.get_frame()  # 获取视频帧
        if frame is None:
            # video_stream.__del__()  # 释放视频流
            break
        yield (b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n'
               + frame + b'\r\n')  # 生成视频流的帧

# 视频流的传输路由:从网页获取视频源,返回视频流
@app.route('/video_feed')
def video_feed():
    video_source = request.args.get('video_source', 'camera')  # 从网页获取视频源
    return Response(gen_frames(video_source),
                    content_type='multipart/x-mixed-replace; boundary=frame')

if __name__ == '__main__':
    # 启动一个本地开发服务器,激活该网页
    print("URL: http://127.0.0.1:5000")
    app.run(host='0.0.0.0', port=5000, debug=True, threaded=True)  # 绑定 IP 地址和端口号

The difference between the program cvFlask05.py and cvFlask04.py is:
(1) The defined video stream class VideoStream accepts the video source parameter source, uses OpenCV to create a video reading object, and reads video frames frame by frame.
(2) The subroutine video_feed() obtains the path and file name 'vedio_01.mp4' of the video file from the web page template index2.html as the video source.


cvFlask05 project web page template

The webpage template index2.html of the video stream is specified in the subroutine index(). The webpage index2.html is located in the templates folder, and the specific content is as follows.

<!DOCTYPE html>
<html>
  <head>
    <title>Video Streaming Demonstration</title>
  </head>
  <body>
    <h2  align="center">OpenCV+Flask 例程:视频传输</h2>
    <img src="{
    
    { url_for('video_feed', video_source='vedio_01.mp4') }}" alt="Video stream">
  </body>
</html>

Similarly, the img tag defines the url used by the image, which is returned to the front end by the url_for() function. The difference between the web page template index2.html and index1.html is that the url is dynamically obtained by using the name of the view function and the query string. 'video_feed' is the name of the view function, and the path and file name of the video file 'vedio_01.mp4' is placed in url_for() as a parameter in the form of a keyword argument.

The /video_feed path is served by the video_feed() method, which returns a multipart response. The generator function gen_frames() continuously obtains pictures from VideoStream frame by frame, and returns them to the client through the generator. When the client browser receives the streaming media, it will display it frame by frame in the picture defined by the img tag, so as to realize video playback.


cvFlask05 project running

Enter the root directory of the cvFlask05 project, run the program cvFlask05.py, and start the streaming server.

 * Running on all addresses (0.0.0.0)  
 * Running on http://127.0.0.1:5000
 * Running on http://192.168.3.249:5000

Open http://192.168.3.249:5000 in the browser of the device (including mobile phone) in the LAN, and then the video file vedio_01.mp4 on the video server can be played.

insert image description here


3.6 Browser to play video files + control buttons

Further, we add two control buttons "Start" and "Stop" to control the start and stop of playing the video stream.
Adding control buttons to a Flask application requires modifying the front-end and back-end code. The front end needs to add buttons and JavaScript code to send requests, and the back end needs to add routes to handle these requests.

We add "start" and "stop" buttons on the frontend, which when clicked send requests to the "/start" and "/stop" routes.

We modify the VideoCamera class and the gen function so that it starts or stops generating video frames on request. A new method set_path has been added to the VideoCamera class to change the video source. We added a new route "/set_path" which accepts a POST request and a form parameter 'video_path' and then uses this parameter to set the video source. Added new routes "/start" and "/stop" to control the on/off status of the video stream.


cvFlask05c project file tree

Create a new Flask project. The file tree of the cvFlask05c project is as follows.

---文件名\
    |---templates\
    |    |---index2c.html
|--- cvFlask05c.py
|--- vedio_01.mp4

cvFlask05c project program file

The task logic is implemented by the Python program file cvFlask05c.py, and the complete code is as follows.

# cvFlask05c.py
# OpenCV+Flask 图像处理例程 05b
# 通过浏览器播放视频服务器上的视频文件+控制按钮
# Copyright 2023 Youcans, XUPT
# Crated:2023-4-30

# coding:utf-8
from flask import Flask, Response, render_template, request
import cv2

app = Flask(__name__)

# 定义视频流类
class VideoStream:
    def __init__(self, video_path=None):  # 传入视频源
        if video_path is None:
            self.video_cap = cv2.VideoCapture(0)  # 创建视频设备读取对象
        else:
            self.video_cap = cv2.VideoCapture(video_path)  # 创建视频文件读取对象
        self.is_streaming = False

    def __del__(self):
        self.video_cap.release()  # 释放视频流

    def get_frame(self):
        success, frame = self.video_cap.read()  # 读取视频帧
        if success and self.is_streaming:
            ret, buffer = cv2.imencode('.jpg', frame)  # 编码为 jpg 格式
            frame_byte = buffer.tobytes()  # 转换为 bytes 类型
            return frame_byte
        else:
            return None

    def set_path(self, video_path):
        self.video_cap.release()
        self.video_cap = cv2.VideoCapture(video_path)

video_stream = VideoStream()  # 实例化视频流对象

# 生成视频流的帧
def gen_frames():
    while True:
        frame = video_stream.get_frame()  # 获取视频帧
        if frame is not None:
            yield (b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n'
               + frame + b'\r\n')  # 生成视频流的帧

# 视频流的网页 HTML 模板
@app.route('/')
def index():
    return render_template('index2c.html')

# 视频流的传输路由:从网页获取视频源,返回视频流
@app.route('/video_feed')
def video_feed():
    return Response(gen_frames(),
                    content_type='multipart/x-mixed-replace; boundary=frame')

@app.route('/start', methods=['POST'])
def start():
    video_stream.is_streaming = True
    return ('', 204)

@app.route('/stop', methods=['POST'])
def stop():
    video_stream.is_streaming = False
    return ('', 204)

@app.route('/set_path', methods=['POST'])
def set_path():
    video_path = request.form.get('video_path')
    video_stream.set_path(video_path)
    return ('', 204)

if __name__ == '__main__':
    # 启动一个本地开发服务器,激活该网页
    print("URL: http://127.0.0.1:5000")
    app.run(host='0.0.0.0', port=5000, debug=True, threaded=True)  # 绑定 IP 地址和端口号

cvFlask05c project web page template

The web page template index2c.html of the video stream is specified in the subroutine index(). We add "start" and "stop" buttons to the front end and specify the format of the buttons. The webpage index2c.html is located in the templates folder, and the specific content is as follows.

<!DOCTYPE html>
<html>
  <head>
    <title>Video Streaming Demonstration</title>
    <style>
      #video {
    
    
          display: block;
          margin: 0 auto;
          width: 600px;
          height: 300px;
      }
      #button-container {
    
    
          display: flex;
          justify-content: center;
          gap: 100px;
          margin-top: 10px;  /* 新增:设置按钮与视频画面的间距 */
      }
      button {
    
    
          width: 60px;
          height: 30px;
      }
      </style>
  </head>
  <body>
    <h2  align="center">OpenCV+Flask 例程:播放视频文件</h2>
    <div style="text-align:center; padding-top:inherit">
      <img id="video" src="{
    
    { url_for('video_feed') }}" style="display: none">
    </div>
    <div id="button-container">
      <button id="start">Start</button>
      <button id="stop">Stop</button>
    </div>

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script>
      $(document).ready(function(){
    
    
          var video_path = "vedio_01.mp4"; // 替换为你的视频文件路径
          $("#start").click(function(){
    
    
              $.post("/set_path", {
    
    "video_path": video_path}, function() {
    
    
                  $.post("/start", function() {
    
    
                      $("#video").show();
                  });
              });
          });
          $("#stop").click(function(){
    
    
              $.post("/stop", function() {
    
    
                  $("#video").hide();
              });
          });
      });
      </script>
  </body>
</html>

Enter the root directory of the cvFlask05c project, run the program cvFlask05c.py, and start the streaming media server.

Open http://192.168.3.249:5000 in the browser of the device (including mobile phones) in the LAN, and there are two action buttons "Start" and "Stop" on the page. Click the "Start" button to start playing the video file vedio_01.mp4 on the video server, and click the "Stop" button to end the playback.

insert image description here


【End of this section】

In the next section we will discuss: OpenCV+Flask real-time monitoring and video playback.


Copyright statement:
youcans@xupt Original works, reprints must be marked with the original link:
[OpenCV DNN] Flask Video Surveillance Target Detection Tutorial 05
(https://blog.csdn.net/youcans/article/details/130989608)
Copyright 2023 youcans, XUPT
Crated: 2023-06-01

Welcome to the "OpenCV DNN @ Youcans" series
[OpenCV DNN] Flask Video Surveillance Target Detection Tutorial 01
[OpenCV DNN] Flask Video Surveillance Target Detection Tutorial 02
[OpenCV DNN] Flask Video Surveillance Target Detection Tutorial 03
[OpenCV DNN] Flask Video Surveillance Target Detection Tutorial 04


Guess you like

Origin blog.csdn.net/youcans/article/details/130989608