概述
RoboMaster视觉教程OpenCV(三)利用文件处理图像
上一次的代码中,我们使用了一个字符串数组来达到写入多个图像而不覆盖的目的。但是仔细想想我们就可以知道每一次程序执行,整型变量还是会从零开始。那么也就是说,虽然第一次程序执行的期间能够不断迭代生成多个图像,但是当程序第二次启动第三次启动时,生成的图像会覆盖上一次程序执行期间生成的图像,因为文件名是一样的。
但是在Robomaster比赛中,我们要使用的嵌入式平台不断的自动开机和关机,如果轻易覆盖掉保存好的文件,那么我们想在热身赛获得的场地信息就可能丢失。如何达到每一次自启动都能够生成新的图片,而不覆盖上一次程序执行的图片呢?这里就需要用到文件。文件储存图片的数字,断电后也能够保存。程序一旦上电,读到的图片路径不再来自于局部变量,而是储存空间内的文件。
本节我们使用的标准C++中的文件操作。略微繁琐。之后我们还会学习Qt,利用QFile达到我们的目的,更加方便。我个人喜欢使用Qt提供的各种方便的类。
文章目录
- RoboMaster视觉教程OpenCV(三)利用文件处理图像
- 一 基本概念
- 二 操作文件保存图像
- 三 代码解析
- 3.1 main()函数
- 3.2 saveVideos()
- 3.3 initVideoWriter()
- 3.4 auto
- 四 今日任务
一 基本概念
阅读任意网课、教科书等资料中的文件读取写入内容。比如中国大学慕课的郭炜老师的讲授。
https://www.icourse163.org/course/PKU-1002029030
学习第七周的3.4节
二 操作文件保存图像
-
首先在程序所在当前目录下,创建一个video文件夹(必须手动,否则找不到路径,png、avi文件可以在程序写入时自动创建,文件夹不可以)
-
在工程目录下实现创建一个文件夹,名为video
-
将以下代码命名为
file-video.cpp
-
利用该命令编译运行
g++ -std=c++11 -o file-video file-video.cpp `pkg-config --libs --cflags opencv`
这次使用g++编译时,加上-std=c++11,因为to_string等是11的新特性(我的笔记本不加-std=c++11就报错,有的人不报错,懵)
#include <iostream>
#include "opencv2/opencv.hpp"
#include <fstream>
using namespace std;
using namespace cv;
#define SAVEVIDEO 1//宏定义,控制
void saveVideos(const cv::Mat &frame);//函数以及对象如何声明
cv::VideoWriter initVideoWriter(const std::string &filename_prefix);
auto save_video = initVideoWriter("./video/");//auto声明必须初始化//需要事先创建一个文件夹
int main(int argc, char** argv)
{
//打开第一个摄像头
VideoCapture cap(0);//
if(!cap.isOpened())
{
cerr << "Can not open a camera or file." << endl;//cerr not cout
return -1;
}
Mat frame;
for(;;)
{
//从 cap 中读一帧,存到 frame
cap >> frame;
if(frame.empty())
break;
imshow("pictures", frame);
if (SAVEVIDEO) saveVideos(frame);
//等待 30 秒,如果按键则推出循环
if(waitKey(30) >= 0)
break;
}
//退出时会自动释放 cap 中占用资源
return 0;
}
void saveVideos(const cv::Mat &frame) {
if (!frame.empty()) {
save_video.write(frame);//video_writer << frame;
} else return;
}
cv::VideoWriter initVideoWriter(const std::string &filename_prefix) {
cv::VideoWriter video;
std::ifstream in(filename_prefix + "cnt.txt");
int cnt = 0;
if (in.is_open()) {
in >> cnt;
in.close();
}
std::string file_name = filename_prefix + std::to_string(cnt) + ".avi";
cnt++;
std::ofstream out(filename_prefix + "cnt.txt");
if (out.is_open()) {
out << cnt << std::endl;
out.close();
}
video.open(file_name, CV_FOURCC('P', 'I', 'M', '1'), 24, cv::Size(640, 480));//video(file_name, CV_FOURCC('P', 'I', 'M', '1'), 90, cv::Size(640, 480));
return video;
}
三 代码解析
保存视频主要是有两个大知识点,一个是打开和关闭文件,写入或者读取文件中的整型数字。另一个是将文件中的整型数字和视频的路径(filename)结合起来。之后将filename作为参数传到VideoWriter类的对象initVideoWriter()。
3.1 main()函数
主函数的内容并不多,也不复杂。主要功能是打开摄像头,并读取一帧显示,然后将这个帧传给子函数saveVideos()中。
3.2 saveVideos()
saveVideos()函数中的代码很简单,就是将从摄像头捕获的一帧利用VideoWriter类的对象保存成为视频。那么,这个VideoWriter类的对象是哪里来的呢?是一个函数,initVideoWriter()传回来的。
3.3 initVideoWriter()
这个initVideoWriter()是一个函数,只不过这个函数的返回值是一个VideoWriter类的对象。在这个函数里,它读取了文件中的整型数字,将文件中的整型数字和视频的路径(filename)结合起来。之后初始化了一个VideoWriter类的对象。把这个类传给了saveVideos()函数。
此外,对于文件的输入及输出是相对于程序来说的。程序读取文件中的数字,对于程序来说是输入也就是in。5257行,读取文件数字,与6063行写法类似。
对于string类型的路径,学习一下to_string()以及互相之间的加减用法。
3.4 auto
代码中11行完成了对于这个VideoWriter类的对象到初始化。不过比较奇特的是,它使用了一个auto变量。这个变量是C++的新特性。他在这里的作用仅仅是为了能够自动获取到后面变量的类型,可以少些几个字。如果不用auto的话,可以将类型直接写为cv::VideoWriter。
auto拓展阅读:https://www.cnblogs.com/KunLunSu/p/7861330.html
四 今日任务
打开摄像头,从摄像头处读取帧,每一帧都显示,但是每200帧保存一帧为png图片,图片的名称从文件中查找。能够实现开机重启后不会覆盖图片的功能。
((为什么每200帧保存一帧?如果每一帧都保存的话,保存的文件会太多。所以读取200帧,虽然两百帧都显示,但是199帧显示完毕就不再管,只保存其中一帧。
可以在极短时间内运行一下程序,看看程序运行起来是多么快,类似manifold这样的平台,配上工业相机,帧率可达100帧。这时候这个保存间隔可以设置为20000帧)
PS:不建议不断打开关闭文件。这里只是一个自己学习玩乐的任务。另外,这里用的是一个很粗略的延时,利用计数,建议使用OpenCV自带的获取FPS的函数,再获取系统时间来实现精确延时。(比如每秒保存一张图)
微信公众号欢迎大家关注我的个人公众号,现阶段主要总结Robomaster相关的计算机视觉知识。
公众号名称:三丰杂货铺
最后
以上就是漂亮哑铃为你收集整理的RoboMaster视觉教程OpenCV(三)利用文件处理图像RoboMaster视觉教程OpenCV(三)利用文件处理图像的全部内容,希望文章能够帮你解决RoboMaster视觉教程OpenCV(三)利用文件处理图像RoboMaster视觉教程OpenCV(三)利用文件处理图像所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复