Gradio全解20------Streaming:流式传输的多媒体应用(6)------RT-DETR模型构建视频流目标检测系统
- 本篇摘要
- [20. Streaming:流式传输的多媒体应用](#20. Streaming:流式传输的多媒体应用)
-
- [20.6 RT-DETR模型构建视频流目标检测系统](#20.6 RT-DETR模型构建视频流目标检测系统)
-
- [20.6.1 RT-DETR模型](#20.6.1 RT-DETR模型)
-
- [1. 模型介绍](#1. 模型介绍)
- [2. 使用示例](#2. 使用示例)
- [20.6.2 系统配置](#20.6.2 系统配置)
- [20.6.3 推理函数实现](#20.6.3 推理函数实现)
-
- [1. 视频读取与处理](#1. 视频读取与处理)
- [2. 推理循环实现](#2. 推理循环实现)
- [20.6.4 Gradio演示界面实现](#20.6.4 Gradio演示界面实现)
- 参考文献:
本章目录如下:
- 《Gradio全解20------Streaming:流式传输的多媒体应用(1)------Mistral-7B实现流式传输音频:魔力8号球》;
- 《Gradio全解20------Streaming:流式传输的多媒体应用(2)------基于Mini-Omni模型构建对话式聊天机器人》;
- 《Gradio全解20------Streaming:流式传输的多媒体应用(3)------实时语音识别技术(ASR)》;
- 《Gradio全解20------Streaming:流式传输的多媒体应用(4)------基于Groq的带自动语音检测功能的多模态Gradio应用》;
- 《Gradio全解20------Streaming:流式传输的多媒体应用(5)------基于YOLO与WebRTC的摄像头实时目标检测》;
- 《Gradio全解20------Streaming:流式传输的多媒体应用(6)------RT-DETR模型构建视频流目标检测系统》。
本篇摘要
本章讲述流式传输的应用,包括音频、图像和视频格式的流式传输。
20. Streaming:流式传输的多媒体应用
本章讲述流式传输的应用,包括音频、图像和视频格式的流式传输。音频应用包括流式传输音频、构建音频对话式聊天机器人、实时语音识别技术和自动语音检测功能;图像应用包括基于WebRTC的摄像头实时目标检测;视频应用包括构建视频流目标检测系统。
20.6 RT-DETR模型构建视频流目标检测系统
本指南将使用RT-DETR模型对用户上传视频进行实时目标检测,并借助Gradio 5.0全新视频流功能实现检测结果的实时传输。在开始之前,先了解下RT-DETR模型。
20.6.1 RT-DETR模型
RT-DETR(Real-Time DEtection TRansformer)模型在论文《DETRs Beat YOLOs on Real-time Object Detection》中提出,它是一种专注于实现实时性能同时保持高精度的目标检测模型。该模型基于Transformer架构(该架构在深度学习多个领域已展现出显著优势),通过对图像进行处理来识别并定位其中的多个目标。
1. 模型介绍
近年来,基于Transformer的端到端检测器(DETRs)已取得显著性能突破。然而,DETRs计算成本高的问题尚未得到有效解决,这限制了其实际应用,也阻碍了其充分发挥无需后处理的优势,如非极大值抑制NMS(non-maximum suppression)。论文《DETRs Beat YOLOs on Real-time Object Detection》首先分析了现代实时目标检测器中NMS对推理速度的影响,并建立了端到端速度基准。为避免NMS导致的推理延迟,论文提出了首个实时端到端目标检测器RT-DETR。
具体而言,RT-DETR模型在以下方面实现了突破:
- 设计了高效混合编码器,通过解耦尺度内交互与跨尺度融合来高效处理多尺度特征;
- 提出IoU感知查询选择机制,以优化目标查询的初始化;
- 提出的检测器支持通过灵活调整解码器层数(无需重新训练)来调节推理速度,提升了实时检测器的实用性。
实验表明:
- RT-DETR-L在COCO val2017上达到53.0% AP(Average Precision),T4 GPU上实现114 FPS(Frame Per Second);RT-DETR-X达到54.8% AP与74 FPS。同规模下,两项指标均超越所有YOLO检测器;
- 此外,RT-DETR-R50以53.1% AP和108 FPS的表现,在精度上超越DINO-Deformable-DETR-R50达2.2% AP,速度提升约21倍。对比图如下:
RT-DETR系列的最新版本是RT-DETRv2模型,它在论文《RT-DETRv2: Improved Baseline with Bag-of-Freebies for Real-Time Detection Transformer 》中提出。RT-DETRv2通过以下改进优化了RT-DETR:引入可选择的多尺度特征提取,采用离散采样算子提升部署兼容性及改进训练策略(包括动态数据增强和尺度自适应超参数)。这些改进在保持实时性能的同时,显著增强了模型的灵活性和实用性。
2. 使用示例
RT-DETR系统首先采用预训练的卷积神经网络(基于原始代码中的ResNet-D改进架构)对输入图像进行处理,该网络会从模型最后三个层级提取多层次特征图。随后,通过混合编码器架构,将提取到的多尺度特征转换为序列化的图像特征表示,这种设计能有效保留不同尺度的空间信息。接着,使用配备了辅助预测头的解码器迭代优化目标查询,该过程可直接生成边界框,无需额外后续处理即可获取边界框的分类置信度(logits)和坐标。示例代码如下:
python
import torch
import requests
from PIL import Image
from transformers import RTDetrForObjectDetection, RTDetrImageProcessor
url = 'http://images.cocodataset.org/val2017/000000039769.jpg'
image = Image.open(requests.get(url, stream=True).raw)
# RT-DETR
image_processor = RTDetrImageProcessor.from_pretrained("PekingU/rtdetr_r50vd")
model = RTDetrForObjectDetection.from_pretrained("PekingU/rtdetr_r50vd")
# RT-DETRv2
# image_processor = RTDetrImageProcessor.from_pretrained("PekingU/rtdetr_v2_r18vd")
# model = RTDetrV2ForObjectDetection.from_pretrained("PekingU/rtdetr_v2_r18vd")
inputs = image_processor(images=image, return_tensors="pt")
with torch.no_grad():
outputs = model(**inputs)
results = image_processor.post_process_object_detection(outputs, target_sizes=torch.tensor([(image.height, image.width)]), threshold=0.3)
for result in results:
for score, label_id, box in zip(result["scores"], result["labels"], result["boxes"]):
score, label = score.item(), label_id.item()
box = [round(i, 2) for i in box.tolist()]
print(f"{model.config.id2label[label]}: {score:.2f} {box}")
输出如下:
bash
sofa: 0.97 [0.14, 0.38, 640.13, 476.21]
cat: 0.96 [343.38, 24.28, 640.14, 371.5]
cat: 0.96 [13.23, 54.18, 318.98, 472.22]
remote: 0.95 [40.11, 73.44, 175.96, 118.48]
remote: 0.92 [333.73, 76.58, 369.97, 186.99]
以下是由Hugging Face官方及社区提供的资源列表,可以帮助我们快速入门RT-DETR:
- 使用Trainer或Accelerate微调RTDetrForObjectDetection的脚本可在此处获取: huggingface/transformers/examples/pytorch/object-detection;
- 另请参阅目标检测任务指南:Object detection;
- 关于RT-DETR在自定义数据集上进行推理和微调的Notebook可在此处查看: NielsRogge/Transformers-Tutorials/RT-DETR/RT-DETR notebooks。
更多成员函数及其它详细信息请参阅: Transformers - RT-DETR及RT-DETRv2。
20.6.2 系统配置
系统配置分为环境准备、模型获取及硬件加速三部分,如下:
- 环境准备:首先需安装以下系统依赖:
bash
opencv-python
torch
transformers>=4.43.0
spaces
- 模型获取:从Hugging Face Hub下载预训练模型:
python
from transformers import RTDetrForObjectDetection, RTDetrImageProcessor
image_processor = RTDetrImageProcessor.from_pretrained("PekingU/rtdetr_r50vd")
model = RTDetrForObjectDetection.from_pretrained("PekingU/rtdetr_r50vd").to("cuda")
- 硬件加速:将模型通过代码**to("cuda")**加载至GPU显存以加速推理。本系统将部署在Hugging Face Spaces平台,利用其免费的ZeroGPU集群资源运行推理任务。
20.6.3 推理函数实现
我们的推理函数首先接收一个视频和用户设定的置信度阈值,目标检测模型会识别视频中多个对象并为每个对象分配置信度分数;置信度越低,出现误检的可能性就越高,因此允许用户根据需求自行设置这个置信度阈值。然后,该函数将遍历视频中的每一帧,并对每帧运行RT-DETR模型;我们会为帧中每个检测到的对象绘制边界框,并将帧保存到新的输出视频中,函数将以两秒为片段逐步生成输出视频。
由于存在基于时间的配额限制,所以需要在ZeroGPU上尽可能降低推理时间。我们可以在运行模型前将输出视频的原始帧率减半,并将输入帧的尺寸缩小为原尺寸的一半来降低推理时间。以下是完整的推理函数代码:
python
import spaces
import cv2
from PIL import Image
import torch
import time
import numpy as np
import uuid
from draw_boxes import draw_bounding_boxes
SUBSAMPLE = 2
@spaces.GPU
def stream_object_detection(video, conf_threshold):
cap = cv2.VideoCapture(video)
fps = int(cap.get(cv2.CAP_PROP_FPS))
desired_fps = fps // SUBSAMPLE
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) // 2
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) // 2
# Use UUID to create a unique video file
output_video_name = f"output_{uuid.uuid4()}.mp4"
# This means we will output mp4 videos
video_codec = cv2.VideoWriter_fourcc(*"mp4v") # type: ignore # Output Video
output_video = cv2.VideoWriter(output_video_name, video_codec, desired_fps, (width, height)) # type: ignore
iterating, frame = cap.read()
n_frames = 0
batch = []
while iterating:
frame = cv2.resize( frame, (0,0), fx=0.5, fy=0.5)
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
if n_frames % SUBSAMPLE == 0:
batch.append(frame)
if len(batch) == 2 * desired_fps:
inputs = image_processor(images=batch, return_tensors="pt").to("cuda")
with torch.no_grad():
outputs = model(**inputs)
boxes = image_processor.post_process_object_detection(
outputs,
target_sizes=torch.tensor([(height, width)] * len(batch)),
threshold=conf_threshold)
for i, (array, box) in enumerate(zip(batch, boxes)):
pil_image = draw_bounding_boxes(Image.fromarray(array), box, model, conf_threshold)
frame = np.array(pil_image)
# Convert RGB to BGR
frame = frame[:, :, ::-1].copy()
output_video.write(frame)
batch = []
output_video.release()
yield output_video_name
output_video_name = f"output_{uuid.uuid4()}.mp4"
output_video = cv2.VideoWriter(output_video_name, video_codec, desired_fps, (width, height)) # type: ignore
iterating, frame = cap.read()
n_frames += 1
下面逐段解析代码。
1. 视频读取与处理
本应用将使用OpenCV处理视频,因为它是Python中处理视频的行业标准。通过OpenCV的VideoCapture型变量cap读取输入视频,每次调用cap.read()都会获取视频的下一帧。
为了实现Gradio视频流传输,我们需要为每个输出视频"块(chunk)"生成不同的视频文件,这里使用output_video = cv2.VideoWriter(output_video_name, video_codec, desired_fps, (width, height))创建要写入的下一个视频文件。其中video_codec用于指定视频文件类型,目前仅支持"mp4"和"ts"格式的视频流传输。
2. 推理循环实现
对于视频中的每一帧,我们都会将其尺寸缩小一半。由于OpenCV以BGR格式读取文件,需要先转换为transformer预期的RGB格式,这正是while循环前两行代码所实现的功能。
我们每隔一帧采集一次,并将帧添加至批处理列表,从而使输出视频的帧率减半。当批处理视频内容累计达到两秒时,就会运行模型推理。选择两秒阈值是为了确保每批处理时间足够短,既能实现服务器上的视频流畅显示,又不需要进行过多独立的前向传播。同时需要注意的是,为了使Gradio视频流正常工作,批处理时长至少需要1秒。
运行模型的前向传播后,我们使用模型的post_process_object_detection方法将检测到的边界框缩放到输入帧的原始尺寸。通过自定义函数绘制边界框,之后需要将RGB格式转换回BGR格式才能写回输出视频。完成当前批处理后,我们会为下一批处理创建新的输出视频文件。其中绘制边界框函数draw_bounding_boxes源码如下:
python
from PIL import ImageDraw, ImageFont # type: ignore
import colorsys
def get_color(label):
# Simple hash function to generate consistent colors for each label
hash_value = hash(label)
hue = (hash_value % 100) / 100.0
saturation = 0.7
value = 0.9
rgb = colorsys.hsv_to_rgb(hue, saturation, value)
return tuple(int(x * 255) for x in rgb)
def draw_bounding_boxes(image, results: dict, model, threshold=0.3):
draw = ImageDraw.Draw(image)
font = ImageFont.load_default()
for score, label_id, box in zip(
results["scores"], results["labels"], results["boxes"]
):
if score > threshold:
label = model.config.id2label[label_id.item()]
box = [round(i, 2) for i in box.tolist()]
color = get_color(label)
# Draw bounding box
draw.rectangle(box, outline=color, width=3) # type: ignore
# Prepare text
text = f"{label}: {score:.2f}"
text_bbox = draw.textbbox((0, 0), text, font=font)
text_width = text_bbox[2] - text_bbox[0]
text_height = text_bbox[3] - text_bbox[1]
# Draw text background
draw.rectangle(
[box[0], box[1] - text_height - 4, box[0] + text_width, box[1]], # type: ignore
fill=color, # type: ignore
)
# Draw text
draw.text((box[0], box[1] - text_height - 4), text, fill="white", font=font)
return image
20.6.4 Gradio演示界面实现
该UI代码与标准Gradio应用基本一致,我们将采用经典的双栏布局,使用户可以并排查看输入和输出视频。要实现流式传输功能,必须在输出视频组件中设置streaming=True参数,另外参数autoplay虽然并非必需配置,但启用该选项可显著提升用户观感。
python
import gradio as gr
with gr.Blocks() as app:
gr.HTML(
"""
<h1 style='text-align: center'>
Video Object Detection with <a href='https://huggingface.co/PekingU/rtdetr_r101vd_coco_o365' target='_blank'>RT-DETR</a>
</h1>
""")
with gr.Row():
with gr.Column():
video = gr.Video(label="Video Source")
conf_threshold = gr.Slider(
label="Confidence Threshold",
minimum=0.0,
maximum=1.0,
step=0.05,
value=0.30,
)
with gr.Column():
output_video = gr.Video(label="Processed Video", streaming=True, autoplay=True)
video.upload(
fn=stream_object_detection,
inputs=[video, conf_threshold],
outputs=[output_video],
)
最后,我们可以在此处查看在Hugging Face Spaces上托管的演示:gradio/rt-detr-object-detection。运行截图如下: