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

计时器任务实现(保存视频和图像)

      下面是一个简单的计时器任务实现,可持续地每秒保存一幅图像,也可持续地每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

相关文章:

计时器任务实现(保存视频和图像)

下面是一个简单的计时器任务实现&#xff0c;可持续地每秒保存一幅图像&#xff0c;也可持续地每60秒保存一个视频&#xff0c;图像和视频均以当前时间命名&#xff1a; TimerTask类的实现如下&#xff1a; class TimerTask { public:TimerTask(const std::string& path):…...

树莓百度百科能否揭开成都树莓集团的神秘面纱?

树莓百度百科作为大众获取信息的重要渠道&#xff0c;在一定程度上为人们了解树莓集团提供了窗口&#xff0c;但要完全揭开其神秘面纱&#xff0c;仍存在一定局限性。 从树莓百度百科上&#xff0c;我们能获取到关于树莓集团的基本信息&#xff0c;如公司的成立时间、法定代表人…...

【如何看懂数据手册和原理图】

【如何看懂数据手册和原理图】 文章目录 【如何看懂数据手册和原理图】1.数据手册1.1去哪里看&#xff1f;1.2需要注意的 2.支路3.回路4.网孔5.电路定理&#xff1a;基尔霍夫定律**集总参数电路** 抽象理想化5.1基尔霍夫电流定律 (KCL)5.2基尔霍夫电压定律 (KVL)5.3总结 6.读懂…...

SQL 优化工具使用之 explain 详解

一、导读 对于大部分开发人员来说&#xff0c;平常接触的无非就是增删改查这些基本操作&#xff0c;创建存储过程&#xff0c;视图等等都是 DBA 该干的活&#xff0c;但是想要把这些基本操作写的近乎完美也是一件难事。 而 explain 显示了 MySQL 如何使用索引来处理 select 语…...

深度解析Unity3D渲染管线:网格、材质与GPU渲染的协同逻辑

在3D实时渲染领域&#xff0c;网格&#xff08;Mesh&#xff09;、材质&#xff08;Material&#xff09;和GPU渲染三者构成了虚拟世界的基石。它们如同乐高积木的零件&#xff0c;通过精确的协作&#xff0c;最终在屏幕上呈现出复杂的视觉场景。本文将从技术原理、协作机制到性…...

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)解析

文章目录 概要理论知识操作实操环境配置基础命令格式&#xff1a;效果示例 概要 超分辨率系列论文阅读卷1&#xff1a;Real-Time Single Image and Video Super-Resolution Using an Efficient Sub-Pixel Convolutional Neural Network PDF网址&#xff1a;https://arxiv.org/…...

QT--对话框的切换

文章目录 前言一、主窗口ui二、创建子窗口三、步骤1.主界面------>子页面2.子界面------>主页面 四、总结 前言 之前我们学了qt中最重要的东西–信号和槽 我们现在实现这样一个demo&#xff0c;程序启动后弹出主界面&#xff0c;点击主界面的按钮弹出子窗口&#xff0c;…...

深入浅出:CUDA是什么,如何利用它进行高效并行计算

在当今这个数据驱动的时代&#xff0c;计算能力的需求日益增加&#xff0c;特别是在深度学习、科学计算和图像处理等领域。为了满足这些需求&#xff0c;NVIDIA推出了CUDA&#xff08;Compute Unified Device Architecture&#xff09;&#xff0c;这是一种并行计算平台和编程模…...

Zotero PDF Translate插件配置百度翻译api

Zotero PDF Translate插件可以使用几种翻译api&#xff0c;虽然谷歌最好用&#xff0c;但是由于众所周知的原因&#xff0c;不稳定。而cnki有字数限制&#xff0c;有道有时也不行。其他的翻译需要申请密钥。本文以百度为例&#xff0c;进行申请 官方有申请教程&#xff1a; Zot…...

利用acme.sh 申请 Google 免费证书

1.Google API权限准备 获取 EAB 密钥 ID 和 HMAC 登录你的 GCP 控制台面板&#xff0c;进入 Public Certificate Authority API 管理页面&#xff08;https://console.cloud.google.com/apis/library/publicca.googleapis.com&#xff09;点击启动&#xff1a; 或者直接在下一…...

腾讯云cloudstudio使用笔记(一)

0、计划及目标 1&#xff09;、这个系列用于将cloudstudio快速入门将前端代码在cloudstudio中从git仓库拉下来并运行—本文档的目标已实现 2&#xff09;、基于cloudstudio和腾讯的ai代码助手腾讯自己满血的deepseek写代码&#xff0c;减少前端工作量—待补充 3&#xff09;、…...

python自动化制作常规的日报数据可视化

python自动化制作常规的日报数据可视化 作者&#xff1a;i阿极 作者简介&#xff1a;Python领域新星作者、多项比赛获奖者&#xff1a;博主个人首页 &#x1f60a;&#x1f60a;&#x1f60a;如果觉得文章不错或能帮助到你学习&#xff0c;可以点赞&#x1f44d;收藏&#x1f4…...

C语言:在主函数中输入十个等长的字符串。用另一函数对它们排序,然后在主函数输出这10个已排好序的字符串。

&#xff08;1&#xff09;用字符型二维数组 #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 连接总结 实现的效果 待机页面&#xff1a; 等待页面&#xff1a; 完成页面&#xff1a; 前言 随着人工智能技术的飞速发展&#xff0c;大模型对话系统已成为…...

SQLMesh 系列教程5- 详解SQL模型

本文将详细介绍 SQLMesh 的 SQL 模型组成要素及其在实际项目中的应用。SQLMesh 是一个强大的数据工程工具&#xff0c;其 SQL 模型由 MODEL DDL、预处理语句、主查询、后处理语句以及可选的 ON VIRTUAL UPDATE 语句组成。我们将通过一个电商平台每日销售报告的实例&#xff0c;…...

本地DeepSeek模型GGUF文件转换为PyTorch格式

接前文,我们在本地Windows系统上,基于GGUF文件部署了DeepSeek模型(DeepSeek-R1-Distill-Qwen-1.5B.gguf版本),但是GGUF是已经量化的版本,我们除了对其进行微调之外,无法对其训练,那么还有没有其他办法对本地的GGUF部署的DeepSeek模型进行训练呢?今天我们就反其道而行之…...

Flutter:动态表单(在不确定字段的情况下,生成动态表单)

关于数据模型&#xff1a;模型就是一种规范约束&#xff0c;便于维护管理&#xff0c;在不确定表单内会出现什么数据时&#xff0c;就没有模型一说。 这时就要用到动态表单&#xff08;根据接口返回的字段&#xff0c;生成动态表单&#xff09; 1、观察数据格式&#xff0c;定义…...

【Python项目】文本相似度计算系统

【Python项目】文本相似度计算系统 技术简介&#xff1a;采用Python技术、Django技术、MYSQL数据库等实现。 系统简介&#xff1a;本系统基于Django进行开发&#xff0c;包含前端和后端两个部分。前端基于Bootstrap框架进行开发&#xff0c;主要包括系统首页&#xff0c;文本分…...

C# ref 和 out 的使用详解

总目录 前言 在 C# 编程中&#xff0c;ref 和 out 是两个非常重要的关键字&#xff0c;它们都用于方法参数的传递&#xff0c;但用途和行为却有所不同。今天&#xff0c;我们就来深入探讨一下这两个关键字的用法和区别&#xff0c;让你在编程中能够得心应手地使用它们。 一、什…...

HSTracker:macOS炉石传说玩家的终极智能对战助手与套牌管理工具

HSTracker&#xff1a;macOS炉石传说玩家的终极智能对战助手与套牌管理工具 【免费下载链接】HSTracker A deck tracker and deck manager for Hearthstone on macOS 项目地址: https://gitcode.com/gh_mirrors/hs/HSTracker 对于macOS平台的《炉石传说》玩家来说&#…...

AI系统的“正确性”到底怎么定义?

很多团队第一次做 AI 应用测试时&#xff0c;都会遇到一个很尴尬的问题&#xff1a; 传统系统测对错&#xff0c;通常有明确答案。 接口返回状态码是不是 200&#xff1f; 金额计算是不是 99.99&#xff1f; 权限校验是不是拦住了非法用户&#xff1f; 数据库字段是不是落对了…...

解锁B站缓存视频:m4s-converter让你的收藏永不消失

解锁B站缓存视频&#xff1a;m4s-converter让你的收藏永不消失 【免费下载链接】m4s-converter 一个跨平台小工具&#xff0c;将bilibili缓存的m4s格式音视频文件合并成mp4 项目地址: https://gitcode.com/gh_mirrors/m4/m4s-converter 你是否遇到过精心收藏的B站视频突…...

别再为材质转换头疼了!3DMAX标准/Arnold材质转glTF PBR的保姆级教程

3DMAX材质转换终极指南&#xff1a;从标准/Arnold到glTF PBR的无损工作流 在三维内容创作领域&#xff0c;glTF格式已成为跨平台实时渲染的黄金标准。但许多资深3D美术师都经历过这样的困境&#xff1a;在3DMAX中精心调制的材质&#xff0c;通过Max2Babylon插件导出为glTF后&am…...

2026年计算机科学论文降AI工具推荐:算法研究和软件工程部分降AI指南

2026年计算机科学论文降AI工具推荐&#xff1a;算法研究和软件工程部分降AI指南 帮同学选过降AI工具&#xff0c;综合价格、效果、保障来看&#xff0c;推荐嘎嘎降AI&#xff08;www.aigcleaner.com&#xff09;。 4.8元&#xff0c;达标率99.26%&#xff0c;计算机论文降AI的…...

使用 Nodejs 和 Taotoken 为你的应用后端添加智能对话功能

使用 Nodejs 和 Taotoken 为你的应用后端添加智能对话功能 1. 准备工作 在开始集成 Taotoken 之前&#xff0c;需要确保你的开发环境已经具备以下条件。首先&#xff0c;确保 Node.js 版本在 16 或更高&#xff0c;这是大多数现代 JavaScript 特性的最低要求。其次&#xff0…...

WinClaw:Go语言实现的Windows轻量级自动化库实战指南

1. 项目概述&#xff1a;一个Windows环境下的轻量级自动化利器最近在折腾一些Windows环境下的自动化任务&#xff0c;比如批量重命名文件、定时清理日志、自动整理桌面截图&#xff0c;或者是一些需要重复点击的简单GUI操作。一开始想着用Python写脚本&#xff0c;但涉及到UI自…...

Claude被曝能“识破“基准测试:AI评估感知能力敲响安全警钟

当一台AI能稳定识别出自己正在被考核&#xff0c;甚至据此调整答题策略&#xff0c;我们不得不追问&#xff1a;现有的AI安全评估体系&#xff0c;究竟还能不能测出真实的"水位"&#xff1f; Anthropic最新披露的一项内部调查&#xff0c;正在整个AI安全圈掀起波澜。…...

完整指南:如何用开源AIOps平台Keep终结告警疲劳,实现智能运维自动化

完整指南&#xff1a;如何用开源AIOps平台Keep终结告警疲劳&#xff0c;实现智能运维自动化 【免费下载链接】keep The open-source AIOps and alert management platform 项目地址: https://gitcode.com/GitHub_Trending/kee/keep 面对海量告警信息却无从下手&#xff…...

ESP32-S2六路32A自锁继电器模块解析与应用

1. 项目概述&#xff1a;ESP32-S2六路32A自锁继电器模块 在智能家居和工业自动化领域&#xff0c;继电器控制模块一直是核心组件之一。最近我在项目中测试了一款名为"6Gang30AmpsLatchRelayEspHomeReady"的DIN导轨安装式ESP32-S2继电器模块&#xff0c;这个名称虽然冗…...