视频分析框架VideoPipe完整介绍
(2024年4月编写)
github地址
https://github.com/sherlockchou86/video_pipe_c
作者微信
zhzhi78(备注 videopipe),拉群交流(1000人群),及时获取代码更新。
网站介绍
配套教程
http://www.videopipe.cool/index.php/2024/09/11/videopipetutorials/
演示Sample
http://www.videopipe.cool/index.php/2024/08/21/videopipesamples/
0、一个引子
计算机视觉(Computer Vision,后简称CV)是人工智能领域中的一个细分场景。随着深度学习技术的飞速发展,基于神经网络的图像算法已经慢慢取代了传统图像算法,也越来越多地落地到实际应用场景中。下图列举了常见的神经网络图像算法:

图1 常见神经网络图像算法
神经网络的训练、调优离不开算法工程师,近几年在众多IT技术招聘岗位中,无论是薪资待遇还是招聘数量上,算法工程师岗位都是名列前茅。那么在这个调参(炼丹)火热的时代(公司保安大爷都知道什么叫“监督学习”),如何将训练好的神经网络图像算法模型快速部署落地到实际应用场景中呢?VideoPipe视频分析框架满足这一需求,它适用于大部分视频结构化应用场景,可以快速集成训练好的图像算法模型,包括但不限于:
图像分类算法。给定的图片是小猫还是小狗?是白毛还是黑毛?目标检测算法。给定的图片中包含哪些目标(车、人、文字...)?目标坐标、尺寸是多少?图像分割算法。为给定的图片做像素级分割,不同区域显示不同颜色。图像特征编码算法。为给定的图片提取“指纹级”特征,可用于图片识别、对比、检索。图像生成算法。随机生成指定风格的图片,或为图片转换风格(比如将手机拍摄的人物照片转成卡通风格)。
VideoPipe视频分析框架可广泛应用于智慧交通、智能安防等领域,可快速构建人脸识别、车牌识别、交通事件检测、以图搜图、OCR文字识别、AI换脸等软件系统。下图是使用VideoPipe实现口算练习检查(仿作业帮APP)的功能截图:

图2 口算练习检查
图中绿色代表正确,红色代表错误(并在括号中给出了正确答案),橙色代表格式不对(比如表达式中左括号没有对应的右括号)。另外,图中上半部分的管道代表口算练习检查的核心环节。下面整理了作业帮APP中口算练习检查功能的完整流程,我们按照该流程可以完整复现作业帮APP中的功能:
- 用户打开作业帮APP,点击
口算检查按钮,APP弹出相机界面准备拍照 - 用户将手机对准口算作业本,保持相机画面正对口算题目,点击
拍照按钮 - 作业帮APP抓拍一张照片,通过http协议上传到作业帮服务器
- 服务器收到图片数据(编码数据),对其进行解码,生成图片
- 服务器调用OCR文字识别算法,对图片中的口算题目进行检测和识别,得到String类型字符串,类似
1+1=2 - 服务器调用数学表达式解析库(一种可以对数学表达式进行解析和计算的工具库),计算
=号左边的结果(这里结果是2),然后将左边结果和=号右边的值(学生答题结果,这里也是2)进行比较,给出对错结论 - 按照步骤6的方式检查整张图片中的口算表达式,最后计算总得分
- 服务器将检查结果(对、错、无效)用不同颜色叠加到原上传图片上
- 服务器将最终结果(含叠加结果的图片)返回给作业帮APP,APP呈现给用户
我们可以看到,口算练习检查整个流程包含了多个处理环节和技术栈,我用图片直观描述如下:

图3 口算练习检查流程
图中虚线部分全部可以借助VideoPipe来实现,图片接收和解码、字符检测和识别、数学表达式解析和计算、检查结果叠加,这些环节在VideoPipe中有节点类型一一与之对应:
vp_image_src_node节点:完成接收图片和解码工作vp_ppocr_text_detector_node节点:完成字符检测和识别vp_expr_check_node节点:完成数学表达式解析和计算vp_expr_osd_node节点:完成检查结果叠加
VideoPipe可以帮助你实现口算练习检查的核心环节,当然VideoPipe能做的远不止于此,接下来我来对它做详细介绍。
1、VideoPipe介绍
一个用于视频(含图片,下同)分析的图像算法集成框架。它可以处理复杂任务,如流读取(从本地或网络)、解码、基于深度学习模型推理(分类/检测/特征提取/...)、跟踪、行为分析(逻辑处理)、数据叠加(OSD)、数据转发(如Kafka/Socket)、编码和流推送(RTMP或本地文件)。整个框架采用面向插件的编程风格,我们可以使用各种不同类型的插件,即框架中的Node类型,来构建不同类型的视频分析管道。

图4 VideoPipe工作管道(示意)
VideoPipe类似于英伟达的DeepStream和华为的mxVision,但它更易于使用,更具备可移植性,并且对于像GStreamer这样难以学习(编程风格或调试方面)的第三方模块依赖较少。该框架纯粹由原生C++ STL编写,只依赖主流的第三方库(如OpenCV),因此代码更易于在不同平台上移植。
注意:
VideoPipe是一个让计算机视觉领域中算法模型集成更加简单的框架,它并不是TensorFlow、TensorRT类似的深度学习框架。
2、主要功能
VideoPipe包含以下主要功能:
- 流读取。支持主流的视频流协议,如udp(视频或图像)、rtsp、rtmp、文件(视频或图像)。
- 视频解码。支持基于OpenCV/GStreamer的视频(图片)解码(支持硬件加速)。
- 基于深度学习的算法推理。支持基于深度学习算法的多级推理,例如目标检测、图像分类、特征提取。你只需准备好模型并了解如何解析其输出即可。推理可以基于不同的后端实现,如
OpenCV::DNN(默认)、TensorRT、PaddleInference、ONNXRuntime等,任何你喜欢的都可以。 - 屏幕显示(OSD)。支持可视化,如将模型输出结果绘制到帧上。
- 数据代理。支持将结构化数据(json/xml/自定义格式)以kafka/Sokcet等方式推送到云端、文件或其他第三方平台。
- 目标跟踪。支持目标追踪,例如IOU、SORT跟踪算法等。
- 行为分析(BA)。支持基于跟踪的行为分析,例如越线、停车、违章等交通判断。
- 录制。支持特定时间段的视频录制,特定帧的截图。
- 视频编码。支持基于OpenCV/GStreamer的视频(图片)编码(支持硬件加速)。
- 流推送。支持通过rtmp、rtsp(无需专门的rtsp服务器)、文件(视频/图像)、udp(仅限图像)、屏幕显示(GUI)进行流推送或结果展示。
3、主要特点
VideoPipe具备以下特点:
- 可视化管道,对程序调试非常有帮助。管道的运行状态会自动在屏幕上刷新,包括管道中每个连接点的fps、缓存大小、延迟等信息,你可以根据这些运行信息快速确定管道的瓶颈所在。
- 节点之间通过智能指针传递数据,默认情况下是浅拷贝,当数据在整个管道中流动时无需进行内容拷贝操作。当然,如果需要,你可以指定深拷贝,例如当管道具有多个分支时,你需要分别在两个不同的内容拷贝上进行操作。
- 你可以构建不同类型的管道,支持单通道或多通道的管道,管道中的各通道是独立的。每个通道可以拆分成多个分支并行处理不同的任务,之后进行数据同步,再合并回一个分支进行输出。
- 管道支持钩子(回调),你可以向管道注册回调以获取状态通知(参见第1项特点),例如实时获取某个连接点的fps。
- VideoPipe中已经内置了丰富的节点(Node)类型,所有节点都可以由用户重新实现,也可以根据你的实际需求实现更多节点类型。
- 支持动态操作管道,支持多线程并行操作,支持
热插拔操作模式(管道无需先暂停,即插即用)。 - 整个框架主要由原生C++编写,可在所有平台上移植。
4、如何使用
4.1 快速开始
下面是一个如何构建Pipeline然后运行的Sample(请先修改代码中的相关文件路径):
#include "../nodes/vp_file_src_node.h"
#include "../nodes/infers/vp_yunet_face_detector_node.h"
#include "../nodes/infers/vp_sface_feature_encoder_node.h"
#include "../nodes/osd/vp_face_osd_node_v2.h"
#include "../nodes/vp_screen_des_node.h"
#include "../nodes/vp_rtmp_des_node.h"
#include "../utils/analysis_board/vp_analysis_board.h"
/*
* ## 1-1-N sample ##
* 1个视频输入,1个视频分析任务(人脸检测和识别),2个输出(屏幕输出/RTMP推流输出)
*/
int main() {
VP_SET_LOG_INCLUDE_CODE_LOCATION(false);
VP_SET_LOG_INCLUDE_THREAD_ID(false);
VP_LOGGER_INIT();
// 创建节点
auto file_src_0 = std::make_shared<vp_nodes::vp_file_src_node>("file_src_0", 0, "./test_video/10.mp4", 0.6);
auto yunet_face_detector_0 = std::make_shared<vp_nodes::vp_yunet_face_detector_node>("yunet_face_detector_0", "./models/face/face_detection_yunet_2022mar.onnx");
auto sface_face_encoder_0 = std::make_shared<vp_nodes::vp_sface_feature_encoder_node>("sface_face_encoder_0", "./models/face/face_recognition_sface_2021dec.onnx");
auto osd_0 = std::make_shared<vp_nodes::vp_face_osd_node_v2>("osd_0");
auto screen_des_0 = std::make_shared<vp_nodes::vp_screen_des_node>("screen_des_0", 0);
auto rtmp_des_0 = std::make_shared<vp_nodes::vp_rtmp_des_node>("rtmp_des_0", 0, "rtmp://192.168.77.60/live/10000");
// 构建管道
yunet_face_detector_0->attach_to({file_src_0});
sface_face_encoder_0->attach_to({yunet_face_detector_0});
osd_0->attach_to({sface_face_encoder_0});
// 管道自动拆分
screen_des_0->attach_to({osd_0});
rtmp_des_0->attach_to({osd_0});
// 启动管道
file_src_0->start();
// 可视化管道
vp_utils::vp_analysis_board board({file_src_0});
board.display();
}
上面代码运行后,会出现3个画面:
- 管道的运行状态图,状态自动刷新
- 屏幕显示结果(GUI)
- 播放器显示结果(RTMP)

图5 1-1-N_sample运行截图
在上面Sample中,VideoPipe从本地读取视频文件,然后检测其中的人脸、对每个人脸提取特征、比较2张人脸的相似度、将结果叠加到视频上,最后在屏幕中显示,并以RTMP的形式将视频推到服务器上供互联网其他用户播放。整个流程完全由VideoPipe帮忙完成,插件式编程风格,直观、灵活。
4.2 更多案例
github仓库中有接近40个Sample,涵盖人脸识别、车辆检测分类、以图搜图、目标跟踪、交通事件检测、车牌识别、动态管道、图像分割等等。下面是拥堵检测和口算练习检查的截图:
车牌识别

拥堵检测

更多案例请访问github仓库。
5、原理细节
下面给大家详细介绍框架实现原理和技术细节,对该部分感兴趣的小伙伴可以加我微信交流(见文章末尾)。
5.1 视频结构化应用的核心环节
视频结构化是将非结构化数据(视频/图片)转换为结构化数据的过程。非结构化数据通常包括:
- 视频
- 图像
- 音频
- 自然语言文本
而结构化数据主要包括诸如 JSON、XML或数据库中的数据表等,这些数据可以直接由机器(程序)处理。具体到视频(含图片,下同)方面,结构化的过程主要涉及以下核心部分:
读取流。从网络或本地机器获取视频流。解码。将字节流解码为帧,因为算法只能作用于图像。推理。对图像进行深度学习推理,如检测、分类或特征提取。跟踪。跟踪视频中的目标。行为分析/逻辑处理。分析目标的轨迹、属性。OSD。在图像上显示结果,用于调试或得到直观效果。消息代理。将结构化数据推送到外部,供业务平台使用。编码。对包含结果的帧进行编码,以便传输、存储。推送流。将字节流推送到外部或直接保存。

上述每个环节对应VideoPipe中的一种插件类型,即代码中的Node。
5.2 VideoPipe中的Node
VideoPipe中的每个Node负责一种任务(严格遵循单一职责原则),例如解码或推理。我们可以将许多节点串在一起构建成管道,并让视频数据流经整个管道。每个Node内部都有两个队列,一个用于缓存上游节点推送的数据,另一个用于缓存等待被推送到下游节点的数据。我们可以在两个队列之间编写逻辑代码,这是典型的生产者-消费者模式。

默认情况下,生产者和消费者在节点内部使用单个线程工作,因此在处理复杂任务时(例如,在 vp_message_broker_node中推送数据是一个耗时的操作),我们需要编写异步代码来避免阻塞管道。

VideoPipe中有三种类型的节点,分别是:
SRC节点:源节点,数据被创建的地方(内部只有一个队列,用于缓存被推送到下游节点的数据)。MID节点:中间节点,数据将在此处理。DES节点:目标节点,数据消失的地方(内部只有一个队列,用于缓存来自上游节点的数据)。
每个节点本身具有合并多个上游节点和拆分成多个下游节点的能力。注意,默认情况下节点在将数据从一个节点传输到另一个节点时使用浅拷贝和等值拷贝。如果您需要深拷贝或希望按通道索引传输数据(希望数据不混淆),则在分裂点添加一个vp_split_node类型节点。

5.3 VideoPipe中的数据流
视频是一种重量级数据,因此频繁进行深拷贝会降低管道的性能。实际上,VideoPipe中两个节点之间传递的数据默认使用智能指针,一旦数据由源节点创建,数据内容在整个管道中大多数时间不会被复制(但如果需要,我们可以指定深度拷贝模式,例如使用vp_split_node)。

视频由连续的帧组成,VideoPipe 逐帧处理这些帧,因此帧元数据中的帧索引也会连续增加。
5.4 VideoPipe中的钩子
钩子是一种机制,让主体在发生某些事件时通知检测者,VideoPipe也支持钩子。管道触发回调函数(std::function)与外部代码通信,例如实时推送管道自身的 fps、延迟和其他状态信息。我们在编写回调函数内部代码时,不允许有阻塞出现,否则影响整个管道性能。

钩子有助于调试我们的应用程序,并快速找出整个管道中的瓶颈,VideoPipe框架中自带的可视化工具vp_analysis_board就依赖于钩子机制。
5.5 在VideoPipe中实现新的Node类型
vp_node是VideoPipe中所有节点的基类。我们可以定义一个从vp_node派生的新节点类,并重写一些虚函数,如handle_frame_meta和handle_control_meta。
handle_frame_meta:处理流经当前节点的帧数据。handle_control_meta:处理流经当前节点的控制指令数据。

帧数据指的是VideoPipe中的 vp_frame_meta,其中包含与帧相关的数据,如帧索引、数据缓冲区、原始宽度等等。控制指令数据指的是VideoPipe中的 vp_control_meta,其中包含与命令相关的数据,例如记录视频、记录图像等。
注意,并非所有流经当前节点的数据都应该被处理,我们只需要处理我们感兴趣的内容。
六、相似框架对比
VideoPipe主要用途与DeepStream/mxVision相似,用于快速构建视频分析应用系统。但三者之间存在一些差异:
| 序号 | 名称 | 是否开源 | 学习门槛 | 适用平台 | 性能 | 三方依赖 |
|---|---|---|---|---|---|---|
| 1 | DeepStream | 否 | 高 | 仅限英伟达 | 高 | 多 |
| 2 | mxVision | 否 | 高 | 仅限华为 | 高 | 多 |
| 3 | VideoPipe | 是 | 低 | 不限平台 | 中 | 少 |
DeepStream和mxVision(包括其他AI硬件厂家推出的类似框架)只可用于自家硬件平台,性能相对较高,VideoPipe由于要兼容各种不同硬件,数据共享方面弱于前者。VideoPipe学习门槛更低,核心代码完全开源,编码风格和代码调试方便均要优于其他类似框架(VideoPipe没有GObject相关内容)。下图显示视频分析过程中数据共享程度对整个处理管道性能的影响:

上图左侧数据来回在CPU和GPU之间传递,影响整个管道处理速度;右侧大部分操作全部在GPU侧完成,减少数据来回传递次数,数据共享程度更高,有利于管道处理性能。
视频分析框架VideoPipe完整介绍的更多相关文章
- 马蜂窝视频编辑框架设计及在 iOS 端的业务实践
(马蜂窝技术公众号原创内容,ID: mfwtech) 熟悉马蜂窝的朋友一定知道,点击马蜂窝 App 首页的发布按钮,会发现发布的内容已经被简化成「图文」或者「视频」. 长期以来,游记.问答.攻略等图文 ...
- 系统级性能分析工具perf的介绍与使用[转]
测试环境:Ubuntu16.04(在VMWare虚拟机使用perf top存在无法显示问题) Kernel:3.13.0-32 系统级性能优化通常包括两个阶段:性能剖析(performance pro ...
- ISP基本框架及算法介绍
什么是ISP,他的工作原理是怎样的? ISP是Image Signal Processor的缩写,全称是影像处理器.在相机成像的整个环节中,它负责接收感光元件(Sensor)的原始信号数据,可以理解为 ...
- 【转】OMCS网络语音视频聊天框架(跨平台)
原文地址:http://www.cnblogs.com/zhuweisky/archive/2012/08/02/2617877.html OMCS网络语音视频框架是集成了语音通话.视频通话.远程桌面 ...
- NVIDIA DeepStream 5.0构建智能视频分析应用程序
NVIDIA DeepStream 5.0构建智能视频分析应用程序 无论是要平衡产品分配和优化流量的仓库,工厂流水线检查还是医院管理,要确保员工和护理人员在照顾病人的同时使用个人保护设备(PPE),就 ...
- 系统级性能分析工具perf的介绍与使用
测试环境:Ubuntu16.04(在VMWare虚拟机使用perf top存在无法显示问题) Kernel:3.13.0-32 系统级性能优化通常包括两个阶段:性能剖析(performance pro ...
- iOS集成ijkplayer视频直播框架,遇到的bug和坑...
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 32.0px "Helvetica Neue"; color: #555555 } p. ...
- 符号执行-基于python的二进制分析框架angr
转载:All Right 符号执行概述 在学习这个框架之前首先要知道符号执行.符号执行技术使用符号值代替数字值执行程序,得到的变量的值是由输入变 量的符号值和常量组成的表达式.符号执行技术首先由Kin ...
- 开源网络抓包与分析框架学习-Packetbeat篇
开源简介packbeat是一个开源的实时网络抓包与分析框架,内置了很多常见的协议捕获及解析,如HTTP.MySQL.Redis等.在实际使用中,通常和Elasticsearch以及kibana联合使用 ...
- windows下nodejs express安装及入门网站,视频资料,开源项目介绍
windows下nodejs express安装及入门网站,视频资料,开源项目介绍,pm2,supervisor,npm,Pomelo,Grunt安装使用注意事项等总结 第一步:下载安装文件下载地址: ...
随机推荐
- python多进程完成模拟支付
#!/usr/bin/python # -*- coding: UTF-8 -*- '''@auther :mr.qin @IDE:pycharm''' from tool.Common import ...
- 创建一个专属的 CLI
作为一个前端,基本上每次初始化项目都会用到脚手架,通过一些脚手架可以快速的搭建一个前端的项目并集成一些所需的功能模块,避免自己每次都手动一个一个去安装.安装各个包的这个过程其实没啥营养,通过封装一个脚 ...
- 2024CSP-J游记
拿到题的第一步,先看第一题,大致扫了一眼,水题.以为是hash,进一步思考了一下,hash不行.发现可以用set,于是拿set敲了一下,样例全对. 第二题,看了眼样例以为是DFS.实际看了看发现是模拟 ...
- house of cat
调用方法 调用链1 house of cat调用链 __malloc_assert 在 2.35 的 glibc 中源码如下 static void __malloc_assert (const ch ...
- 怎样替换 rhel 7.3 的 yum
[背景] 想在自己安装的虚拟机上搭建一套 git+gitee+vscode 环境(欢迎看下期文章),发现python版本是2.7,这个版本太老 想通过yum进行更新,结果提示需要注册,索性就查查替换y ...
- PS命令显示进程数,清理僵尸进程
显示系统上所有进程的进程树 ps -ef --forest 显示给定进程的进程树 -C:Select by command name.这个命令会把name指定进程的所有子进程显示出来 [root@lo ...
- Docker之基础(一)
接触Docker有很久一段时间, 但是没有好好总结一下, 借此公司项目全面容器化, 记录一下常用的Docker操作 概况: 本次容器化的项目包括PHP+Python项目,PHP是基于php-fpm的基 ...
- 使用Tesseract进行图片文字识别
Tesseract介绍 Tesseract 是一个开源的光学字符识别(OCR)引擎,最初由 HP 在 1985 年至 1995 年间开发,后来被 Google 收购并开源.Tesseract 支持多种 ...
- 自有Jar包生成Docker镜像
前言 经常会有些自己写的一些SpringBoot小项目,为了实现一些小的功能/需求,但是部署的时候,不管是生成jar包,还是war包部署到tomcat中,都容易因为需要部署的环境(比如java版本.t ...
- 前端好用API之scrollIntoView
前情 在前端开发需求中,经常需要用到锚点功能,以往都是获取元素在滚动容器中的位置再设置scrollTop来实现的. scrollIntoView介绍 scrollIntoView()方法将调用它的元素 ...