pycharm + anaconda + yolo11(ultralytics) 的视频流实时检测,保存推流简单实现

news2025/3/15 10:58:12

目录

  • 背景
  • pycharm安装配置
  • 代码实现
    • 创建本地视频配置 和 推流配置
    • 视频帧的处理和检测框绘制
    • 主要流程
    • 遇到的一些问题

背景

首先这个基于完整安装配置了anaconda和yolo11的环境,如果需要配置开始的话,先看下专栏里另一个文章。
这次的目的是实现拉取视频流,做检测并绘制对象检测框。之后,将结果保存本地视频,并且推流到对应的rtmp服务器,便于调试也可以实时显示处理结果视频。

pycharm安装配置

安装就不提了吧,到官网下载个免费的社区版本就ok了,安装也基本不会有啥问题。
安装完成后,打开你的本地ultralytics文件夹作为项目,然后在设置里加一下解释器:
在这里插入图片描述
记得选对你的anaconda配置的环境,右边的列表能看到你环境中安装的库。

代码实现

创建本地视频配置 和 推流配置

依据传入的opencv捕获的视频流对象,获取本地保存视频的一些参数,创建video_writer,并记录推流参数。

def create_video_writer(cap_video, path_output):
    # 获取视频流参数
    width = int(cap_video.get(cv2.CAP_PROP_FRAME_WIDTH))
    height = int(cap_video.get(cv2.CAP_PROP_FRAME_HEIGHT))
    fps = int(cap_video.get(cv2.CAP_PROP_FPS))
    # 初始化本地视频保存
    fourcc = cv2.VideoWriter.fourcc(*'mp4v')
    out_writer = cv2.VideoWriter(path_output, fourcc, fps, (width, height))
    # 推流的参数配置
    command = [
    'ffmpeg',
    '-y',                    # 覆盖输出文件(如果存在)
    '-f', 'rawvideo',        # 输入格式
    '-pix_fmt', 'bgr24',     # OpenCV 的像素格式
    '-s', f'{width}x{height}', # 分辨率
    '-r', str(fps),          # 帧率
    '-i', '-',               # 从标准输入读取
    '-c:v', 'libx264',       # 输出视频编码
    '-preset', 'ultrafast',       # 编码速度预设
    '-f', 'flv',             # 输出格式(RTMP 需要 flv)
    RTMP_SERVER_URL
    ]

    print("视频参数:fps " + str(fps))
    return out_writer, command

视频帧的处理和检测框绘制

依据传入的模型对象和视频帧,去绘制检测框和文本,之后返回结果的图像以及结果数据。

def process_frame(model_in, frame_in):
 results = model_in.predict(frame_in)
 # 绘制检测框
 for result in results:
     for box in result.boxes:
         x1, y1, x2, y2 = map(int, box.xyxy[0])
         conf = box.conf[0].item()
         cls_id = int(box.cls[0])
         label = f"{model_in.names[cls_id]} {conf:.2f}"
         print(label)
         # 绘制矩形和标签
         draw_rounded_rect(frame_in, (x1, y1), (x2, y2), (0, 255, 0), 2,
                           cv2.LINE_AA, 10)  # 红色圆角矩形
         cv2.putText(frame_in, label, (x1, y1 - 10),
                     cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
         return frame_in, results

draw_rounded_rect 单纯为了绘制个圆角框,可以简单的用cv2.rectangle(frame_in, (x1, y1), (x2, y2), (0, 255, 0), 2, cv2.LINE_AA)画。

def draw_rounded_rect(img, pt1, pt2, color, thickness, line_type, corner_radius):
    x1, y1 = pt1
    x2, y2 = pt2
    # 绘制四个角的圆弧
    cv2.ellipse(img, (x1 + corner_radius, y1 + corner_radius), (corner_radius, corner_radius), 180, 0, 90, color, thickness, line_type)
    cv2.ellipse(img, (x2 - corner_radius, y1 + corner_radius), (corner_radius, corner_radius), 270, 0, 90, color, thickness, line_type)
    cv2.ellipse(img, (x1 + corner_radius, y2 - corner_radius), (corner_radius, corner_radius), 90, 0, 90, color, thickness, line_type)
    cv2.ellipse(img, (x2 - corner_radius, y2 - corner_radius), (corner_radius, corner_radius), 0, 0, 90, color, thickness, line_type)
    # 绘制四条边
    cv2.line(img, (x1 + corner_radius, y1), (x2 - corner_radius, y1), color, thickness, line_type)
    cv2.line(img, (x1, y1 + corner_radius), (x1, y2 - corner_radius), color, thickness, line_type)
    cv2.line(img, (x1 + corner_radius, y2), (x2 - corner_radius, y2), color, thickness, line_type)
    cv2.line(img, (x2, y1 + corner_radius), (x2, y2 - corner_radius), color, thickness, line_type)

主要流程

流程主要就是加载模型,捕获对应的rtmp视频流,跑循环一帧帧解析数据,之后把帧的绘制结果写入本地的视频文件,同时帧结果也通过ffmpeg库推到对应的RTMP server去播放。最后终端清除资源。

# 加载模型
model = YOLO(MODEL_PATH)
# 初始化视频流
cap = cv2.VideoCapture(RTSP_URL)
if not cap.isOpened():
    raise ValueError("无法打开视频流!")
print("视频流已连接...")
out_writer, ffmpeg_command = create_video_writer(cap, OUTPUT_VIDEO_PATH)
if ENABLE_FEATURE_STREAM:
    # 启动 FFmpeg 进程
    ffmpeg_proc = subprocess.Popen(ffmpeg_command, stdin=subprocess.PIPE, stderr=subprocess.PIPE)
if ENABLE_FEATURE_DISPLAY:
    cv2.namedWindow("DISPLAY", cv2.WINDOW_NORMAL)
print("本地视频写入配置完成...")
try:
    while True:
        ret, frame = cap.read()
        if not ret:
            print("视频流中断,尝试重连...")
            cap.release()
            cap = cv2.VideoCapture(RTSP_URL)
            time.sleep(1)
            continue
        # 处理单帧画面
        out_frame, _ = process_frame(model, frame)
        if ENABLE_FEATURE_DISPLAY:
            frame_small = cv2.resize(out_frame, (1080, 900))
            cv2.waitKey(1)
            cv2.imshow("DISPLAY", frame_small)
        if ENABLE_FEATURE_STREAM:
            # 推流到服务器
            if ffmpeg_proc.stdin:
                ffmpeg_proc.stdin.write(out_frame.tobytes())
        # 保存到本地
        out_writer.write(out_frame)
except KeyboardInterrupt:
    print("用户中断操作")
finally:
    # 清理资源
    cap.release()
    out_writer.release()
    if ENABLE_FEATURE_STREAM:
        if ffmpeg_proc.stdin:
            ffmpeg_proc.stdin.close()
            ffmpeg_proc.terminate()
        print("等待进程退出")
        ffmpeg_proc.wait()
    print("资源已释放")

然后前面的import,就是缺什么装什么,直接在conda环境里pip装就好了。

from ultralytics import YOLO
import cv2
import time
import subprocess
import numpy as np

# 参数
ENABLE_FEATURE_STREAM = True
ENABLE_FEATURE_DISPLAY = True
RTSP_URL = "rtmp://xxxxx"  # RTSP 或 HTTP 流地址
OUTPUT_VIDEO_PATH = "YOLO11OutPut.mp4"  # 本地保存路径
RTMP_SERVER_URL = "rtmp://xxxxxx"  # 推流服务器地址
MODEL_PATH = "yolo11n.pt"

效果就是跑起来前端会有实时视频,并且本地会有mp4保存,远端服务器也能实时看到视频。
在这里插入图片描述
至于什么效果啥的就是后续自己调整的事情了。

遇到的一些问题

  • 第一个是图里后续加了中文标签,默认opencv字体不支持绘制中文会是?问号。
    有两个方法一个是去改yolo的绘制代码,比较麻烦,我最后用的是转PIL绘制,当然需要下字体文件SimHei.ttf丢在目录下。标签的可以在项目内的ultralytics/ultralytics/blob/main/ultralytics/cfg/datasets/coco.yaml找到识别的标签集合,自己简单补个对应中文标签组。至于代码不难,就参考着自己调整吧:
from PIL import Image, ImageDraw, ImageFont
cn_names = {
    0: "人", 1: "自行车", 2: "汽车", 3: '摩托车', 4: '飞机', 5: '大巴', 6: '火车', 7: '卡车', 8: '船', 9: '信号灯'
}
font_path = "SimHei.ttf"
font_size = 20
font = ImageFont.truetype(font_path, font_size)
def put_text_cn(img, text, pos, color, font):
    # 转换 OpenCV 图像为 PIL 格式
    img_pil = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
    draw = ImageDraw.Draw(img_pil)
    # 计算文本尺寸并绘制背景框
    bbox = draw.textbbox((0, 0), text, font=font)
    text_width = bbox[2] - bbox[0]  # 宽度 = 右边界 - 左边界
    text_height = bbox[3] - bbox[1]  # 高度 = 下边界 - 上边界
    x, y = pos
    bg_pos = (x, y - text_height-5, x + text_width, y)
    # draw.rectangle(bg_pos, fill=color)
    # 绘制文本
    draw.text((bg_pos[0], bg_pos[1]), text, font=font, fill=(255, 255, 255))  # 白色文字
    # 转换回 OpenCV 格式
    return cv2.cvtColor(np.array(img_pil), cv2.COLOR_RGB2BGR)
  • 第二个是一开始跑yolo的时候遇到过报“NotImplementedError: Could not run 'torchvision::nms“错误。查了下是已安装库版本的问题,参考https://stackoverflow.com/questions/75103127/getting-notimplementederror-could-not-run-torchvisionnms-with-arguments-fr
    uninstall对应的torch库然后重新安装官网链接安装一次试试~
  • 还有就是如果下载模型异常,也是跑不起来的,网络实在不行可以考虑直接去yolo的文档里找预训练的模型链接,把模型下下来丢项目根目录先:
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2315405.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Netty基础—5.Netty的使用简介

大纲 1.Netty服务端的启动流程 2.服务端IO事件的处理类 3.Netty客户端的启动流程 4.客户端IO事件的处理类 5.启动Netty服务端和客户端的方法说明 6.Netty服务端和客户端使用总结 7.什么是TCP粘包拆包 8.TCP粘包拆包的几种情况 9.TCP粘包拆包的原因 10.粘包问题的解决…

C++初阶——类和对象(一)

C初阶——类和对象(一) 一、面向过程和面向对象 1.面向过程 面向过程的程序设计(Procedure-Oriented Programming),简称POP,是一种是以程序执行流程为核心的编程范式。它是先分析出解决问题所需要的的步…

RabbitMQ入门:从安装到高级消息模式

文章目录 一. RabbitMQ概述1.1 同步/异步1.1.1 同步调用1.1.2 异步调用 1.2 消息中间件1.2.1 概念1.2.2 作用1.2.3 常见的消息中间件1.2.4 其他中间件 1.3 RabbitMQ1.3.1 简介1.3.2 特点1.3.3 方式1.3.4 架构1.3.5 运行流程 二. 安装2.1 Docker 安装 RabbitMQ 三. 简单队列&…

Linux应用:进程的回收

进程的诞生和消亡 程的诞生通常是通过系统调用(如fork、exec等)来创建新进程。当一个进程完成其任务或者出现错误时,它会进入消亡阶段。进程可以通过exit函数主动结束自身,也可能由于操作系统的调度策略(如资源耗尽、…

如何利用 AI 技术快速定位和修复生产环境问题

网罗开发 (小红书、快手、视频号同名) 大家好,我是 展菲,目前在上市企业从事人工智能项目研发管理工作,平时热衷于分享各种编程领域的软硬技能知识以及前沿技术,包括iOS、前端、Harmony OS、Java、Python等…

(链表)206. 反转链表

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。 示例 1: 输入:head [1,2,3,4,5] 输出:[5,4,3,2,1]示例 2: 输入:head [1,2] 输出:[2,1]示例 3: 输入&am…

农业建设项目管理系统评测:8款推荐工具优缺点分析

本文主要介绍了以下8款农业建设项目管理系统:1.PingCode; 2. Worktile ;3. 建米农业工程项目管理系统;4. 开创云数字农业管理平台; 5. Trimble Ag Software;6.Conservis; 7. Agworld &#xff1…

linux 命令 tail

tail 是 Linux 中用于查看文件末尾内容的命令&#xff0c;常用于日志监控和大文件快速浏览。以下是其核心用法及常见选项&#xff1a; 基本语法 tail [选项] 文件名 常用选项 显示末尾行数 -n <行数> 或 --lines<行数> 指定显示文件的最后若干行&#xff08;…

实验8 搜索技术

实验8 搜索技术 一、实验目的 &#xff08;1&#xff09;掌握搜索技术的相关理论&#xff0c;能根据实际情况选取合适的搜索方法&#xff1b; &#xff08;2&#xff09;进一步熟悉盲目搜索技术&#xff0c;掌握其在搜索过程中的优缺点&#xff1b; &#xff08;3&#xff09;…

VSTO(C#)Excel开发9:处理格式和字体

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 源码指引&#xff1a;github源…

LinkedList底层结构和源码分析(JDK1.8)

参考视频&#xff1a;韩顺平Java集合 特点 LinkedList 底层实现了 双向链表 和 双端队列 的特点。可以添加任意元素&#xff08;元素可以重复&#xff09;&#xff0c;包括 null。线程不安全&#xff0c;没有实现同步。 LinkedList 底层结构 LinkedList 底层维护了一个双向链…

数字内容体验的技术支柱是什么?

数据分析引擎构建基础 数字内容体验的技术底座始于对海量用户行为数据的深度解析。作为技术体系的根基&#xff0c;数据分析引擎通过实时采集、清洗与结构化处理&#xff0c;将分散的点击轨迹、停留时长及交互偏好转化为可操作的洞察。其核心能力体现在三方面&#xff1a;一是…

C# 使用Markdown2Pdf把md文件转换为pdf文件

NuGet安装Markdown2Pdf库&#xff0c;可以把格式简单markdown文件转换为pdf。但该库用了Puppeteer Sharp&#xff0c;因此会在运行过程中提示指定Chrome浏览器路径或自动下载Chrome浏览器。 代码如下&#xff1a; using Markdown2Pdf;var converter new Markdown2PdfConverte…

专家系统如何运用谓词逻辑进行更复杂的推理

前文&#xff0c;我们讲解了命题逻辑和谓词逻辑的基本概念、推理规则、应用以及一些简单的示例。具体内容可以先看我的文章&#xff1a;人工智能的数学基础之命题逻辑与谓词逻辑&#xff08;含示例&#xff09;-CSDN博客 那么形如专家系统这类复杂系统&#xff0c;是如何通过谓…

html css网页制作成品——糖果屋网页设计(4页)附源码

目录 一、&#x1f468;‍&#x1f393;网站题目 二、✍️网站描述 三、&#x1f4da;网站介绍 四、&#x1f310;网站效果 五、&#x1fa93; 代码实现 &#x1f9f1;HTML 六、&#x1f947; 如何让学习不再盲目 七、&#x1f381;更多干货 一、&#x1f468;‍&#x1f…

落雪音乐Pro 8.8.6 | 内置8条音源,无需手动导入,纯净无广告

洛雪音乐Pro版内置多组稳定音源接口&#xff0c;省去手动导入的繁琐操作&#xff0c;安装即可畅听海量音乐。延续原版无广告的纯净体验&#xff0c;支持歌单推荐与音源切换&#xff0c;满足个性化听歌需求。此版本仅支持在线播放&#xff0c;无法下载音乐&#xff0c;且与原版不…

什么是全栈?

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点下班 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 &#x1f4c3;文章前言 &#x1f537;文章均为学习工…

XML文件格式的简介及如何用Python3处理XML格式对象

诸神缄默不语-个人技术博文与视频目录 文章目录 1. XML格式简介2. 格式化XML文件的工具3. Python处理XML&#xff1a;xml库1. xml.etree.\(c\)ElementTree2. xml.dom.minidom 4. 本文撰写过程中参考的其他网络资料 1. XML格式简介 可扩展标记语言 (Extensible Markup Language…

通过qemu仿真树莓派系统调试IoT固件和程序

通过qemu仿真树莓派系统调试IoT固件和程序 本文将介绍如何使用 QEMU 模拟器在 x86 架构的主机上运行 Raspberry Pi OS&#xff08;树莓派操作系统&#xff09;。我们将从下载镜像、提取内核和设备树文件&#xff0c;到启动模拟环境&#xff0c;并进行一些常见的操作&#xff0…

Oracle底层原理解析

Oracle 解析 1、union \ union all \ Intersect \ Minus内部处理机制&#xff08;优化&#xff09; 当查询语句中的where子句中使用到or时&#xff0c;可以用union all来代替。因为使用or查询语句的时候&#xff0c;引起全表扫描&#xff0c;并走索引查询 特别&#xff1a;当…