计时器任务实现(保存视频和图像)
下面是一个简单的计时器任务实现,可持续地每秒保存一幅图像,也可持续地每60秒保存一个视频,图像和视频均以当前时间命名:
TimerTask类的实现如下:
class TimerTask {
public:TimerTask(const std::string& path):path_(path) {}~TimerTask() { release(); }void release(){running_ = false;if (monitor_thread_.joinable())monitor_thread_.join();}std::tuple<bool, float> set_minimum_available_space(unsigned int gb);bool set_save_directory_name(const std::string& dir_name);std::string get_local_time();std::tuple<bool, std::string> get_current_directory_name();void save_video(unsigned int seconds) { save_video_ = true; seconds_ = seconds; }void save_image() { save_video_ = false; }void monitor_disk_space(unsigned int gb);private:float get_available_space();std::string path_;unsigned int gb_{0};std::string dir_name_{}; // relative path,used to store videos or imagesbool save_video_{false}; // video or imageunsigned int seconds_{ 0 };std::atomic<bool> running_{ true };std::thread monitor_thread_;
}; // class TimerTask
namespace {
float get_disk_space(std::string_view path)
{namespace fs = std::filesystem;constexpr float GB{ 1024.0 * 1024 * 1024 };try {auto space_info = fs::space(path);return (space_info.available / GB);} catch (const fs::filesystem_error& e) {std::cerr << "Error: " << e.what() << std::endl;return 0.f;}
}void monitor_space(unsigned int gb, std::string_view path, std::atomic<bool>& running)
{namespace fs = std::filesystem;std::mutex mtx;if (!fs::exists(path) || !fs::is_directory(path)) {std::lock_guard<std::mutex> lock(mtx);std::cerr << "Error: " << path << "is not a directory" << std::endl;}while (running) {try {float space = get_disk_space(path);//std::cout << "space: " << space << ", path: " << path << std::endl;if (space < gb) {std::vector<fs::path> names;for (const auto& entry : fs::directory_iterator(path)) {if (fs::is_directory(entry)) {names.push_back(entry.path());}}if (names.size() <= 1) {//{// std::lock_guard<std::mutex> lock(mtx);// std::cerr << "Error: requires at least 2 directories to exist: " << names.size() << std::endl;//}continue;}std::sort(names.begin(), names.end());fs::remove_all(names[0]);{std::lock_guard<std::mutex> lock(mtx);std::cout << "delete dir: " << names[0] << std::endl;}}} catch (const fs::filesystem_error& e) {std::lock_guard<std::mutex> lock(mtx);std::cerr << "Error: " << e.what() << std::endl;}std::this_thread::sleep_for(std::chrono::seconds(1));}
}} // namespacefloat TimerTask::get_available_space()
{return get_disk_space(path_);
}std::tuple<bool, float> TimerTask::set_minimum_available_space(unsigned int gb)
{gb_ = gb;auto space = get_available_space();if (gb_ > space)return std::make_tuple(false, space);elsereturn std::make_tuple(true, space);
}std::string TimerTask::get_local_time()
{using std::chrono::system_clock;auto time = system_clock::to_time_t(system_clock::now());std::tm* tm = std::localtime(&time);std::stringstream buffer;buffer << std::put_time(tm, "%Y%m%d%H%M%S");return buffer.str();
}bool TimerTask::set_save_directory_name(const std::string& dir_name)
{namespace fs = std::filesystem;dir_name_ = dir_name;fs::path path(path_ + "/" + dir_name_);if (fs::exists(path))return true;else {try {return fs::create_directories(path);} catch (const fs::filesystem_error& e) {std::cerr << "Error: " << e.what() << std::endl;return false;}}
}std::tuple<bool, std::string> TimerTask::get_current_directory_name()
{namespace fs = std::filesystem;auto local_time = get_local_time();std::string month(local_time.cbegin(), local_time.cbegin() + 6);std::string day(local_time.cbegin(), local_time.cbegin() + 8);auto curr_dir_name = path_ + "/" + dir_name_ + "/" + month + "/" + day;fs::path path(curr_dir_name);if (fs::exists(path))return std::make_tuple(true, curr_dir_name);else {try {return std::make_tuple(fs::create_directories(path), curr_dir_name);} catch (const fs::filesystem_error& e) {std::cerr << "Error: " << e.what() << std::endl;return std::make_tuple(false, curr_dir_name);}}
}void TimerTask::monitor_disk_space(unsigned int gb)
{monitor_thread_ = std::thread(monitor_space, gb, path_ + "/" + dir_name_, std::ref(running_));
}
类主要函数说明:
(1).set_minimum_available_space函数:用于指定当前可执行文件所在的磁盘剩余空间不低于指定值时才执行;
(2).set_save_directory_name函数:用于指定生成的图像或视频存在的路径。目录结构形式为:指定目录名/月(202502)/日(20250215)。
(3).monitor_disk_space函数:线程函数,用于持续监测磁盘剩余空间,低于指定值时则会删除之前已经存储的文件,每次删除一个月份目录。
(4).get_current_directory_name函数:用于获取当前图像或视频存放的路径名,会按时间自动创建。
(5).get_local_time函数:用于获取当前时间,格式为如为20250215125015。
测试代码如下:
int test_write_video()
{constexpr unsigned int minimum_available_space{ 100 }; // GBconstexpr unsigned int video_seconds{ 60 };constexpr unsigned int minimum_remaining_space{ 50 }; // GBconstexpr char dir_name[]{"record"};constexpr bool save_video{ true };auto current_path = std::filesystem::current_path();TimerTask task(current_path.string());if (auto [ret, space] = task.set_minimum_available_space(minimum_available_space); !ret) { // GBstd::cerr << "Error: insufficient remaining space: " << space << "GB" << std::endl;return -1;}if (auto ret = task.set_save_directory_name(dir_name); !ret) {std::cerr << "Error: failed to create directory: " << dir_name << std::endl;return -1;}task.monitor_disk_space(minimum_remaining_space);cv::VideoCapture cap(0);if (!cap.isOpened()) {std::cerr << "Error: failed to open capture" << std::endl;return -1;}cv::Mat frame;constexpr char win_name[]{"Show"};cv::namedWindow(win_name, cv::WINDOW_NORMAL);if (save_video) { // videotask.save_video(video_seconds);auto frame_width = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_WIDTH));auto frame_height = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_HEIGHT));if (frame_width == 0 || frame_height == 0) {std::cerr << "Error: failed to get frame width or height: " << frame_width << "," << frame_height << std::endl;return -1;}auto fps = cap.get(cv::CAP_PROP_FPS);if (fps <= 0)fps = 30.0;auto codec = cv::VideoWriter::fourcc('D', 'I', 'V', 'X');cv::VideoWriter write_video;auto start_time = std::chrono::high_resolution_clock::now();while (true) {cap >> frame;if (frame.empty()) {std::cerr << "Error: frame is empty" << std::endl;return -1;}auto current_time = std::chrono::high_resolution_clock::now();std::chrono::duration<double> elapsed = current_time - start_time;if (elapsed.count() >= video_seconds || !write_video.isOpened()) {if (write_video.isOpened())write_video.release();auto [ret, curr_dir_name] = task.get_current_directory_name();if (!ret) {std::cerr << "Error: failed to get current directory name: " << curr_dir_name << std::endl;return -1;}auto file_name{ curr_dir_name + "/" + task.get_local_time() + ".avi" };write_video.open(file_name, codec, fps, cv::Size(frame_width, frame_height));if (!write_video.isOpened()) {std::cerr << "Error: failed to open video write: " << file_name << std::endl;return -1;}start_time = std::chrono::high_resolution_clock::now();}write_video.write(frame);cv::imshow(win_name, frame);if (cv::waitKey(1) == 27) // Esc exitbreak;}cap.release();if (write_video.isOpened())write_video.release();} else { // image: save one image per secondtask.save_image();auto start_time = std::chrono::high_resolution_clock::now();while (true) {cap >> frame;if (frame.empty()) {std::cerr << "Error: frame is empty" << std::endl;return -1;}auto current_time = std::chrono::high_resolution_clock::now();std::chrono::duration<double> elapsed = current_time - start_time;if (elapsed.count() >= 1.0) {auto [ret, curr_dir_name] = task.get_current_directory_name();if (!ret) {std::cerr << "Error: failed to get current directory name: " << curr_dir_name << std::endl;return -1;}cv::imwrite(curr_dir_name + "/" + task.get_local_time() + ".png", frame);start_time = current_time;}cv::imshow(win_name, frame);if (cv::waitKey(1) == 27) // Esc exitbreak;}cap.release();}cv::destroyAllWindows();task.release();return 0;
}
执行结果如下图所示:

GitHub:https://github.com/fengbingchun/OpenCV_Test
相关文章:
计时器任务实现(保存视频和图像)
下面是一个简单的计时器任务实现,可持续地每秒保存一幅图像,也可持续地每60秒保存一个视频,图像和视频均以当前时间命名: TimerTask类的实现如下: class TimerTask { public:TimerTask(const std::string& path):…...
树莓百度百科能否揭开成都树莓集团的神秘面纱?
树莓百度百科作为大众获取信息的重要渠道,在一定程度上为人们了解树莓集团提供了窗口,但要完全揭开其神秘面纱,仍存在一定局限性。 从树莓百度百科上,我们能获取到关于树莓集团的基本信息,如公司的成立时间、法定代表人…...
【如何看懂数据手册和原理图】
【如何看懂数据手册和原理图】 文章目录 【如何看懂数据手册和原理图】1.数据手册1.1去哪里看?1.2需要注意的 2.支路3.回路4.网孔5.电路定理:基尔霍夫定律**集总参数电路** 抽象理想化5.1基尔霍夫电流定律 (KCL)5.2基尔霍夫电压定律 (KVL)5.3总结 6.读懂…...
SQL 优化工具使用之 explain 详解
一、导读 对于大部分开发人员来说,平常接触的无非就是增删改查这些基本操作,创建存储过程,视图等等都是 DBA 该干的活,但是想要把这些基本操作写的近乎完美也是一件难事。 而 explain 显示了 MySQL 如何使用索引来处理 select 语…...
深度解析Unity3D渲染管线:网格、材质与GPU渲染的协同逻辑
在3D实时渲染领域,网格(Mesh)、材质(Material)和GPU渲染三者构成了虚拟世界的基石。它们如同乐高积木的零件,通过精确的协作,最终在屏幕上呈现出复杂的视觉场景。本文将从技术原理、协作机制到性…...
POI优化Excel录入
57000单词原始录入时间258S 核心代码: List<Word> wordBookList ExcelUtil.getReader(file.getInputStream()).readAll(Word.class);if (!CollectionUtil.isEmpty(wordBookList)) {for (Word word : wordBookList) {//逐条向数据库中插入单词wordMapper.insert(word);}…...
实时图像与视频超分辨率:高效子像素卷积网络(ESPCN)解析
文章目录 概要理论知识操作实操环境配置基础命令格式:效果示例 概要 超分辨率系列论文阅读卷1:Real-Time Single Image and Video Super-Resolution Using an Efficient Sub-Pixel Convolutional Neural Network PDF网址:https://arxiv.org/…...
QT--对话框的切换
文章目录 前言一、主窗口ui二、创建子窗口三、步骤1.主界面------>子页面2.子界面------>主页面 四、总结 前言 之前我们学了qt中最重要的东西–信号和槽 我们现在实现这样一个demo,程序启动后弹出主界面,点击主界面的按钮弹出子窗口,…...
深入浅出:CUDA是什么,如何利用它进行高效并行计算
在当今这个数据驱动的时代,计算能力的需求日益增加,特别是在深度学习、科学计算和图像处理等领域。为了满足这些需求,NVIDIA推出了CUDA(Compute Unified Device Architecture),这是一种并行计算平台和编程模…...
Zotero PDF Translate插件配置百度翻译api
Zotero PDF Translate插件可以使用几种翻译api,虽然谷歌最好用,但是由于众所周知的原因,不稳定。而cnki有字数限制,有道有时也不行。其他的翻译需要申请密钥。本文以百度为例,进行申请 官方有申请教程: Zot…...
利用acme.sh 申请 Google 免费证书
1.Google API权限准备 获取 EAB 密钥 ID 和 HMAC 登录你的 GCP 控制台面板,进入 Public Certificate Authority API 管理页面(https://console.cloud.google.com/apis/library/publicca.googleapis.com)点击启动: 或者直接在下一…...
腾讯云cloudstudio使用笔记(一)
0、计划及目标 1)、这个系列用于将cloudstudio快速入门将前端代码在cloudstudio中从git仓库拉下来并运行—本文档的目标已实现 2)、基于cloudstudio和腾讯的ai代码助手腾讯自己满血的deepseek写代码,减少前端工作量—待补充 3)、…...
python自动化制作常规的日报数据可视化
python自动化制作常规的日报数据可视化 作者:i阿极 作者简介:Python领域新星作者、多项比赛获奖者:博主个人首页 😊😊😊如果觉得文章不错或能帮助到你学习,可以点赞👍收藏Ǵ…...
C语言:在主函数中输入十个等长的字符串。用另一函数对它们排序,然后在主函数输出这10个已排好序的字符串。
(1)用字符型二维数组 #include <stdio.h> #include <string.h> int main() {void sort(char s[][6]);int i;char str[10][6];printf("input 10 strings:\n");for (i0;i<10;i)scanf("%s",str[i]);sort(str);printf(&…...
构建高效智能对话前端:基于Ant Design X 的deepseek对话应用
文章目录 实现的效果前言Ant Design X添加欢迎组件创建对话气泡存储对话历史渲染对话气泡 输入组件WebSocket 连接总结 实现的效果 待机页面: 等待页面: 完成页面: 前言 随着人工智能技术的飞速发展,大模型对话系统已成为…...
SQLMesh 系列教程5- 详解SQL模型
本文将详细介绍 SQLMesh 的 SQL 模型组成要素及其在实际项目中的应用。SQLMesh 是一个强大的数据工程工具,其 SQL 模型由 MODEL DDL、预处理语句、主查询、后处理语句以及可选的 ON VIRTUAL UPDATE 语句组成。我们将通过一个电商平台每日销售报告的实例,…...
本地DeepSeek模型GGUF文件转换为PyTorch格式
接前文,我们在本地Windows系统上,基于GGUF文件部署了DeepSeek模型(DeepSeek-R1-Distill-Qwen-1.5B.gguf版本),但是GGUF是已经量化的版本,我们除了对其进行微调之外,无法对其训练,那么还有没有其他办法对本地的GGUF部署的DeepSeek模型进行训练呢?今天我们就反其道而行之…...
Flutter:动态表单(在不确定字段的情况下,生成动态表单)
关于数据模型:模型就是一种规范约束,便于维护管理,在不确定表单内会出现什么数据时,就没有模型一说。 这时就要用到动态表单(根据接口返回的字段,生成动态表单) 1、观察数据格式,定义…...
【Python项目】文本相似度计算系统
【Python项目】文本相似度计算系统 技术简介:采用Python技术、Django技术、MYSQL数据库等实现。 系统简介:本系统基于Django进行开发,包含前端和后端两个部分。前端基于Bootstrap框架进行开发,主要包括系统首页,文本分…...
C# ref 和 out 的使用详解
总目录 前言 在 C# 编程中,ref 和 out 是两个非常重要的关键字,它们都用于方法参数的传递,但用途和行为却有所不同。今天,我们就来深入探讨一下这两个关键字的用法和区别,让你在编程中能够得心应手地使用它们。 一、什…...
剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...
Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...
【JavaSE】绘图与事件入门学习笔记
-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角,以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向,距离坐标原点x个像素;第二个是y坐标,表示当前位置为垂直方向,距离坐标原点y个像素。 坐标体系-像素 …...
【JavaSE】多线程基础学习笔记
多线程基础 -线程相关概念 程序(Program) 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存…...
STM32HAL库USART源代码解析及应用
STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...
省略号和可变参数模板
本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...
[ACTF2020 新生赛]Include 1(php://filter伪协议)
题目 做法 启动靶机,点进去 点进去 查看URL,有 ?fileflag.php说明存在文件包含,原理是php://filter 协议 当它与包含函数结合时,php://filter流会被当作php文件执行。 用php://filter加编码,能让PHP把文件内容…...
毫米波雷达基础理论(3D+4D)
3D、4D毫米波雷达基础知识及厂商选型 PreView : https://mp.weixin.qq.com/s/bQkju4r6med7I3TBGJI_bQ 1. FMCW毫米波雷达基础知识 主要参考博文: 一文入门汽车毫米波雷达基本原理 :https://mp.weixin.qq.com/s/_EN7A5lKcz2Eh8dLnjE19w 毫米波雷达基础…...
安卓基础(Java 和 Gradle 版本)
1. 设置项目的 JDK 版本 方法1:通过 Project Structure File → Project Structure... (或按 CtrlAltShiftS) 左侧选择 SDK Location 在 Gradle Settings 部分,设置 Gradle JDK 方法2:通过 Settings File → Settings... (或 CtrlAltS)…...
