如何使用 OpenCV 和 Flask 实现带红色边框的视频录制与下载

秋瑶同学_7009

秋瑶同学_7009

2026-08-06

800人浏览

原创

如何使用 OpenCV 和 Flask 实现带红色边框的视频录制与下载

本文介绍一种基于 flask 和 opencv 的端到端视频处理方案:在浏览器中实时调用摄像头录制视频,并在服务端为每一帧动态添加红色(rgb: 0,0,255)边框,最终生成并提供带边框的 mp4 文件供下载。

本文介绍一种基于 flask 和 opencv 的端到端视频处理方案:在浏览器中实时调用摄像头录制视频,并在服务端为每一帧动态添加红色(rgb: 0,0,255)边框,最终生成并提供带边框的 mp4 文件供下载。

在原始实现中,用户通过前端 MediaRecorder 录制视频并保存为本地 Blob,再上传或触发后端处理——但该流程存在关键缺陷:边框是在录制完成后的离线转码阶段添加的,而 MediaRecorder 生成的 MP4 文件常因编码兼容性问题导致 cv2.VideoCapture 读取失败或帧尺寸异常,致使 cv2.copyMakeBorder 无法正确应用。更严重的是,原始代码中 VideoWriter 初始化时仍使用原始帧尺寸 (frame_width, frame_height),未适配加边框后的新分辨率,造成写入失败或画面裁剪。

本教程采用更鲁棒、更符合生产逻辑的架构:服务端直连摄像头持续采集 → 实时预处理(如镜像)→ 流式传输至前端预览 → 同步后处理(逐帧加边框并写入文件)。整个流程避免了浏览器端视频编码/解码的不可控因素,确保边框精准、稳定地叠加在每一帧上。

✅ 核心改进点

  • 边框在录制过程中实时添加:不再依赖后期转码,杜绝因视频容器格式(如 H.264 vs MJPEG)引发的读取失败;
  • VideoWriter 分辨率严格匹配加边框后尺寸:out = cv2.VideoWriter(..., (w + 2×t, h + 2×t)),其中 t 为边框厚度;
  • 协程解耦预/后处理逻辑:video_writer 协程专注“接收帧 → 加边框 → 写磁盘”,主流函数专注“捕获 → 预处理 → 流式响应”,职责清晰、可扩展性强;
  • 零前端 JavaScript 视频处理负担:所有图像操作均在服务端完成,兼容性高,调试简单。

? 完整可运行代码(app.py)

import time
from flask import Flask, render_template_string, Response
import cv2

def coroutine(func):
    def start(*args, **kwargs):
        cr = func(*args, **kwargs)
        next(cr)
        return cr
    return start

@coroutine
def video_writer(dst_video, frame_width, frame_height):
    border_thickness = 20
    border_color = (0, 0, 255)  # BGR order for OpenCV

    # ✅ 关键:输出尺寸 = 原始尺寸 + 双侧边框
    out = cv2.VideoWriter(
        dst_video,
        cv2.VideoWriter_fourcc(*'MJPG'),
        10,
        (frame_width + 2 * border_thickness, frame_height + 2 * border_thickness)
    )

    try:
        while True:
            frame = (yield)
            # ✅ 实时加边框(BORDER_CONSTANT + RGB→BGR 转换已隐含)
            bordered_frame = cv2.copyMakeBorder(
                frame,
                top=border_thickness,
                bottom=border_thickness,
                left=border_thickness,
                right=border_thickness,
                borderType=cv2.BORDER_CONSTANT,
                value=border_color
            )
            out.write(bordered_frame)
    except GeneratorExit:
        pass
    finally:
        out.release()

def stream_main(target, path_video):
    cap = cv2.VideoCapture(0)
    if not cap.isOpened():
        raise RuntimeError("Failed to open camera")

    frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))

    # 初始化协程(传入视频路径和尺寸)
    writer = target(path_video, frame_width, frame_height)

    def gen_frame_content(img_bytes):
        return b''.join([
            b'--frame\r\nContent-Type: image/jpeg\r\n\r\n',
            img_bytes,
            b'\r\n'
        ])

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

        # ✅ 后处理:写入带边框视频(同步)
        writer.send(frame)

        # ✅ 预处理:供前端显示(如水平翻转,提升用户体验)
        display_frame = cv2.flip(frame, 1)

        # 编码为 JPEG 并流式返回
        success, buffer = cv2.imencode('.jpg', display_frame)
        if not success:
            continue

        yield gen_frame_content(buffer.tobytes())
        time.sleep(0.04)  # 控制约 25 FPS

    cap.release()
    writer.close()

# —— 路由配置 ——
app = Flask(__name__)
OUTPUT_VIDEO_PATH = 'recorded_with_border.avi'  # 推荐 .avi + MJPEG,兼容性优于 MP4

@app.route('/')
def index():
    return render_template_string('''
        <h2>? Live Recording with Red Border</h2>
        <p>Camera starts automatically. To stop recording, close this tab or reload.</p><div class="aritcle_card flexRow artxards">
											<div class="artcardd flexRow">
												<a class="aritcle_card_img" rel="nofollow" href="/ai/3838" title="ljg-skills"><img
														src="https://img.php.cn/upload/ai_manual/001/246/273/178599577233497.png" alt="ljg-skills" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
												<div class="aritcle_card_info flexColumn">
													<a rel="nofollow" href="/ai/3838" title="ljg-skills" class="overflowclass">ljg-skills</a>
													<p class="overflowclass">ljg-skills是一款AI提示词工具,'Prompt之神'李继刚开源的 AI 技能集。</p>
												</div>
												<a rel="nofollow" href="/ai/3838" title="ljg-skills" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
												</a>
											</div>
										</div>
        @@##@@
    ''')

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

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

⚠️ 注意事项与最佳实践

  • 视频格式选择:推荐使用 .avi + MJPG 编码(如示例),因其帧内压缩、无跨帧依赖,cv2.VideoWriter 兼容性远高于 H.264 MP4。若需 MP4,须改用 cv2.VideoWriter_fourcc(*'avc1') 并确保系统安装 ffmpeg 支持;
  • 边框颜色注意:OpenCV 使用 BGR 顺序,(0, 0, 255) 表示红色(非 RGB),无需额外转换;
  • 性能提示:边框厚度、分辨率、帧率需权衡。border_thickness=20 在 640×480 下效果明显;若 CPU 较弱,可降低 time.sleep() 或 VideoWriter FPS;
  • 停止机制:当前方案通过页面关闭/刷新终止录制(GeneratorExit 捕获)。如需显式“停止按钮”,可在 Flask 中增加 /stop_recording 路由,通过全局状态控制 cap 和 writer 生命周期;
  • 生产部署:务必添加异常处理(如磁盘满、权限拒绝)、视频路径安全校验(防路径遍历),并考虑使用 threading.Lock 保护共享资源。

✅ 验证效果

启动服务后访问 http://localhost:5000/,摄像头自动开启,画面实时显示(已镜像)。同时,recorded_with_border.avi 在后台持续写入——打开该文件,将看到每帧四周均有 20 像素宽的纯红色边框,且无黑边、拉伸或闪烁。

此方案将视频处理逻辑完全收口于服务端,规避了浏览器编码差异与前后端数据传递损耗,是构建可靠视频标注、教学录制、安防预览等系统的坚实基础。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

flask使用教程

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
html版权符号
html版权符号

html版权符号是“©”,可以在html源文件中直接输入或者从word中复制粘贴过来,php中文网还为大家带来html的相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

2023.06.14

6015

7

html在线编辑器
html在线编辑器

html在线编辑器是用于在线编辑的工具,编辑的内容是基于HTML的文档。它经常被应用于留言板留言、论坛发贴、Blog编写日志或等需要用户输入普通HTML的地方,是Web应用的常用模块之一。php中文网为大家带来了html在线编辑器的相关教程、以及相关文章等内容,供大家免费下载使用。

2023.06.21

3392

4

html网页制作
html网页制作

html网页制作是指使用超文本标记语言来设计和创建网页的过程,html是一种标记语言,它使用标记来描述文档结构和语义,并定义了网页中的各种元素和内容的呈现方式。本专题为大家提供html网页制作的相关的文章、下载、课程内容,供大家免费下载体验。

2023.07.31

3070

5

html空格
html空格

html空格是一种用于在网页中添加间隔和对齐文本的特殊字符,被用于在网页中插入额外的空间,以改变元素之间的排列和对齐方式。本专题为大家提供html空格的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.01

3079

5

html是什么
html是什么

HTML是一种标准标记语言,用于创建和呈现网页的结构和内容,是互联网发展的基石,为网页开发提供了丰富的功能和灵活性。本专题为大家提供html相关的各种文章、以及下载和课程。

2023.08.11

4859

6

html字体大小怎么设置
html字体大小怎么设置

在网页设计中,字体大小的选择是至关重要的。合理的字体大小不仅可以提升网页的可读性,还能够影响用户对网页整体布局的感知。php中文网将介绍一些常用的方法和技巧,帮助您在HTML中设置合适的字体大小。

2023.08.11

3021

3

html转txt
html转txt

html转txt的方法有使用文本编辑器、使用在线转换工具和使用Python编程。本专题为大家提供html转txt相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.31

2829

3

html文本框代码怎么写
html文本框代码怎么写

html文本框代码:1、单行文本框【<input type="text" style="height:..;width:..;" />】;2、多行文本框【textarea style=";height:;"></textare】。

2023.09.01

2508

6

HTML嵌入CSS样式的方法
HTML嵌入CSS样式的方法

HTML嵌入CSS样式的方法有内联样式、内部样式表和外部样式表。本专题为大家提供CSS样式相关的文章、下载、课程内容,供大家免费下载体验。

2023.09.20

2568

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.6万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133.4万人学习