计时器任务实现(保存视频和图像)
下面是一个简单的计时器任务实现,可持续地每秒保存一幅图像,也可持续地每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 是两个非常重要的关键字,它们都用于方法参数的传递,但用途和行为却有所不同。今天,我们就来深入探讨一下这两个关键字的用法和区别,让你在编程中能够得心应手地使用它们。 一、什…...
利用最小二乘法找圆心和半径
#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...
【Oracle APEX开发小技巧12】
有如下需求: 有一个问题反馈页面,要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据,方便管理员及时处理反馈。 我的方法:直接将逻辑写在SQL中,这样可以直接在页面展示 完整代码: SELECTSF.FE…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...
LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...
HBuilderX安装(uni-app和小程序开发)
下载HBuilderX 访问官方网站:https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本: Windows版(推荐下载标准版) Windows系统安装步骤 运行安装程序: 双击下载的.exe安装文件 如果出现安全提示&…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...
【C++进阶篇】智能指针
C内存管理终极指南:智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...
加密通信 + 行为分析:运营商行业安全防御体系重构
在数字经济蓬勃发展的时代,运营商作为信息通信网络的核心枢纽,承载着海量用户数据与关键业务传输,其安全防御体系的可靠性直接关乎国家安全、社会稳定与企业发展。随着网络攻击手段的不断升级,传统安全防护体系逐渐暴露出局限性&a…...
