Opencv把用于操作系统、文件系统以及摄像机等硬件设备交互的函数纳入到highgui(High-level Graphical User Interface)模块中,我们可以利用该模块方便地打开窗口、显示图像、读出或写入图像相关的文件(图像和视频)、处理简单的鼠标点击、鼠标移动和键盘事件等等众多功能。
图像的载入与保存
使用cv::imread()读取图片
cv::imread():
cv::Mat cv::imread(
const string &filename, //Input filename
int flags=cv::IMREAD_COLOR //Flags set how to interpret file
};
默认情况下,flags被设置为cv::IMREAD_COLOR,这个值表示图片将被以三通道8位的格式读取,在这种情况下,即使原始文件中的图像是灰度图像,读取到内存中的仍然有三通道,每个通道拥有相同数据的图像。
如果flags被设置为cv::IMREAD_GRAYSCALE,那么不管文件内部图像是几通道的,图片都以灰度图像的格式加载。
flags的另外一个值是cv::IMREAD_ANYCOLOR,在此种情况下,图片的载入方式取决于其内部图像的具体情况,如果是彩色图像,就以三通道的形式载入,如果是灰度图像,则按单通道的形式载入。
cv::IMREAD_COLOR | 总是读取三通道图像 |
cv::IMREAD_GRAYSCALE | 总是读取单通道图像 |
cv::IMREAD_ANYCOLOR | 通道数由文件实际通道数决定(不超过3) |
cv::IMREAD_ANYDEPTH | 允许加载超过8bit深度 |
cv::IMREAD_UNCHANGED | 读取图像时,将保留图像中的alpha通道 |
#include<iostream>
#include<opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat src= imread("C:\\Users\\32498\\Pictures\\17.png",IMREAD_COLOR);//IMREAD_COLOR 三通道读取
imshow("src", src);
Mat src_gray = imread("C:\\Users\\32498\\Pictures\\17.png", IMREAD_GRAYSCALE);//IMREAD_GRAYSCALE 单通道读取
imshow("src_gray", src_gray);
waitKey();
}
运行结果如下
以不同的方式读取同一幅图片,得到不同的结果。
使用cv::imwrite()保存图像
cv::imwrite()有三个输入参数
bool cv::imwrite(
const string& filename, //Input filename
cv::InputArray image, //image to write to file
const vector<int>& params = vector<int>() //optional for parameterized fmts
)
第一个参数给定了文件名,文件名的拓展部分用来决定以何种格式保存图像(比如常见的.jpg .png .tif .bmp等格式)
第二个参数是待存储的输入图像
第三个参数被用作特殊类型文件的写入操作时所需的数据
我们在前一个程序的基础上再增加一行语句,保存图片
imwrite("test.png", src);
#include<iostream>
#include<opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat src= imread("C:\\Users\\32498\\Pictures\\17.png",IMREAD_COLOR);//IMREAD_COLOR 三通道读取
imshow("src", src);
Mat src_gray = imread("C:\\Users\\32498\\Pictures\\17.png", IMREAD_GRAYSCALE);//IMREAD_GRAYSCALE 单通道读取
imshow("src_gray", src_gray);
imwrite("test.png", src);
waitKey();
}
最终我们就把这张图片保存了下来,那么保存在哪里呢?
就在当前程序的文件夹里面
当然也可以使用绝对路径设置图片要保存的地方,比如我们这里将路径设置为
imwrite("C:\\Users\\32498\\Pictures\\test.png", src);
就可以将图片保存到这个路径下,
视频的处理
使用cv::VideoCapture对象读取视频流
首先我们需要一个cv::VideoCapture对象 ,它包含我们从摄像机或者视频文件读取每一帧所必需的信息,根据数据源的不同,我们需要以不同的调用方式来构建cv::VideoCapture对象:
cv::videoCapture::videoCapture(
cosnt string& filename //Input filename
);
cv::videoCapture::videoCapture(
int device // video capture device id
);
cv::videoCapture::videoCapture();
在第一个构造函数中,只需要给出视频文件的文件名就可以了,opencv会自动打开对应的视频文件,并准备后续的读取操作 。如果打开成功,那么便可以从中获取图像帧,成员函数cv::VideoCapture::isOpened()会返回true。
输入参数为整型变量的cv::VideoCapture::VideoCapture()函数,即就是第二种构造函数,我们给出一个标识符来表明我们希望使用哪个摄像机以及我们希望操作系统以何种方式与该摄像机通信。对于摄像机来说,它只是一个标识码,如果当前系统下只有以恶搞摄像机时参数为0,当有多个摄像机同时处于当前系统中时,参数递增即可。在某些平台上,你可以给cv::VideoCapture::VideoCapture()函数传入-1,这会使OpenCV弹出一个选择窗口,让你能够手动选择希望使用的相机。
创建VideoCapture()对象的最后一种方式是直接创建一个VideoCapture对象而不提供关于即将打开的硬件设备的任何信息。
cv::VideoCapture cap;
cap.open("test.avi");
这种情况下,虽然会创建一个VideoCapture对象,但无法直接使用,直到显式打开你想要读取数据的视频源。
使用cv::VideoCapture::read()从视频流中读取图像
bool cv::VideoCapture::read(
cv::OutputArray image
);
一旦有了一个cv::VideoCapture对象,便可以从中读取图像了,最简单的一种方式是调用cv::VideoCapture::read()函数,该函数从cv::VideoCapture表示的文件中读取下一帧数据,并将数据插入到你提供的变量中。
使用cv::VideoCapture::operator>>()从视频流读取图像数据
cv::VideoCapture& cv::VideoCapture::operator>>(
cv::Mat &image
);
也可以使用重载函数 cv::VideoCapture& cv::VideoCapture::operator>>()(输入流操作符)从VideoCapture对象中读取下一帧数据。
使用cv::VideoCapture::grab()和cv::VideoCapture::retrieve()从视频流中读取图像数据
为了取代上述的一次从相机或者视频源只读取一张图像并完成解码的操作,你可以将其拆分为一个捕获操作(类似于内存的拷贝)和恢复操作(用于实际完成对已抓取的数据进行解码)
bool cv::VideoCapture::grab(void);
bool cv::VideoCapture::retrieve(
cv::OutputArray image,
int channel=0
);
grab()函数将当前可以使用的图像数据拷贝至用户看不到的一个内部缓冲区。先完成数据的抓取(grab),将数据安全放入缓存区之后再进行解码恢复(retrieve),这样做十分有意义。因为在多相机读取时,需要尽可能缩短多个相机获取的图像帧之间的时间差。
相机属性cv::VideoCapture::get()和cv::VideoCapture::set()
视频文件通常不仅仅包含一帧一帧的图像,还包括许多重要的元数据,当打开一个视频文件时,相关信息就会被拷贝到cv::VideoCapture对象内部数据区,如果能够实现对该数据区参数的读取或者写入将会非常有用,这两个函数就帮我们实现了。