当前位置: 首页 > news >正文

图像处理常见的两种拉流方式

传统算法或者深度学习在进行图像处理之前,总是会首先进行图像的采集,也就是所谓的拉流。解决拉流的方式有两种,一个是直接使用opencv进行取流,另一个是使用ffmpeg进行取流,如下分别介绍这两种方式进行拉流处理。

1、opencv直接取流

opencv的取流方式主要是利用VideoCapture类进行处理的。VideoCapture提供了一整套的读取视频流信息的方案,主要的函数如下:
VideoCapture有三个构造函数:

  • 不带任何参数的构造函数
    在这里插入图片描述
  • 带有一个视频流地址的构造函数
    在这里插入图片描述
  • 带有一个视频index的构造函数
    在这里插入图片描述
    isOpened()函数主要是判定是否成功打开流地址
    在这里插入图片描述
    read()读取视频数据
    在这里插入图片描述
    release()函数用于释放类对象
    在这里插入图片描述
    具体参考地址:https://docs.opencv.org/4.0.0/d8/dfe/classcv_1_1VideoCapture.html

1.1 python拉流

主要流程为分为以下几步:

  • 通过流的地址实例化VideoCapture类
  • 判断是否成功打开流地址
  • 循环读取每一帧流数据并处理
  • 释放实例化的对象
  • 释放cv
def vedio2Img(vedio_path, save_path):cap = cv2.VideoCapture(vedio_path)fps = int(cap.get(cv2.CAP_PROP_FPS))total_count = cap.get(cv2.CAP_PROP_FRAME_COUNT)count = 0img_idx = 0if not cap.isOpened():returnwhile True:success, frame = cap.read()if success:try:count += 1if count % fps == 0:img_idx += 1name = save_path.split('\\')[-1]save_path1 = os.path.join(save_path, '{}_vedio_{}.jpg'.format(name, str(img_idx)))save_img(save_path1, frame)print('finish number {} img save'.format(img_idx))cv2.waitKey(1)except:print('encounter some wrong')continuecap.release()cv2.destroyAllWindows()

1.2 C++ opencv拉流

c++的使用opencv拉流的方式和opencv基本一致(ps:python的底层应该是C++实现的),因此其实现格式如下所示:

	std::string vedio_path = "rtsp://admin:123456@127.0.0.1/Streaming/Channels/11000";cv::VideoCapture cap;cap.open(vedio_path);if (!cap.isOpened()) {std::cout << "error about cap" << std::endl;}VideoFrameDecode videoframe;cv::Mat frame;while (cap.read(frame)){if (frame.empty()) {break;}int w = frame.size().width;int h = frame.size().height;printf("h=%i,w=%i", h, w);unsigned char* buffer = frame.data;size_t stride = frame.step;cv::Mat img = cv::Mat(h, w, CV_8UC3, (void*)buffer, stride);cv::namedWindow("demo", cv::WINDOW_NORMAL);cv::imshow("demo", img);cv::waitKey(0);}cap.release();cv::destroyAllWindows();

2、ffmpeg拉流(C++实现)

  • 下载ffmpeg包的
    ffmpeg包下载地址
    博主下载的5.1.2版本
    在这里插入图片描述

  • vs2022配置使用
    在C/C+±>附加包含目录中添加新下载的ffmpeg包的include路径
    在这里插入图片描述
    在链接器->附加库目录中添加ffmpeg包的lib文件路径
    在这里插入图片描述
    在链接器->输入->附加依赖项中加入所需要的lib库目录,整理如下:

    avcodec.lib
    avdevice.lib
    avfilter.lib
    avformat.lib
    avutil.lib
    swresample.lib
    swscale.lib
    

    如果不想在环境变量中配置ffmpeg中bin文件的目录,可以使用如下方式临时配置:
    在调试->环境中使用Path=D:\ffmpeg\bin;%PATH即可临时使用
    在这里插入图片描述

博主将拉流方式封装为一个类,主要代码如下所示:
ffmpeg.h文件如下:

#ifndef __FFMPEG_DECODE_H__
#define __FFMPEG_DECODE_H__// Opencv
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
extern "C"
{
#include<libavutil/avutil.h>
#include<libavutil/imgutils.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include<libavdevice/avdevice.h>
};struct VideoFrameDecode {void* buffer;		//֡帧的buffer指针(仅支持RGB格式)int pitch;			//图像一行的宽度
};class ReadFfmpeg
{
public:ReadFfmpeg(char* rtsppath);~ReadFfmpeg();void processOneFrame(cv::Mat &img);private:AVFormatContext* formatContext = nullptr; int ret = -1;int videoStreamIndex = -1;AVCodecParameters* codecParameters = nullptr;const AVCodec* codec = nullptr; AVCodecContext* codecContext = nullptr; AVPacket packet; AVFrame* pFrameRGB;uint8_t* buffer;SwsContext* sws_ctx; };
#endif

其中具体实现的ffmpeg.cpp文件如下所示

#include "ReadFfmpeg.h"
#include <iostream>
#include<chrono>
#include<thread>
using namespace std;ReadFfmpeg::ReadFfmpeg(char* rtsppath)
{avformat_network_init();AVDictionary* formatOptions = nullptr;av_dict_set_int(&formatOptions, "buffer_size", 2 << 20, 0);av_dict_set(&formatOptions, "rtsp_transport", "tcp", 0); //默认使用udp协议进行传输,会出现max delay reached. need to consume packet av_dict_set_int(&formatOptions, "timeout", 5000000, 0);formatContext = avformat_alloc_context();ret = avformat_open_input(&formatContext, rtsppath, nullptr, &formatOptions);if (ret != 0) {std::cerr << "Failed to open RTSP stream." << std::endl;}ret = avformat_find_stream_info(formatContext, nullptr);if (ret < 0) {std::cerr << "Failed to find stream info." << std::endl;}for (unsigned int i = 0; i < formatContext->nb_streams; ++i) {if (formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {videoStreamIndex = i;break;}}if (videoStreamIndex == -1) {std::cerr << "Failed to find video stream." << std::endl;}codecParameters = formatContext->streams[videoStreamIndex]->codecpar;codec = avcodec_find_decoder(codecParameters->codec_id);if (codec == nullptr) {std::cerr << "Failed to find video decoder." << std::endl;}codecContext = avcodec_alloc_context3(codec);if (avcodec_parameters_to_context(codecContext, codecParameters) < 0) {std::cerr << "Failed to allocate codec context." << std::endl;}ret = avcodec_open2(codecContext, codec, nullptr);if (ret < 0) {std::cerr << "Failed to open codec." << std::endl;}pFrameRGB = av_frame_alloc();buffer = (uint8_t*)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_RGB24, codecContext->width, codecContext->height, 1));av_image_fill_arrays(pFrameRGB->data, pFrameRGB->linesize, buffer, AV_PIX_FMT_RGB24, codecContext->width, codecContext->height, 1);sws_ctx = sws_getContext(codecContext->width, codecContext->height, codecContext->pix_fmt,codecContext->width, codecContext->height, AV_PIX_FMT_RGB24,SWS_BILINEAR, nullptr, nullptr, nullptr);ret = av_read_frame(formatContext, &packet);if (ret < 0) {std::cerr << "Failed to open packet." << std::endl;}
}ReadFfmpeg::~ReadFfmpeg()
{avformat_network_deinit();avcodec_free_context(&codecContext);sws_freeContext(sws_ctx);	av_free(pFrameRGB);av_free(buffer);av_free(codecParameters);avformat_close_input(&formatContext);
}void ReadFfmpeg::processOneFrame(cv::Mat& img)
{if (img.empty()){img = cv::Mat(codecContext->height, codecContext->width, CV_8UC3);}int ret = av_read_frame(formatContext, &packet);if (ret >= 0) {if (packet.stream_index == videoStreamIndex) {avcodec_send_packet(codecContext, &packet);AVFrame* avFrame = av_frame_alloc();int res = avcodec_receive_frame(codecContext, avFrame);if (res == 0) {// Convert frame to RGBsws_scale(sws_ctx, avFrame->data, avFrame->linesize, 0, codecContext->height, pFrameRGB->data, pFrameRGB->linesize);img.data = pFrameRGB->data[0];}av_frame_free(&avFrame);}}av_packet_unref(&packet);
}void test() {char* filename = (char*)"rtsp://admin:123456@127.0.0.1:10000/Streaming/Channels/10000";ReadFfmpeg* fmpeg = new ReadFfmpeg(filename);cv::Mat img;int nFrame = 0;auto start = std::chrono::system_clock::now();for (;;){nFrame++;fmpeg->processOneFrame(img);if (nFrame % 100==0) {nFrame = 0;auto end = std::chrono::system_clock::now();auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);std::cout << "the fps is: " << static_cast<float>(100 / (duration.count() / 1000.0)) << std::endl;start = end;}// Display framecv::namedWindow("RTSP Stream", cv::WINDOW_NORMAL);cv::imshow("RTSP Stream", img);cv::waitKey(1);}delete fmpeg;}

以上是一个非常简单的拉流方式,仅可以用作一个demo,实现流的读取,如果想达到实时状态的取流和处理,需要使用多线程的方式,实现一个读取流数据的线程,将数据放入队列,同时实现一个读取流数据的线程,从队列读取数据,同时运行。

附录

实际上opencv也是可以使用ffmpeg的方式进行拉流的,只不过需要在编译opencv的时候,指定ffmpeg版本。

相关文章:

图像处理常见的两种拉流方式

传统算法或者深度学习在进行图像处理之前&#xff0c;总是会首先进行图像的采集&#xff0c;也就是所谓的拉流。解决拉流的方式有两种&#xff0c;一个是直接使用opencv进行取流&#xff0c;另一个是使用ffmpeg进行取流&#xff0c;如下分别介绍这两种方式进行拉流处理。 1、o…...

数据可视化数据调用浅析

数据可视化是现代数据分析和决策支持中不可或缺的一环。它将数据转化为图形、图表和可视化工具&#xff0c;以便更直观地理解和解释数据。在数据可视化的过程中&#xff0c;数据的调用和准备是关键的一步。本文将探讨数据可视化中的数据调用过程&#xff0c;并介绍一些常用的数…...

恒运资本:CPO概念发力走高,兆龙互联涨超10%,华是科技再创新高

CPO概念15日盘中发力走高&#xff0c;截至发稿&#xff0c;华是科技涨超15%再创新高&#xff0c;兆龙互联涨逾11%&#xff0c;中贝通讯涨停&#xff0c;永鼎股份、太辰光涨超5%&#xff0c;天孚通讯涨逾4%。 消息面上&#xff0c;光通讯闻名咨询机构LightCounting近日发布的202…...

【蓝桥杯】[递归]母牛的故事

原题链接&#xff1a;https://www.dotcpp.com/oj/problem1004.html 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 我们列一个年份和母牛数量的表格&#xff1a; 通过观察&#xff0c;找规律&#xff0c;我们发现&#xff1a; 当年份小于等于4时&…...

使用RDP可视化远程桌面连接Linux系统

使用RDP可视化远程桌面连接Linux系统 远程桌面连接Linux安装安装包准备服务器安装xrdp远程连接 远程桌面连接Linux 通常使用SSH来连接服务器&#xff0c;进行命令行操作&#xff0c;但是这次需要远程调试生产环境的内网服务器&#xff0c;进行浏览器访问内网网站&#xff0c;至…...

数据可视化diff工具jsondiffpatch使用学习

1.jsondiffpatch 简介 jsondiffpatch 是一个用于比较和生成 JSON 数据差异的 JavaScript 库。它可以将两个 JSON 对象进行比较&#xff0c;并生成一个描述它们之间差异的 JSON 对象。这个差异对象可以用于多种用途&#xff0c;例如&#xff1a; 生成可视化的差异报告应用差异…...

pdf 转 word

pdf 转 word 一、思路 直接调用LibreOffice 命令进行文档转换的命令行工具 使用的前系统中必须已经安装了 libreofficelibreoffice已翻译的用户界面语言包: 中文 (简体)libreoffice离线帮助文档: 中文 (简体)上传字体 重点&#xff1a;重点&#xff1a;重点&#xff1a; 亲…...

【数据结构OJ题】设计循环队列

原题链接&#xff1a;https://leetcode.cn/problems/design-circular-queue/ 1. 题目描述 2. 循环队列的概念和结构 为充分利用向量空间&#xff0c;克服"假溢出"现象的方法是&#xff1a;将向量空间想象为一个首尾相接的圆环&#xff0c;并称这种向量为循环向量。…...

Java 中创建对象有哪些方式?

目录 面试回答 使用 new 关键字 使用反射机制 使用 Class 类的 newInstance() 方法 使用 Constructor 类的 newInstance 方法 使用 clone 方法 使用反序列化 使用方法句柄 使用 Unsafe 分配内存 面试回答 使用 new 关键字 这是我们最常用的、也是最简单的创建对象的方…...

Kafka 消息发送和消费流程

发送消息 流程如下&#xff1a; Producer 端直接将消息发送到 Broker 中的 Leader 分区中Broker 对应的 Leader 分区收到消息会先写入 Page Cache&#xff0c;定时刷盘进行持久化&#xff08;顺序写入磁盘&#xff09;Follower 分区拉取 Leader 分区的消息&#xff0c;并保持…...

UVa10048 Audiophobia(floyd)

题意 给出一个图&#xff0c;图中的边表示从点u到点v路径上的噪音。给出q个查询&#xff0c;问从u到v所经路径上的最小噪音 思路 在使用floyd计算点对之间的路径时&#xff0c; D u , v k m i n { D u , v k − 1 , m a x { D u , k k − 1 , D k , v k − 1 } } D_{u, v}^…...

​Redis概述

目录 Redis - 概述 使用场景 如何安装 Window 下安装 Linux 下安装 docker直接进行安装 下载Redis镜像 Redis启动检查常用命令 Redis - 概述 redis是一款高性能的开源NOSQL系列的非关系型数据库,Redis是用C语言开发的一个开源的高键值对(key value)数据库,官方提供测试…...

MsrayPlus多功能搜索引擎采集软件

MsrayPlus多功能搜索引擎采集软件 摘要&#xff1a; 本文介绍了一款多功能搜索引擎软件-MsrayPlus&#xff0c;该软件能够根据关键词从搜索引擎中检索相关数据&#xff0c;并提供搜索引擎任务、爬虫引擎任务和联系信息采集三大功能。我们将分析该软件在不同领域的应用&#xf…...

机器学习之概率论

最近&#xff0c;在了解机器学习相关的数学知识&#xff0c;包括线性代数和概率论的知识&#xff0c;今天&#xff0c;回顾了概率论的知识&#xff0c;贴上几张其他博客的关于概率论的图片&#xff0c;记录学习过程。...

【深度学习 | 数据可视化】 视觉展示分类边界: Perceptron模型可视化iris数据集的决策边界

&#x1f935;‍♂️ 个人主页: AI_magician &#x1f4e1;主页地址&#xff1a; 作者简介&#xff1a;CSDN内容合伙人&#xff0c;全栈领域优质创作者。 &#x1f468;‍&#x1f4bb;景愿&#xff1a;旨在于能和更多的热爱计算机的伙伴一起成长&#xff01;&#xff01;&…...

【计算机视觉】相机基本知识(还在更新)

1.面阵工业相机与线阵工业相机 1.1 基本概念区别 面阵相机则主要采用的连续的、面状扫描光线来实现产品的检测&#xff1b; 线阵相机即利用单束扫描光来进行物体扫描的工作的。 1.2 优缺点 &#xff08;1&#xff09;面阵CCD工业相机&#xff1a; 优点&#xff1a;应用面…...

C++ (友元)(类嵌套时,成员函数以及类声明定义的顺序)小demo

#include<iostream> using namespace std; class Building; //1.因为Goodgay类需要声明Building类变量&#xff0c; //所以Building类必须Goodgay类之前声明&#xff08;前向声明&#xff09;&#xff1b; class GoodGay { public:GoodGay();void visit(); private:Build…...

前端实习第五周周记

前言 每一天做了什么还是要记录一下&#xff0c;不然过两天后就会发现&#xff0c;慢慢遗忘自己的收获与做过的东西。 这周做的是医学检验系统的样本库部分。由于是公司的代码所以不能交代具体&#xff0c;那么久聊一下每天具体做了些什么以及我的一些收获。 周一 周一上午…...

【图论】Floyd算法

一.简介 Floyd算法&#xff0c;也称为Floyd-Warshall算法&#xff0c;是一种用于解决所有节点对最短路径问题的动态规划算法。它可以在有向图或带权图中找到任意两个节点之间的最短路径。 Floyd算法的基本思想是通过中间节点逐步优化路径长度。它使用一个二维数组来存储任意两…...

ceph数据分布

ceph的存储是无主结构&#xff0c;数据分布依赖client来计算&#xff0c;有两个条主要路径。 1、数据到PG 2、PG 到OSD 有两个假设&#xff1a; 第一&#xff0c;pg的数量稳定&#xff0c;可以认为保持不变&#xff1b; 第二&#xff0c; OSD的数量可以增减&#xff0c;OSD的…...

通过Wrangler CLI在worker中创建数据库和表

官方使用文档&#xff1a;Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后&#xff0c;会在本地和远程创建数据库&#xff1a; npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库&#xff1a; 现在&#xff0c;您的Cloudfla…...

JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案

JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停​​ 1. ​​安全点(Safepoint)阻塞​​ ​​现象​​:JVM暂停但无GC日志,日志显示No GCs detected。​​原因​​:JVM等待所有线程进入安全点(如…...

如何在最短时间内提升打ctf(web)的水平?

刚刚刷完2遍 bugku 的 web 题&#xff0c;前来答题。 每个人对刷题理解是不同&#xff0c;有的人是看了writeup就等于刷了&#xff0c;有的人是收藏了writeup就等于刷了&#xff0c;有的人是跟着writeup做了一遍就等于刷了&#xff0c;还有的人是独立思考做了一遍就等于刷了。…...

【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)

1.获取 authorizationCode&#xff1a; 2.利用 authorizationCode 获取 accessToken&#xff1a;文档中心 3.获取手机&#xff1a;文档中心 4.获取昵称头像&#xff1a;文档中心 首先创建 request 若要获取手机号&#xff0c;scope必填 phone&#xff0c;permissions 必填 …...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题

在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件&#xff0c;这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下&#xff0c;实现高效测试与快速迭代&#xff1f;这一命题正考验着…...

中医有效性探讨

文章目录 西医是如何发展到以生物化学为药理基础的现代医学&#xff1f;传统医学奠基期&#xff08;远古 - 17 世纪&#xff09;近代医学转型期&#xff08;17 世纪 - 19 世纪末&#xff09;​现代医学成熟期&#xff08;20世纪至今&#xff09; 中医的源远流长和一脉相承远古至…...

Java + Spring Boot + Mybatis 实现批量插入

在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法&#xff1a;使用 MyBatis 的 <foreach> 标签和批处理模式&#xff08;ExecutorType.BATCH&#xff09;。 方法一&#xff1a;使用 XML 的 <foreach> 标签&#xff…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中&#xff0c;我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道&#xff0c;它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...

虚拟电厂发展三大趋势:市场化、技术主导、车网互联

市场化&#xff1a;从政策驱动到多元盈利 政策全面赋能 2025年4月&#xff0c;国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》&#xff0c;首次明确虚拟电厂为“独立市场主体”&#xff0c;提出硬性目标&#xff1a;2027年全国调节能力≥2000万千瓦&#xff0…...

Kafka主题运维全指南:从基础配置到故障处理

#作者&#xff1a;张桐瑞 文章目录 主题日常管理1. 修改主题分区。2. 修改主题级别参数。3. 变更副本数。4. 修改主题限速。5.主题分区迁移。6. 常见主题错误处理常见错误1&#xff1a;主题删除失败。常见错误2&#xff1a;__consumer_offsets占用太多的磁盘。 主题日常管理 …...