当前位置: 首页 > 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;让你在编程中能够得心应手地使用它们。 一、什…...

超短脉冲激光自聚焦效应

前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应&#xff0c;这是一种非线性光学现象&#xff0c;主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场&#xff0c;对材料产生非线性响应&#xff0c;可能…...

DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径

目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

关于nvm与node.js

1 安装nvm 安装过程中手动修改 nvm的安装路径&#xff0c; 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解&#xff0c;但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后&#xff0c;通常在该文件中会出现以下配置&…...

C++八股 —— 单例模式

文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全&#xff08;Thread Safety&#xff09; 线程安全是指在多线程环境下&#xff0c;某个函数、类或代码片段能够被多个线程同时调用时&#xff0c;仍能保证数据的一致性和逻辑的正确性&#xf…...

逻辑回归暴力训练预测金融欺诈

简述 「使用逻辑回归暴力预测金融欺诈&#xff0c;并不断增加特征维度持续测试」的做法&#xff0c;体现了一种逐步建模与迭代验证的实验思路&#xff0c;在金融欺诈检测中非常有价值&#xff0c;本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...

论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing

Muffin 论文 现有方法 CRADLE 和 LEMON&#xff0c;依赖模型推理阶段输出进行差分测试&#xff0c;但在训练阶段是不可行的&#xff0c;因为训练阶段直到最后才有固定输出&#xff0c;中间过程是不断变化的。API 库覆盖低&#xff0c;因为各个 API 都是在各种具体场景下使用。…...

区块链技术概述

区块链技术是一种去中心化、分布式账本技术&#xff0c;通过密码学、共识机制和智能合约等核心组件&#xff0c;实现数据不可篡改、透明可追溯的系统。 一、核心技术 1. 去中心化 特点&#xff1a;数据存储在网络中的多个节点&#xff08;计算机&#xff09;&#xff0c;而非…...

面试高频问题

文章目录 &#x1f680; 消息队列核心技术揭秘&#xff1a;从入门到秒杀面试官1️⃣ Kafka为何能"吞云吐雾"&#xff1f;性能背后的秘密1.1 顺序写入与零拷贝&#xff1a;性能的双引擎1.2 分区并行&#xff1a;数据的"八车道高速公路"1.3 页缓存与批量处理…...

接口 RESTful 中的超媒体:REST 架构的灵魂驱动

在 RESTful 架构中&#xff0c;** 超媒体&#xff08;Hypermedia&#xff09;** 是一个核心概念&#xff0c;它体现了 REST 的 “表述性状态转移&#xff08;Representational State Transfer&#xff09;” 的本质&#xff0c;也是区分 “真 RESTful API” 与 “伪 RESTful AP…...

2025 后端自学UNIAPP【项目实战:旅游项目】7、景点详情页面【完结】

1、获取景点详情的请求【my_api.js】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口&#xff08;适配服务端返回 Token&#xff09; export const login async (code, avatar) > {const res await http(/login/getWXSessionKey, {code,avatar}); };//…...