学习OpenCV 第二版<2-2>:First Program—Display a Picture

来源:互联网 发布:东北大学软件学院好吗 编辑:程序博客网 时间:2024/06/10 04:16

感兴趣的话大家可以到这里下载英文原版:http://download.csdn.net/download/zleisure/7451051(下载时请看下资源简介)

第一个程序——显示图像


       OpenCV提供了读取各种类型的图像文件、视频内容以及摄像机输入的功能。这些功能是OpenCV开发包中所包含的HighGUI工具集的一部分。http://opencv.org网站,你可以从文档链接到教程页http://docs.opencv.org/doc/tutorials/tutorials.html可以看到使用OpenCV各个方面的教程。

      在本教程部分,“OpenCV入门”教程解释了对不同的操作系统和开发工具的组合如何设置OpenCV。

      我们将使用由“highgui模块”为例来创建一个简单程序,该程序用以打开并在屏幕上显示一张图像(例2-1)。

      例2-1:一个简单OpenCV程序,用于从磁盘加载图像并显示在屏幕上

#include<opencv2/opencv.hpp> //Include file for every supported OpenCV functionint main( int argc,char** argv ){    cv::Matimg = 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" );}

       需要注意的是OpenCV函数都包含在一个名为CV的命名空间内。要调用OpenCV函数,你必须通过对每个调用函数前预置CV::,显示地告诉编译器你正在访问cv命名空间。为了摆脱这种繁琐差事,我们可以采用using namespace cv;如例2-2中所示 【1】 。这告诉编译器假定函数可能属于该命名空间。 还要注意例2-1和例2-2之间包含文件的差异;在前者中,我们使用了一般包含opencv.hpp,而在后者中,我们只使用了必要的包含文件,以提高编译时间。

       例2-2:同例2-1,但采用“using namespace”指令。为了更快的编译,我们只使用必要的头文件,而不是一般的opencv.hpp。

#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;     namedWindow( "Example2", WINDOW_AUTOSIZE );     imshow( "Example2", img );     waitKey( 0 );     destroyWindow( "Example2" ); }

       当以上程序编译后,我们就可以在命令行模式下通过输入一个参数执行它,执行时,该程序将向内从加载一幅图像,并将图像显示在屏幕上,直至按下键盘的任意一个键后关闭窗口并推出程序。下面我们将对以上代码做逐行分析,以理解每个命令具体做什么。

       cv::Mat img =cv::imread( argv[1], -1 );

       这行载入图像。【2】函数cv::imread()是一个高层调用接口,它通过文件名确定被加载文件的格式;并且该函数将自动分配图像数据结构所需的内存。需要指出的是,cv::imread()可以读取绝大多数格式类型的图像文件,这些类型包括BMP、DIB,JPEG,JPE,PNG,PBM,PGM,PPM,SR,RAS和TIFF。该函数执行完后将返回cv::Mat数据结构。cv::Mat结构体将是我们在使用OpenCV时会最常用到的数据结构。OpenCV使用这个数据结构处理诸如单通道(single-channel)、多通道(multichannel)、整形的(integer-valued)、浮点型的(floating-point-valued)等所有类型的图像文件。紧接着这行:

       if( img.empty() ) return-1;

       检查是否图像真正的被读取。CV::namedWindow()也是一个高层调用接口,该函数用于在屏幕上创建一个窗口,将图像包含于该窗口中并显示该图像。

       cv::namedWindow("Example2", cv::WINDOW_AUTOSIZE );

       该函数由HighGUI库提供,此函数也为窗口分配一个名称(本例中为“Example2”)。如果要使用HighGUI库所提供的其他函数与该窗口进行交互时,我们将通过该名字引用这个窗口。

       cv::namedWindow()的第二个参数定义了窗口的属性。它可以被设置为0(
默认值)或cv::WINDOW_AUTOSIZE。设置为0时,窗口的大小不会因图像的大小而改变,图像只能在窗口中根据窗口的大小进行拉伸或缩放;而设置为cv::WINDOW_AUTOSIZE时,窗口则会根据图像的实际大小自动进行拉伸或缩放,以容纳图像,但用户也可重定义窗口大小。

       cv::imshow("Example2", img );

       当第二个参数只要一个有与莫个图像文件相对应的cv::Mat结构,我们就可以在一个已创建好的窗口中使用cv::imshow()显示该图像。【3】cv::imshow()函数被调用时,该窗口将被重新绘制,并且图像也会显示在窗口中,如果该窗口在创建时被指定为cv::WINDOW_AUTOSIZE标志作为cv::namedWindow()函数的第二个参数,该窗口将根据图像的大小自动调整为与图像一致。

       cv::waitKey( 0 );

       cv::waitKey()函数的功能是使程序暂停,等待用户触发一个按键操作。但如果将该函数参数设为一个正数,则程序将暂停一段时间,时间长为该整数值个毫秒单位,然后继续执行,即使用户灭有按下任何键。当设置该函数参数为0或负数时,程序将一直等待用户触发按键操作。这个函数还有另一个非常重要的作用:它可以处理任何窗口事件,比如创建窗口和绘制他们的内容。所以使用cv::imshow()显示图像后,必须使用它。

       对于cv::Mat,在离开其作用域后图像将自动释放分配的空间,类似于STL式的容器类。这种自动回收是由一个内部参考计数器控制。在大部分情况下,这意味着我们不再需要担心图像的内存分配和释放,从OpenCV 1.0的IplImage强加的乏味繁琐看,减轻了程序员的负担。

       cv::destroyWindow("Example2" );

       最后,可以销毁显示图像文件的窗口。cv::destroyWindow()函数将关闭窗口并同时释放为该窗口所分配的所有内存。因为当应用程序的窗口被关闭时,该应用程序窗口所占用的一切资源都会有操作系统自动释放,所以一些简单程序,我们可以跳过这一步。对于复杂的程序,为了避免内存泄漏,在窗口离开其作用域之前,程序员应该确保释放资源。

       我们的下一个任务将是要去构建一个几乎与第一个例子程序一样非常简单的程序——读取并播放一个视频文件。之后,我们将开始鼓捣更多的实际图像问题。

【1】:当然,一旦你这样做,你就会有与其他潜在的命名空间名称冲突的风险。也就是做,如果函数foo()
即存在cv命名空间也存在于std命名空间,你必须利用cv::foo()或std:foo()来显示指定所使用的函数。在这本书中,除了在我们的特定例子2 - 2,对于OpenCV命名空间我们将使用显式形式cv::,因为这是通常被认为是更好的编程风格。

【2】:一个正当的程序将检查argv[1]的存在,并在其不存在时,传递一个指导性错误消息给用户。在本书中我们将省略这样的必要提示,并假设读者在理解错误处理代码以有足够的培养。

【3】:在你用imshow()函数调用的窗口不存在的情况下,系统将根据你在imshow()函数中指定的调用窗口名字创建一个窗口。这个窗口仍然可以像往常一样用destroyWindow()摧毁。

0 0
原创粉丝点击