您的位置:首页 > 运维架构

初识OpenCV(基础篇)

2016-07-13 17:59 651 查看
OpenCV其实就是一堆C和C++语言的源代码文件,这些源代码文件中实现了许多常用的计算机视觉算法。例如C接口函数cvCanny()实现了Canny边缘提取算法。可以直接将这些源代码添加到我们自己的软件项目中,而不需要自己再去写代码实现Canny算法。

 由于OpenCV中源代码文件巨多,根据算法的功能,将这些源文件分到多个模块中:core、imgproc、highgui等。将每个模块中的源文件编译成一个库文件(如opencv_core.lib、opencv_imgproc.lib、opencv_highgui.lib等),用户在使用时,仅将所需的库文件添加到自己的项目中,与自己的源文件一起连接成可执行程序则可。

OpenCV主体分为五个模块:

OpenCV的CV模块包含基本的图像处理函数和高级的计算机视觉算法。

ML是机器学习库,包含一些基于统计的分析和聚类工具。
HighGUI包含图像和视频输入/输出的函数。

CXCore包含OpenCV的一些基本数据结构和相关函数。

CvAux模块,该模块一般存放一些即将被淘汰的算法和函数(如嵌入式隐马尔可夫模型的人脸识别算法),同时还有一些新出现的实验性的算法(如背景和前景的分割)

C/C++语言中的main函数,经常带有参数argc,argv,如下: 

int main(int argc, char** argv)

或者

int main(int argc, char* argv[])

在上面代码中,argc表示命令行输入参数的个数(以空白符分隔),argv中存储了所有的命令行参数。

下面的程序演示argc和argv的使用: 

#include <stdio.h>

int main(int argc, char ** argv) {

    int i;

    for (i=0; i < argc; i++)

        printf("Argument %d is %s.\n", i, argv[i]);     return 0; }

openCV常见编译错误:

找不到头文件往往会提示如下错误:

hello.cpp(2): fatal error C1083: Cannot open include file: 'opencv2/opencv.hppp': No such file or directory

找不到头文件一般有两个原因:一个是头文件的文件名拼写错误;或者未将头文件所在路径添加到开发环境中。

这个例子显然是拼写错误,但是更多的情况下都是第二种错误。

我们再来详细的说说关于OpenCV

OpenCV采用BSD协议,这是一个非常宽松的协议。简而言之,用户可以修改OpenCV的源代码,可以将OpenCV嵌入到自己的软件中,可以将包含OpenCV的软件销售,可以用于商业产品,也可以用于科研领域。BSD协议并不具有“传染性”,如果你的软件中使用了OpenCV,你不需要公开代码。你可以对OpenCV做任何操作,协议对用户的唯一约束是要在软件的文档或者说明中注明使用了OpenCV,并附上OpenCV的协议。

openCV小例子(读取图像)

#include <stdio.h>

#include <opencv2/opencv.hpp>

using namespace cv;

int main(int argc, char** argv )

{

    if ( argc != 2 )

    {

        printf("usage: DisplayImage.out <Image_Path>\n");

        return -1;

    }

    Mat image;

    image = imread( argv[1], 1 );

    if ( !image.data )

    {

        printf("No image data \n");

        return -1;

    }

    namedWindow("Display Image", WINDOW_AUTOSIZE );

    imshow("Display Image", image);

    waitKey(0);

    return 0;

}

OpenCV中读图像文件:

将图像文件读入内存,可以使用 imread()函数;将 Mat 对象以图像文件格式

写入内存,可以使用 imwrite()函数。

 

imread()函数返回的是 Mat 对象,如果读取文件失败,则会返回一个空矩阵,

即 Mat::data 的值是 NULL。执行 imread()之后,需要检查文件是否成功读入,你

可以使用 Mat::empty()函数进行检查。imread()函数的声明如下:

Mat imread(const string&filename, int flags=1 )

很明显参数 filename 是被读取或者保存的图像文件名;在 imread()函数中,

flag 参数值有三种情况:

  flag>0,该函数返回 3通道图像,如果磁盘上的图像文件是单通道的灰

度图像,则会被强制转为 3通道;

  flag=0,该函数返回单通道图像,如果磁盘的图像文件是多通道图像,则

会被强制转为单通道;

  flag<0,则函数不对图像进行通道转换。

 

imread()函数支持多种文件格式,且该函数是根据图像文件的内容来确定文

件格式,而不是根据文件的扩展名来确定。所只是的文件格式如下:

  Windows 位图文件 - BMP,DIB;

  JPEG 文件 - JPEG,JPG, JPE;

  便携式网络图片 - PNG;

  便携式图像格式 - PBM,PGM,PPM;

  Sun rasters - SR,RAS;

  TIFF 文件 - TIFF,TIF;

  OpenEXR HDR 图片 - EXR;

  JPEG 2000 图片- jp2。

你所安装的 OpenCV 并不一定能支持上述所有格式,文件格式的支持需要特

定的库,只有在编译 OpenCV添加了相应的文件格式库,才可支持其格式。

 

OpenCV中写图像文件:

将图像写入文件,可使用 imwrite()函数,该函数的声明如下:

bool imwrite(const string&filename, InputArray image,

const vector<int>¶ms=vector<int>())

 

文件的格式由 filename参数指定的文件扩展名确定。推荐使用 PNG文件格

式。BMP 格式是无损格式,但是一般不进行压缩,文件尺寸非常大;JPEG 格式

的文件娇小,但是 JPEG 是有损压缩,会丢失一些信息。PNG是无损压缩格式,

推荐使用。

imwrite()函数的第三个参数 params可以指定文件格式的一些细节信息。这

个参数里面的数值是跟文件格式相关的:

  JPEG:表示图像的质量,取值范围从 0 到 100。数值越大表示图像质量

越高,当然文件也越大。默认值是 95。

  PNG:表示压缩级别,取值范围是从 0 到 9。数值越大表示文件越小,

但是压缩花费的时间也越长。默认值是 3。

  PPM,PGM 或 PBM:表示文件是以二进制还是纯文本方式存储,取值为

0 或 1。如果取值为 1,则表示以二进制方式存储。默认值是 1。

 

另外需要注意的是,在保存文件时,如果文件已经存在,imwrite()函数不会

进行提醒,将直接覆盖掉以前的文件。

 

并不是所有的 Mat 对象都可以存为图像文件,目前支持的格式只有 8U 类型

的单通道和 3 通道(颜色顺序为 BGR)矩阵;如果需要要保存 16U 格式图像,只

能使用 PNG、JPEG 2000 和 TIFF 格式。如果希望将其他格式的矩阵保存为图像文

件,可以先用 Mat::convertTo()函数或者 cvtColor()函数将矩阵转为可以保存的格

式。

 

下面例程展示了如何读入一副图像,然后对图像进行 Canny 边缘操作,最后

将结果保存到图像文件中。

#include <iostream>

#include"opencv2/opencv.hpp"

using namespace std;

using namespace cv;

int main(int argc, char*argv[])

{

//读入图像,并将之转为单通道图像

Mat im =imread("lena.jpg", 0);

//请一定检查是否成功读图

if( im.empty() )

{

cout << "Can notload image." << endl;

return -1;

}

//进行 Canny 操作,并将结果存于 result

Mat result;

Canny(im, result, 50, 150);

//保存结果

imwrite("lena-canny.png",result);

return 0;

}

将 lena.jpg 文件放在当前目录,运行该例程后,lena-canny.png 将会出现在当

前目录

 

下面我们介绍OpenCV读写视频:

介绍 OpenCV 读写视频之前,先介绍一下编解码器(codec)。

视频的格式主要由压缩算法决定。压缩算法称之为编码器(coder),解压算

法称之为解码器(decoder),编解码算法可以统称为编解码器(codec)。视频文

件能读或者写,关键看是否有相应的编解码器。

OpenCV 2 中提供了两个类来实现视频的读写。读视频的类是 VideoCapture,

写视频的类是 VideoWriter。

 

OpenCV读视频:

VideoCapture 既可以从视频文件读取图像,也可以从摄像头读取图像。可以

使用该类的构造函数打开视频文件或者摄像头。如果 VideoCapture 对象已经创

建,也可以使用 VideoCapture::open()打开,VideoCapture::open()函数会自动调用

VideoCapture::release()函数,先释放已经打开的视频,然后再打开新视频。

如果要读一帧,可以使用 VideoCapture::read()函数。VideoCapture类重载了>>

操作符,实现了读视频帧的功能。下面的例程演示了使用 VideoCapture 类读视

频。

#include <iostream>

#include"opencv2/opencv.hpp"

using namespace std;

using namespace cv;

int main(int argc, char**argv)

{

//打开第一个摄像头

//VideoCapture cap(0);

//打开视频文件

VideoCapturecap("video.short.raw.avi");

//检查是否成功打开

if(!cap.isOpened())

{

cerr << "Can notopen a camera or file." << endl;

return -1;

}

Mat edges;

//创建窗口

namedWindow("edges",1);

for(;;)

{

Mat frame;

//从 cap 中读一帧,存到 frame

cap >> frame;

//如果未读到图像

if(frame.empty())

break;

//将读到的图像转为灰度图

cvtColor(frame, edges,CV_BGR2GRAY);

//进行边缘提取操作

Canny(edges, edges, 0, 30, 3);

//显示结果

imshow("edges",edges);

//等待 30 秒,如果按键则推出循环

if(waitKey(30) >= 0)

break;

}

//退出时会自动释放 cap 中占用资源

return 0;

}

 

OpenCV写视频:

使用 OpenCV 创建视频也非常简单,与读视频不同的是,你需要在创建视频

时设置一系列参数,包括:文件名,编解码器,帧率,宽度和高度等。编解码器

使用四个字符表示,可以是CV_FOURCC('M','J','P','G')、CV_FOURCC('X','V','I','D')及

CV_FOURCC('D','I','V','X')等。如果使用某种编解码器无法创建视频文件,请尝试其

他的编解码器。

将图像写入视频可以使用 VideoWriter::write()函数,VideoWriter类中也重载

了<<操作符,使用起来非常方便。另外需要注意:待写入的图像尺寸必须与创建

视频时指定的尺寸一致。

 

下面例程演示了如何写视频文件。本例程将生成一个视频文件,视频的第 0

帧上是一个红色的“0”,第 1 帧上是个红色的“1”,以此类推,共 100 帧。

#include <stdio.h>

#include <iostream>

#include"opencv2/opencv.hpp"

using namespace std;

using namespace cv;

int main(int argc, char**argv)

{

//定义视频的宽度和高度

Size s(320, 240);

//创建 writer,并指定 FOURCC 及 FPS 等参数

VideoWriter  writer = VideoWriter("myvideo.avi",

CV_FOURCC('M','J','P','G'),25, s);

//检查是否成功创建

if(!writer.isOpened())

{

cerr << "Can notcreate video file.\n" << endl;

return -1;

}

//视频帧

Mat frame(s, CV_8UC3);

for(int i = 0; i < 100; i++)

{

//将图像置为黑色

frame = Scalar::all(0);

//将整数 i 转为 i 字符串类型

char text[128];

snprintf(text, sizeof(text),"%d", i);

//将数字绘到画面上

putText(frame,  text, Point(s.width/3,  s.height/3),

FONT_HERSHEY_SCRIPT_SIMPLEX,3,

Scalar(0,0,255), 3, 8);

//将图像写入视频

writer << frame;

}

//退出程序时会自动关闭视频文件

return 0;

}

Opencv支持的功能描述

图像数据操作(内存分配与释放,图像复制、设定和转换) 

图像/视频的输入输出(支持文件或摄像头的输入,图像/视频文件的输出) 

矩阵/向量数据操作及线性代数运算(矩阵乘积、矩阵方程求解、特征值、奇异值分解)  支持多种动态数据结构(链表、队列、数据集、树、图) 
基本图像处理(去噪、边缘检测、角点检测、采样与插值、色彩变换、形态学处理、直方图、图像金字塔结构)

结构分析(连通域/分支、轮廓处理、距离转换、图像矩、模板匹配、霍夫变换、多项式逼近、曲线拟合、椭圆拟合、狄劳尼三角化) 

摄像头定标(寻找和跟踪定标模式、参数定标、基本矩阵估计、单应矩阵估计、立体视觉匹配) 
运动分析(光流、动作分割、目标跟踪) 

目标识别(特征方法、HMM模型) 

基本的GUI(显示图像/视频、键盘/鼠标操作、滑动条)  图像标注(直线、曲线、多边形、文本标注)

OK,哈哈。最后我们来看看那个

莱娜·瑟德贝里



莱娜·瑟德贝里(瑞典文:Lena Soderberg),1951年3月31日出生于瑞典,在1972年11月期的《花花公子》杂志中,她化名为莱娜·舍布洛姆,成为了当期的玩伴女郎。她的中间折页照片由Dwight Hooker拍摄。她的照片(即莱娜图)后来被数字图像处理领域所广泛使用。1997年,在图像科学和技术协会(英语:Society
for Imaging Science and Technology)的第50届会议上,她被邀为贵宾出席。在会议上,她忙于签名、拍照以及介绍自我。

关于Lena Soderberg (ne Sjooblom)的报道说她居住在她的本国瑞典,有着幸福的婚姻并是三个孩子的妈妈,在liquor monopoly州有一份工作。1988年,她被某个瑞典计算机相关杂志采访,因为她的照片而发生的一切令她很高兴。这是她第一次得知她的照片在计算机领域被使用。

为何要使用Lenna图像?
David C. Munson. 在“A Note on Lena” 中给出了两条理由:

首先,Lenna图像包含了各种细节、平滑区域、阴影和纹理,这些对测试各种图像处理算法很有用。它是一副很好的测试图像!

第二,Lena图像里是一个很迷人的女子。所以不必奇怪图像处理领域里的人(大部分为男性)被一副迷人的图像吸引。

我知道你一定特别想要看原图,那么请看!!!



参考资料:《OpenCV入门教程》 作者:于仕琪,博士,助理研究员,深圳大学副教授,OpenCV中文站站长。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: