《学习OpenCV 3(中文版)》 — 第一个程序:显示图片
第一个程序:显示图片
OpenCV提供了一些实用工具来读取从视频流到摄像机画面的各种各样的图像格式,这些工具都是HighGUI的一部分。我们将使用其中的一些工具来创建一个简单的程序,这个程序将打开一张图像并且将其显示在屏幕上(如示例2-1所示)。
示例2-1:一个简单的加载并显示图像的OpenCV程序
#include <opencv2/opencv.hpp> //Include file for every supported OpenCV function
int main( int argc, char** 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::destroyWindow( "Example1" ); return 0;
}
注意,OpenCV的函数都位于cv这一命名空间下,为了调用OpenCV的函数,你需要在每个函数前加上cv::,向编译器说明你所调用的函数处于cv命名空间。为了摆脱这种繁琐的工作,我们可以像示例2-2一样用using namespace cv;指令,告诉编译器假设所有函数都位于cv命名空间下。注1你还需要注意示例2-1和示例2-2在头文件上的不同,在前者中,我们使用了通用的opencv.hpp,而在后者中,我们只使用了必须的头文件来节约编译时间。
示例2-2:与示例2-1不同的是直接使用了using namespace
#include "opencv2/highgui/highgui.hpp" using namespace cv; int main( int argc, char** argv ) {
Mat img = imread( argv[1], -1 ); if( img.empty() ) return -1;
注1: 当然,如果这样做,需要冒着和其他潜在的命名空间冲突的风险。如果函数foo()已经存在于cv和std的命名空间,你必须指定自己使用的是位于cv::foo()的函数还是位于 std::foo()的函数。在本书中,除了示例2-2,都会指明cv::命名空间,并以此保持一个良好的编程风格。
namedWindow( "Example1", cv::WINDOW_AUTOSIZE ); imshow( "Example1", img ); waitKey( 0 );
destroyWindow( "Example1" );
}
当使用命令行编译和运行时,注2示例2-1将加载一张图像到内存中并且显示到屏幕上。它会保持显示直到用户按下一个键,之后程序才会销毁窗口并退出。现在让我们来一行一行地解释代码,并花一些时间来理解每一行代码都在做什么工作。
cv::Mat img = cv::imread( argv[1], -1 );
这一行将会载入图像。注3函数cv::imread()是高级的;依据文件名来决定载入图像格式的处理。这也会自动地申请图像需要的内存,注意,cv::imread()可以读取很多种图像格式,包括BMP,DIP,JPEG,JPE,PNG,PBM,PGM,PPM,SR,RAS以及TIFF。函数会返回一个cv::Mat结构,这个结构是OpenCV中你将会接触最多的自带结构。
OpenCV使用这个结构来处理所有类型的图像:单通道、多通道、整型、浮点数以及各种类型。紧接着的下面这一行:
if( img.empty() ) return -1;
检查这个图像是否真的被载入了。另一个高层级的函数cv::namedWindow()将会在屏幕打开一个窗口,其中可以包含需要显示的图片。
cv::namedWindow( "Example1", cv::WINDOW_AUTOSIZE );
该函数由HighGUI模块提供,会将一个名称赋予窗口(在这里窗口名为"Example1")。
未来HighGUI的和这个窗口的交互函数将由这个名称来指定要与哪个窗***互。
cv::namedWindow第二个参数说明了Windows的特性。这可以全部设置为0(默认情况下),也可以设置为cv::WINDOW_AUTOSIZE。在之前的例子中,窗口的大小将会和载入图像的大小一致,图像将会被缩放以适应窗口的大小。在之后的例子中,窗口将会在图像载入的时候被自动缩放以适应图像的真实大小,也可能由用户自行调整。
注2: 当然,如果这样做的话,你需要冒着和其他潜在的命名空间冲突的风险。如果函数foo() 已经存在于cv和std的命名空间,必须指定你使用的是位于cv::foo()的函数还是位于 std::foo()的函数。在本书中,除了示例2-2,都会指明cv::命名空间,并以此保持一个良好的编程风格。
注3: 好的程序会检查argv[1]是否存在并且给用户反馈一个错误信息,但是在这里没有。我们在本书中将会简略掉这些处理并且假设读者都有足够的的知识来理解处理错误代码的方式及其重要性。
cv::imshow( "Example1", img );
不论何时,只要在cv::Mat中拥有一个图像结构,我们都可以通过cv::imshow() 进行显示。cv::imshow()将建一个窗口(如果这个窗口不存在,它会自动调用 cv::namedWindow()新建一个窗口)。在调用cv::imshow()的时候,窗口将被重绘上要求的图片,并且窗口会按照要求自动调整大小(如果使用cv::WINDOW_AUTOSIZE参数)。
cv::waitKey(0);
cv::waitKey(0);函数告诉系统暂停并且等待键盘事件。如果其传入了一个大于零的参数,它将会等待等同于该参数的毫秒时间,然后继续执行程序。如果参数被设置为0或者一个负数,程序将会无限等待直到有键被按下。
因为有cv::Mat,图像将会在生命周期结束的时候自动释放,其行为类似于标准模板库(STL)中的容器类。这种自动的内存释放由内部的引用指针所控制,最重要的是,这表示我们用不着担心图像的内存申请和释放,这将程序员从OpenCV 1.0 IplImage结构繁琐的维护工作中解放了出来。
cv::destroyWindow( "Example1" );
最后,我们可以让窗口自行销毁。函数cv::destroyWindow()将会关闭窗口并且释放掉相关联的内存空间。为了更简洁的编码,我们将会在之后的例子中略过这一步。在更长、更复杂的代码中,程序员应该在窗口的生命周期自然结束之前自主销毁窗口以防止内存泄漏。
我们下一个任务是创建一个非常简单的、几乎和本例一样的程序来读取视频文件。在此之后,我们将会开始对实际图像进行更多的操作。
- 点赞
- 收藏
- 关注作者
评论(0)