Opencv把用于操作系统、文件系统以及摄像机等硬件设备交互的函数纳入到highgui(High-level Graphical User Interface)模块中,我们可以利用该模块方便地打开窗口、显示图像、读出或写入图像相关的文件(图像和视频)、处理简单的鼠标点击、鼠标移动和键盘事件等等众多功能。
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
#include
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()有三个输入参数
bool cv::imwrite(
const string& filename, //Input filename
cv::InputArray image, //image to write to file
const vector& params = vector() //optional for parameterized fmts
)
第一个参数给定了文件名,文件名的拓展部分用来决定以何种格式保存图像(比如常见的.jpg .png .tif .bmp等格式)
第二个参数是待存储的输入图像
第三个参数被用作特殊类型文件的写入操作时所需的数据
我们在前一个程序的基础上再增加一行语句,保存图片
imwrite("test.png", src);
#include
#include
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::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对象,但无法直接使用,直到显式打开你想要读取数据的视频源。
bool cv::VideoCapture::read(
cv::OutputArray image
);
一旦有了一个cv::VideoCapture对象,便可以从中读取图像了,最简单的一种方式是调用cv::VideoCapture::read()函数,该函数从cv::VideoCapture表示的文件中读取下一帧数据,并将数据插入到你提供的变量中。
cv::VideoCapture& cv::VideoCapture::operator>>(
cv::Mat &image
);
也可以使用重载函数 cv::VideoCapture& cv::VideoCapture::operator>>()(输入流操作符)从VideoCapture对象中读取下一帧数据。
为了取代上述的一次从相机或者视频源只读取一张图像并完成解码的操作,你可以将其拆分为一个捕获操作(类似于内存的拷贝)和恢复操作(用于实际完成对已抓取的数据进行解码)
bool cv::VideoCapture::grab(void);
bool cv::VideoCapture::retrieve(
cv::OutputArray image,
int channel=0
);
grab()函数将当前可以使用的图像数据拷贝至用户看不到的一个内部缓冲区。先完成数据的抓取(grab),将数据安全放入缓存区之后再进行解码恢复(retrieve),这样做十分有意义。因为在多相机读取时,需要尽可能缩短多个相机获取的图像帧之间的时间差。
视频文件通常不仅仅包含一帧一帧的图像,还包括许多重要的元数据,当打开一个视频文件时,相关信息就会被拷贝到cv::VideoCapture对象内部数据区,如果能够实现对该数据区参数的读取或者写入将会非常有用,这两个函数就帮我们实现了。
HighGUI的图形用户输入工具只支持三个基本的交互、即按键、鼠标在图像区域点击、鼠标滚轮
首先我们想用HighGUI在屏幕上创建一个窗口并显示图像。cv::namedWindow()可以完成这一功能,它需要一个窗口的名称和一个标识符flag作为参数输入,标识符flag用于表示窗口是否需要自动调整大小来适应我们输入的图像的大小,完整的函数定义如下
int cv::namedWindow(
const string& name, //handle used to identify window
int flags = 0 //tell window to autosize
);
flag可以设置为0(默认值)WINDOW_NORMAL,表示用户可以调整窗口的大小。
#include
#include
using namespace std;
using namespace cv;
int main()
{
Mat src= imread("C:\\Users\\32498\\Pictures\\17.png");
namedWindow("src", WINDOW_NORMAL);//用户可以改变窗口大小
imshow("src", src);
Mat src1 = imread("C:\\Users\\32498\\Pictures\\R-C(3).jpg");
namedWindow("src1", 0);//用户可以改变窗口大小
imshow("src1", src1);
waitKey();
}
图中左上角出现红框内的双向箭头表示我们可以通过鼠标来控制图片的大小,对图片进行伸缩。
或设置为cv::WINDOW_AUTOSIZE,此时加载不同的图像时,HighGUI会自动对窗口大小进行自适应调整,但是用户不能调整窗口。例如这样一段代码
#include
#include
using namespace std;
using namespace cv;
int main()
{
Mat src= imread("C:\\Users\\32498\\Pictures\\17.png");
namedWindow("src", WINDOW_AUTOSIZE);//用户不可以改变窗口大小
imshow("src", src);
Mat src1 = imread("C:\\Users\\32498\\Pictures\\R-C(3).jpg");
namedWindow("src1", WINDOW_AUTOSIZE);//用户不可以改变窗口大小
imshow("src1", src1);
waitKey();
}
我们使用了WINDOW_AUTOSIZE作为flag, 加载不同的图像时,HighGUI会自动对窗口大小进行自适应调整
可以看到它会根据图片大小自动调整窗口(但是我们不能通过鼠标改变图片的大小)。
当然flag还有其他的值,有需要的话大家可以自己去尝试用一下
通过创建窗口,我们可以放置一些东西在里面。加入我们现在不需要一个窗口,如何销毁一个窗口,也很简单使用函数cv::destoryWindow(),它只有一个参数,就是创建窗口时给窗口指定的名称。
int cv::destoryWindow(
const string& name,
)
通过imshow()函数可以加载一张图片到窗口,方便我们在窗口中查看和欣赏图像
void cv::imshow(
const string &name,
cv::InputArray image
);
第一个参数是我们将要用来展示窗口的名称,第二个参数是将要展示的图像。
注意如果我们只是写了如下代码想用来欣赏一幅图像的话,那很不幸地你会看到这幅图像在屏幕上一闪而过,并不会停留,
#include
#include
using namespace std;
using namespace cv;
int main()
{
Mat src= imread("C:\\Users\\32498\\Pictures\\17.png");
imshow("src", src);
}
为什么呢?在这段代码后面还需要加上一句代码,这样我们才能愉快的观察图片,需要加的代码就是我们下面即将学习的waitKey()函数
cv::waitKey()函数是用于对键盘事件进行特定时长的等待。
int cv::waitKey(
int delay=0
);
这个函数接受一个参数delay,这是在自动返回之前等待按键的时间量(以毫秒为单位),如果延迟设为0,cv::waitKey()将无限期地等待按键。这样我们要显示的图片就会一直停留在屏幕上供我们欣赏。
#include
#include
using namespace std;
using namespace cv;
int main()
{
Mat src= imread("C:\\Users\\32498\\Pictures\\17.png");
imshow("src", src);
waitKey(0);
}
如果设置为waitKey(300),这张图片就会在屏幕上停留300毫秒然后程序会结束,图片也会消失。
如果在延迟毫秒时间之前没有按键输入,cv::waitKey()将返回-1。
通过上面的学习,我们已经能在图片上显示一幅图像了,现在我们再介绍一个函数
void cv::moveWindow(const char*name,int x,int y);
这个函数是用于对窗口在屏幕上进行简单移动,使得窗口的左上角坐标位于(x,y)点,比如
#include
#include
using namespace std;
using namespace cv;
int main()
{
Mat src= imread("C:\\Users\\32498\\Pictures\\17.png");
namedWindow("src1", 0);
moveWindow("src", 1200, 1200);
imshow("src1", src);
namedWindow("src2", 0);
imshow("src2", src);
moveWindow("src", 800, 800);
waitKey(0);
}
我们可以看到通过设置moveWindow()函数设置坐标(x,y),同一幅图被显示在屏幕的不同位置 。