OpenCV 提供了用于读取各种图像文件类型以及视频和相机的函数。这些函数是名为HighGUI
的工具包的一部分。我们将使用其中的一些函数来创建一个简单的程序,该程序可以打开图像并将其显示在屏幕上
#include <opencv2/opencv.hpp>
int main(int argc, char const *argv[])
{
cv::Mat img = cv::imread(argv[1], -1);
if (img.empty())
{
return -1;
}
cv::namedWindow("Example1", cv::WINDOW_AUTOSIZE);
cv::imshow("Example1", img);
cv::waitKey(0);
cv::destroyAllWindows();
return 0;
}
请注意,OpenCV 函数包含于名为cv
的命名空间中。要调用 OpenCV 函数,必须通过将cv::
前缀添加到每个函数前。如果不想这么麻烦,我们可以使用using namespace cv;
指令,这会告诉编译器假设函数可能属于该名称空间。我们再写一个程序,注意这两个程序包含头文件的不同,我们只使用了必要的包含文件来缩短编译时间。
#include <opencv2/highgui/highgui.hpp>
int main(int argc, char const *argv[])
{
cv::Mat img = cv::imread(argv[1], -1);
if (img.empty())
return -1;
cv::namedWindow("Example2", cv::WINDOW_AUTOSIZE);
cv::imshow("Example2", img);
cv::waitKey(0);
cv::destroyWindow("Example2");
return 0;
}
编译并从命令行运行带有一个参数的命令时,程序会将图像显示在屏幕上。然后,它会一直等待,直到用户按下某个键,此时它会关闭窗口并退出。让我们逐行浏览程序,了解每个命令都在做些什么。
cv::Mat img = cv::imread( argv[1], -1 );
此行加载图像。函数cv::imread()
是基于文件名确定要加载的文件格式的函数;它还自动分配图像所需的内存。cv::imread()
可以读取多种图像格式,包括 BMP、DIB、JPEG、JPE、PNG、PBM、PGM、PPM、SR、RAS 和 TIFF。返回cv::Mat
类型的值。这种数据结构是最常见的 OpenCV 数据结构。OpenCV 使用此数据结构处理所有类型的图像:单通道、多通道、整数值、浮点值等等。紧随其后的一行:
if (img.empty())
return -1;
检查图像是否成功读取。另一个函数cv::namedWindow()
在屏幕上打开一个显示图像的窗口。
cv::namedWindow("Example2", cv::WINDOW_AUTOSIZE);
这个函数由 HighGUI 库提供,还为窗口指定名称(在本例中为"Example1"
)。将来与此窗口交互的 HighGUI 调用将使用此名称引用它。
cv::namedWindow()
的第二个参数定义窗口属性。它可以设置为0
(默认值)或cv::WINDOW_AUTOSIZE
。在前一种情况下,无论图像大小如何,窗口的大小都是相同的,并且图像将被缩放以适合窗口。在后一种情况下,当加载图像以适应图像的真实大小时,窗口将自动扩展或收缩。
cv::imshow("Example2", img);
只要cv::Mat
结构中有图像数据,就可以使用cv::imshow()
在现有窗口中显示它。如果窗口不存在(由cv::namedWindow()
创建),则cv::imshow()
函数会创建一个窗口。在调用cv::imshow()
时,将使用适当的大小重新绘制窗口,如果窗口是使用cv::WINDOW_AUTOSIZE
标志创建的,则窗口将根据需要调整自身大小。
cv::waitKey(0);
cv::waitKey()
函数要求程序停止并等待按键。如果给出了一个正整数参数,程序将等待该毫秒数,然后即使没有按任何键也会继续。如果参数设置为0或负数,程序将一直等待按键。
使用cv::Mat
数据结构时,图像在超出作用域时会自动销毁释放,类似于 STL 的容器类。该自动释放由计算机控制。在很大程度上,这意味着我们不再需要担心图像的分配和释放。
cv::destroyWindow("Example2");
最后,我们可以销毁释放窗口。函数cv::destroyWindow()
将关闭窗口并释放任何相关的内存使用。对于较短的程序,我们可以跳过此步骤。对于更长、更复杂的程序,程序员应该确保在窗口超出作用域之前将其销毁释放,以避免内存泄漏。