-卵巢癌晚期症状
OpenCV
入门教程
作者:于仕琪
@
2012
年
8
月
版权所有
?
于仕琪
本作品采用知识共享署名
-
相同方式共享
4.0
国际许可协议进行许可。
1
前
言
OpenCV
是一个广受欢迎的开源计算机视觉库,它提供了很多函数,实现了
很多计 算机视觉算法,算法从最基本的滤波到高级的物体检测皆有涵盖。很多
初学者希望快速掌握
OpenCV
的使用方法,但往往会遇到各种各样的困难。其
实仔细分析,造成这些 困难的原因有两类:第一类是
C/C++
编程基础不过关;
第二类是不了解 算法原理。解决这些困难无非提升编程能力,以及提升理论基
础知识。提升编程能力需要多练习编程,提 升理论知识需要系统学习《数字图
像处理》、《计算机视觉》和《模式识别》等课程,所有这些都不能一 蹴而就,
需要耐下心来认真修炼。
同时我们也需要认识到
OpenCV
只是一个算法库,能为我们搭建计算机视觉
应用提供“砖头”。我们并不需要完 全精通了算法原理之后才去使用
OpenCV
,
只要了解了“砖头”的功能,就可以 动手了。在实践中学习才是最高效的学习
方式。本小册子希望为初学者提供引导,使初学者快速了解 OpenCV
的基本数
据结构以及用法。
此外,如您发现有错误之处,欢迎来信指正。
于仕琪
深圳大学
插播广告
:欢迎有能力、有激情以及对计算机视觉有兴趣的同学报考我的
研究生。欲了解详情可以访问深圳大学招生网
/
或者
给我发
。
2
目录
第
1
章
1.1
1.2
1.3
1.4
1.5
预备知识
..................................... .................................................. ........
5
编程的流程
...................... .................................................. ................
5
什么叫编辑
.............. .................................................. ........................
6
什么叫编译
...... .................................................. ................................
6
什么叫连接................................................ ........................................
7
什么叫运行
........................................ ................................................
7
1.6
Visual C++
是什么
.......... .................................................. ......................
8
1.7
1.8
头 文件
............................................ .................................................. ..
9
库文件
.............................. .................................................. ..............
10
1.9
OpenCV
是什么
...................................... .............................................
1
1
1.10
1.11
1.12
1.13
第
2
章
什么是命令行参数
... .................................................. .....................
12
常见编译错误
....... .................................................. .........................
13
1.11.1
找不到头文件
................................... ......................................
1
3
1.11.2
拼写错误
.......................... .................................................. .....
1
4
常见链接错误
................... .................................................. .............
15
运行时错误
................ .................................................. ....................
17
OpenCV
介绍
.................................................. .................................
1
9
2.1
OpenCV
的来源
................... .................................................. ..............
1
9
2.2
OpenCV
的协议
...................................... .............................................
1
9
第
3
章
3.1
图像的基本操作
.................................. ...............................................
2
1
图像的表示
.......................... .................................................. ..........
21
3.2
Mat
类
...... .................................................. .........................................
2
3
3.3
创建
Mat
对象
................................... ..............................................
2
4
3.3.1
构造函数方法
.............. .................................................. ...........
2
4
3.3.2 create()
函数创建对象
........................... ....................................
2
5
3.3.3 Matlab
风格的创建对象方法
............... ....................................
2
6
3
3.4
3.5
3.6
矩阵的基本元素表达
.................................................. ....................
2
6
像素值的读写
.... .................................................. ............................
2
7
3.5.1
at()
函数
............................... .................................................. .....
2
8
3.5.2
使用迭代器
......... .................................................. ....................
2
9
3.5.3
通过数据指针
................................... ........................................
3
0
选取图像局部区域
....................... .................................................. .
3
2
3.6.1
单行或单列选择
........... .................................................. ..........
3
2
3.6.2
用
Range
选择多行或多列
.................................. .....................
3
3
3.6.3
感兴趣区域
.................................... ...........................................
3
3
3.6.4
取对角线元素
.............. .................................................. ...........
3
4
3.7
Mat
表达式
.................................................. .......................................
34
3.8
Mat_
类
........................ .................................................. ......................
36
3.9
Mat
类的内存管理
................................... ..........................................
38
3.10
输出
............................... .................................................. .................
4
0
3.11 Mat
与
IplImage
和
CvMat
的转换
.................................................
4
2
3.11.1 Mat
转为
IplImage
和
CvMat
格式
..........................................
42
3.11.2 IplImage
和
CvMat
格式转为
Mat ...........................................
42
第
4
章
数据获取与存储
..... .................................................. ..........................
4
4
4.1
4.2
4
读写图像文件
...... .................................................. ..........................
4
4
4.1.1
读图像文件
.................................... ...........................................
4
4
4.1.2
写图像文件
............... .................................................. ..............
4
5
读写视频
............ .................................................. ............................
4
7
4.2.1
读视频
...................................... .................................................
4
7
4.2.2
写视频
................. .................................................. ....................
4
9
第
1
章
预备知识
OpenCV < br>是一个功能强大的计算机视觉库,要用好它,除了要具有相关的计
算机视觉理论知识外,还需要具 有一定的编程能力。本书作者通过对
OpenCV
中文论坛中的大量问题观察,发现有很大比例的问题是因为用户对
C/C++
语言
不熟练,导致出错,或出错后不知如何解决。如果对
C/C++
语言不熟悉,那使
用
OpenCV
时会满头雾水瞎摸索,费心费力。
在这一章中,将介绍一些编程的基本概 念,让读者对编程的流程有一个基
本了解。这样在出现错误时,可以快速确定错误的类型,并知道该如何 解决。
1.1
编程的流程
一个编程的基本流程包括编辑、编译和连接三大步骤。其流程图如图
1.1
所
示。
编辑
编辑
编译
编译
opencv_
连接
5
图
1.1
编程的基本流程
1.2
什么叫编辑
编辑(
edit
)代码即编写代码,是编程的第一步 。你可以任意一个编辑器
进行代码的编写。你可以使用
Windows
自 带的“记事本”来编写代码,也可以
使用
Notepad++
,或者
Visual Studio
提供的编辑器。
图
1.2
使用
Windows
自带的记事本编辑代码
虽然可以使用记事 本软件编辑代码,但是记事本软件的功能非常有限。缺少常
用的语法高亮,自动缩进等功能。所以可以使 用其他功能更丰富的编辑器,如
Notepad++
(图
1.3
)等。
图
1.3
使用
Notepad++
软件编辑代码
1.3
什么叫编译
编译(
compile
)是将用某种编程语言(如
C++
语言)写 成的源代码,转换成目
标文件。目标文件包含着机器代码(可直接被计算机中央处理器执行)以及代码在
运行时使用的数据。编译器(
compiler
)是实现这一目的的软件。编译器有很 多,
如在
Windows
下有微软公司的
,在
Linux
下有
gcc
和
g++
。在命令行
6
下使用
对
源代码进行编译,如图
1.4
所示。编译后,将得到目
标文件
,如图
1.5
所示。
图
1.4
在命令行下使用
对
进行编译
图
1.5
编译后,将新生成
目标文件
1.4
什么叫连接
连接(
link
)是 将多个目标文件,以及库文件生成可执行的文件(或静态库、
或动态库)的过程。连接器(
li nker
)是实现这一目的的软件。常用的连接器有
Windows
下的
,
Linux
下的
ld
等。
在
Windows
下可以使用
将前面生成的
连接为可执行文件。在
命令行下效果如所图
1.6
示。连接后,将生成可执行文件,如图
1.7
所示。
图
1.6
在命令行下使用
对
进行连接
图
1.7
连接后,将新生成
可执行文件
1.5
什么叫运行
运行(
run
)较容易理解,我们在
Windows
资源管理器里用鼠标双击
exe
可
执行程序,可以使程序被载入
CPU
运行。我们也可以在命令行窗口中输入可执
7
行程序的文件名运行,如图
1.8
所示。
图
1.8
在命令行窗口中运行
,可以看到程序打印到标准输出的结果。
1.6
Visual C++
是什么
通过前面的介绍,可以看到一个编程的流程:编 辑
->
编译
->
连接
->
运行。更
具体来说,完成 这个流程需要你:
1.
打开记事本软件,编辑代码,并保存;
2.
在命令行下运行编译器,对代码进行编译,生成目标文件;
3.
在命令行下运行连接器,将目标文件连接起来,生成可执行程序;
4.
在命令行下,或
Windows
资源管理器中运行程序,验证程序的正确性。
< br>如果你的项目只有一个源代码文件,完成上面四个步骤尚可接受。但是如
果你的项目包括几十个甚 至几百个源文件,如无其他软件辅助,只用上面四个
非常基本的步骤进行编程开发,会让人抓狂。
集成开发环境(
Integrated Development Environment
,简称
IDE
)可以帮助你
对项目进行管理。常用的
IDE
有微软公司的
Visual Studio
,里面包含
Visual C++
,
Visual C#
等,其他的还有
Eclipse
、
NetBeans
、
Delphi
等。因此我们平时所说的
VC
不是一种编程语言,也不是编译器,它只是一个
IDE
。
IDE
一般包含编辑器。
IDE
自带的编辑器一般都针对编程语言进行了定制,
实 现语法高亮、自动缩进、自动补全等方便的功能。
IDE
还提供丰富的菜单和按
钮工具,如图
1.9
、图
1.10
和图
1.11
所示。
如果你点击
IDE
中的“生成(
build
)”按钮(图
1.11
),或者点击菜单 “生成
(
build
)”中的菜单项“生成项目(
build
project
)”,那么
IDE
会去调用编译器
和连接器
来生成可执行程序。如果你在调试状态下,还会去调 用调
试器(
debugger
)。
IDE
会提升程序开发的效率,特别是调试程序的效率。
8
图
1.9
微软
Visual Stdio
集成开发环境
图
1.10 Visual Stdio
中的编辑按钮
图
1.11 Visual Stdio
中的生成程序按钮
1.7
头文件
在编程过程中,程序代码往往被拆成很多部分,每部分放在一个独立的源文件中,而不是将所有的代码放在一个源文件中。考虑一个简单的小例子:程序中有两
个函数
main()
和
foo()
。
main()
函数位于
,
foo()
函数位于
,
main()
函数中调用
foo()
函数。在编译阶段,由于编译是对单个文件进行编译,所
以编译
时,编译器不知道是否存在
foo()
函数以及
foo()
调用是否正确,
因此需要头文件辅助。也就是说,在编译命令:
/c
运行时,编译器不知道
foo
的用法是否正确(因为
foo
在另一个文件
中),只有借助头文件中的函数声明来判断。对
进行编译时,不会涉及
文件,只会涉及
和
foo.h
(因为
foo.h
被
include
)文件。头文
件的作用如图
1.1
所示。
9
1.
foo()
函数
这
样
用
对
2.
函
数
声
明
是
int
foo(int
i,
int
j)
,你的
调用看上去是对的。
foo.h
int foo(int i, int j);
#include
int main()
{
int i=foo(3,4);
return i;
}
#include
int foo(int i, int j)
{
……
}
图
1.12
对
进行编译时,需要利用头文件中的
foo()
函数声明来确认
中
对
foo()
的调用是正确的
1.8
库文件
库文件中包含一系列的子程序。例如在上一节的例子中,
源文件中
实现了
foo()
函数,我们假设
foo()
函数是包含重要算法的函数,我们需要将
foo()
函数提供给客户使 用,但是不希望客户看到算法源代码。为了达到这一目的,
我们可以将
编译程库文件(图
1.13
),库文件是二进制的,在库文件中
是看不到原 始的源代码的。库和可执行文件的区别是,库不是独立程序,他们
是向其他程序提供服务的代码。
当然使用库文件的好处不仅仅是对源代码进行保密,使用库文件还可以减少
重复 编译的时间,增强程序的模块化。将库文件连接到程序中,有两种方式,一
种是静态连接库,另一种是动 态连接库。如果希望了解更多关于库文件的知识,
请查阅相关资料,再次不详细分析它们之间的异同。< br>
10
用户
开发者
编辑
编辑
编译
编译
连接
图
1.13
库是二进制的文件,里面包含一系列子程序(
图有问题
)
1.9
OpenCV
是什么
OpenCV
其实就是一堆
C
和
C++
语言的源代码文件,这些源代码文件中实现
了许多常用的计算机视觉算法。例如
C
接口函数
cvCanny()
实现了
Canny
边缘提< br>取算法。可以直接将这些源代码添加到我们自己的软件项目中,而不需要自己
再去写代码实现 Canny
算法,也就是不需要重复“造轮子”。
由于
OpenCV
中源代码文件巨多,根据算法的功能,将这些源文件分到多
个模块中:
core
、
imgproc
、
highgui
等。将每个模块中的源文件编译成一个库文
件(如
opencv_
、
opencv_
、
opencv_
等) ,用户在
使用时,仅将所需的库文件添加到自己的项目中,与自己的源文件一起连接成
可执行程 序则可。
11
1.10
什么是命令行参数
C/C++
语言中的
main
函数,经常带有参数
argc
,
argv
,如下:
int main(int argc, char** argv)
或者
int main(int argc, char* argv[])
在上面代码中,
argc
表示命令行输入参数的个数(以空白符分隔),
argv
中
存储了所有的命令行参数。假如你的程序是
,如果在命令行运行该程序
(如图
1.14
。首先应该在命令行下用
cd
命令进入到
文件所在目录),
运行命令为:
Shiqi Yu
那么,
argc
的值是
3
,
argv[0]
是
,
argv[1]
是
,
argv[2]
是
。
图
1.14
使用命令行参数运行程序
下面的程序演示
argc
和
argv
的使用:
#include
int main(int argc, char ** argv)
{
int i;
for (i=0; i < argc; i++)
printf(
return 0;
}
假如上述代码编译为
,那么运行
a b c d e
12
将得到
Argument 0 is .
Argument 1 is a.
Argument 2 is b.
Argument 3 is c.
Argument 4 is d.
Argument 5 is e.
运行
将得到
Argument 0 is .
Argument 1 is .
1.11
常见编译错误
在编程中,经常会出现各种错误。出现 错误后,不要闭眼抱头作痛苦状。
出现错误后,需要做的第一件事情是阅读出错信息。出错信息虽然看似 凌乱,
但是能够提供很多有价值的信息,帮你解决问题。
1.11.1
找不到头文件
找不到头文件往往会提示如下错误:
(2):
fatal
error
C1083:
Cannot
open
include
file:
'opencv2/': No such file or directory
找不到头文件一般有两个原因:一个是头文件的文件名拼写错误;或者 未将
头
文
件
所
在
路
径
添
加
到
开
发
环
境
中
。
上
例
中
的
错
误
是
文
件
名
拼
写
错
误
,
opencv2/
被错误地拼写为
openc v2/
。如果文件名拼写正
确,编译器还是找不到头文件,则需要将头文件所在路径添加到相应 的变量中。
如在
Visual Studio 2010
中,需要在项目属性(
Project Property
)对话框中设置头
文件路径。具体位置在对话框“
VC++ Directories
”里面的“
Include Directories
”
中,如图
1.15
所示。
13
图
1.15
头文件所在路径设置
1.11.2
拼写错误
在编程中,拼写错误也是一类常见错误。如图
1.16
所示代码中,将
imread
函数错误地拼成
imreadd
,编译器会提示错误:
(9): error C3861: 'imreadd': identifier not found
这句错误提示的意思是说无法找到
imreadd
标识符,因此我们需要仔细检
查
imreadd
找不到的原因。假如你真的有一个函数是
imreadd
,但是找不到,可
能的原因是声明
imreadd
的头文件未使用
include
语句包含到源文件中。
14
图
1.16
拼写错误,将
imread
拼成了
imreadd
,会造成编译时错误。
如果源 代码不符合语法规则,则会造成编译错误。编译错误往往是由于编写代
码不仔细造成,比如拼写错误、漏 了半个括号、漏了分号等。因此一旦遇到便宜错
误,你需要按照错误提示,定位到出错的位置,仔细检查 语法是否符合规范。
1.12
常见链接错误
如果你的代码符合语法规则,则会通过编译过程。编译完所有源代码之后,
下一步是连接目标文件,以形成可执行文件。连接过程中最常见的错误如下(图
1.17
):
1> : error LNK2019: unresolved external symbol
cv::Mat
__cdecl
cv::imread(class
std::basic_string
std::allocator
> const
&,int)
(?imread@cv@@YA?AVMat@1@ABV?$$basic_string@DU?$$cha r_traits@D@std@@
V?$$allocator@D@2@@std@@H@Z) referenced in function _main
这个错误信息里最关键的词是“
unresolved
external
symbol
”,更具体的意
思是在
main
函数中使用了
imread
函数,但是无法从外部找到
imread
。
imread
函数是
OpenCV
的函数,不是用户自己实现的函数。
头文件告诉编
译器有个
imread
函数可以用,编译通过;但是到了连接时,连接器却找不到
imread
的具体实现,故出错。
15
图
1.17
连接错误,无法找到
imread
等函数的实现
图
1.18
添加依赖的库文件
16
要解决这一问题,需要将依赖的库文件添加到项目设置中。具体位置在对
话框“
Linker - Input
”里面的“
Additional Dependencies
”中,如图
1.18
所示。
1.13
运行时错误
经过编译和连接过程,生成了可执行的文件(如
exe
文件)之后,在运行这个可执行文件所产生的错误是运行时错误。比较常见的运行时错误是内存错误。
比如下面这段代码:
#include
#include
using namespace cv;
int main()
{
printf(
);
Mat img = imread(
);
Mat gray;
cv::cvtColor(img, gray, CV_BGR2GRAY);
return 0;
}
编译和连接过程无任何问题,但在运行时弹出如图
1.19
所示对话框,并在
命令行窗口输出错误信息(图
1.20
)。
图
1.19
运行时错误对话框
图
1.20
运行时错误的出错信息
17
错
误
信
息
中
提
示
文
件
的
第
2834
行
有
错< br>,
错
误
原
因
是
条
件
(scn==3 ||scn==4)
不成立。很多
OpenCV
用户看到此错误信息一头雾水,不 知如何下
手解决。根据程序源代码的意思,是将三通道的
BGR
图像
img
转为单通道的图像
gray
。但是程序说
img
既不是
3
通道,也不是
4
通道。而根据
imread
函数的文档,
imread
将图像作为彩色图像读入,条件
(scn==3 ||scn==4)
肯定成立。
这个程序的问题出现在当前目录下无
文件,这样程序无法读到图像,
造成
cvtColor
函数出错。因此对于读入图像时,需要检查图像读入是否成功,以
免造成运行时错误。
在程序编写中,对于数组和指针等,要特别地小心。因为对于空指针以及数
组越界等 问题,编译器无法在编译时给出错误提示。这类错误一旦在运行时发生,
排除起来非常困难。
18
第
2
章
OpenCV
介绍
OpenCV
的全称是
Open Source Computer Vision Library
,是一个开放源代码
的计算机视觉库。
OpenCV
是最初由英特尔公司发起并开发,以
BSD
许可证授权
发行,可以在商业和研究领域中免费使用,现在美国
Willow
Garage
为
OpenCV
提供主要的支持。
OpenCV
可用于开发实时的图像处理、计算机视觉以及模式识
别程序,目前在工业界以及科研领域广泛采用。
2.1
OpenCV
的来源
OpenCV
诞生于
Intel
。
Intel
最初希望提供一个计算机视觉库,使之能充分发
掘
CPU
的计算能力,当然更希望以此促进
Intel
的产品的销售。
OpenCV
最初的开发
工作是由
Intel
在俄罗斯的团队实现。这里面有两个关键人物,一个是
Intel
性
能团队(
Intel’s
Performance
Library
Team
)的李信弘(
Shinn
Lee
)先生,他是团队
的经理,负责
IPP
等库,给予
OpenCV
很大的支持。另一个关键人物是
Vadim
Pisarevsky
,
Vadim
在
Intel
负责
OpenCV
的项目管理、代码集成、代码优化等工作。
在后期
Intel
支持渐少的时候,是
Vadim Pisarevsky
一直在维护着
OpenCV
。
2007
年
6
月,受本书作者之邀,李信弘和
Vadim Pisarevsky
作为嘉宾参加了在北
京举行的“开放源 代码计算机视觉库
(OpenCV)
研讨会”
,并做了非常有价值的
报告。< br>
在
2008
年,一家美国公司,
Willow
Garage
,开始大力支持
OpenCV
,
Vadim
Pisarevsky
和
Gary Bradski
都加入了
Willow Garage
。
Gary Bradski
也是
OpenCV
开
发者中的元老级人物,他曾出版《
Leaning OpenCV
》一书,广受欢迎。
2
1
Willow
Garage
是一家机器人公司,致力于为个人机器人开发开放的硬件平
台和软件。现在已经开发了
PR2
机器人,并支持
ROS
、
OpenCV
、
PCL
等软件。
ROS
(
Robot
Operating
System
)是用于机器人的操作系统,是一个开放源代码的
软件,
OpenCV
作为
ROS
的视觉模块嵌入。
自从获得
Willow
Garage
支持后,
OpenCV
的更新速度明显加快。大量的新
特性被被加入
OpenCV
中,很多算法都是最近一两年的新的科研成果。
OpenCV
正日益成为算法研究和产品开发不可缺少的工具。
2.2
OpenCV
的协议
OpenCV
采用
BSD
协议,这是一个非常宽松的协议。简而言之,用户可以修
1
2
研讨会网址:
//OpenCV_Symposium
Willow Garage
公司网站:
19
改
OpenCV
的源代码,可以将
OpenCV
嵌入到自己的软件中,可以将包含
OpenCV
的软件销售,可以用于商业产品,也可以用于科研领域。
BSD
协议并不具有“传染
性”,如果你的软件中使用了
OpenCV
,你不需要公开代码。你可以对
OpenCV
做
任何操作,协议对用户的唯一约束是要在软件的文档或者说明中注明使用了
OpenCV
,并附上
OpenCV
的协议。
在这个宽松协议下,企业可以在
OpenCV
基础之上进行产品开发,而不需要担
心版权问题(当然你要注明使用了
OpenCV
,并附上
OpenCV
的协议)。科研领域
的研究者,可以使用
OpenCV
快速地实 现系统原型。因此可以这样说,
OpenCV
的
协议保证了计算机视觉技术快速的传播 ,让更多的人从
OpenCV
受益。
20
第
3
章
图像的基本操作
3.1
图像的表示
在正式介绍之前,先简单介绍一下数字图像的基本概念。如图
3.1
中所示
的图像,我们看到的是
Lena
的头像,但是计算机看来,这副图像只是一堆亮度
各异的点。一副尺寸为
M
×
N
的图像可以用一个
M
×
N
的矩阵 来表示,矩阵
元素的值表示这个位置上的像素的亮度,一般来说像素值越大表示该点越亮。
如图
3.1
中白色圆圈内的区域,进行放大并仔细查看,将会如图
3.2
所示。
图
3.1 Lena
的照片
21
图
3.2
图
3.1
中圆圈处的放大效果
一般来说,灰度图用
2
维矩阵表示,彩色(多通道)图像用
3
维矩阵(
M
×
N
×
3
)表示。对于图像显示来说,目前大部分设备都是用无符号
8
位整
数(类型为
CV_8U
)表示像素亮度。
图像数据 在计算机内存中的存储顺序为以图像最左上点(也可能是最左下
点)开始,存储如表
3-1
所示。
表
3-1
灰度图像的存储示意图
I
0 0
I
0 1
…
I
0 N-1
I
1 N-1
I
1 0
I
1 1
…
…
…
…
…
I
M-1 N-1
I
M-1 0
I
M-1 1
…
I
ij
表示第
i
行
j
列的像素值。如果是多通道图像,比如
RGB
图像,则每个
像素用三个字节表示。在
OpenCV
中,
RGB
图像的通道顺序为
BGR
,存储如
表
3-2
所示。
表
3-2
彩色
RGB
图像的存储示意图
B
00
G
00
R
00
B
01
G
01
R
01
…
…
B
10
G
10
R
10
B
11
G
11
R
11
22
…
…
…
…
…
…
…
3.2
Mat
类
早期的
OpenCV
中,使用
IplImage
和
CvMat
数据结构来表示图像。
IplImage
和
CvMat
都是
C
语言的结构。使用这两个结构的问题是内存需要手动管理,开发者必须清楚的知道何时需要申请内存,何时需要释放内存。这个开发者带来
了一定的负担,开发者 应该将更多精力用于算法设计,因此在新版本的
OpenCV
中引入了
Mat
类。
新加入的
Mat
类能够自动管理内存。使用
Mat
类,你不再需要花费大量精
力在内存管 理上。而且你的代码会变得很简洁,代码行数会变少。但
C++
接口
唯一的不足是当前一些嵌入式开发系统可能只支持
C
语言,如果你的开发平台
支持
C++
,完全没有必要再用
IplImage
和
CvMat
。在新版本的
OpenCV
中,开发
者依然可以使用
IplImage
和
CvMat
,但是一些新增加的函数只提供了
Mat
接口。
本书中的例程也都将采用新的
Mat
类,不再介绍
IplImage
和
CvMat
。
23
Mat
类的定义如下所示,关键的属性如下方代码所示:
class CV_EXPORTS Mat
{
public:
//
一系列函数
...
/* flag
参数中包含许多关于矩阵的信息,如:
-Mat
的标识
-
数据是否连续
-
深度
-
通道数目
*/
int flags;
//
矩阵的维数,取值应该大于或等于
2
int dims;
//
矩阵的行数和列数,如果矩阵超过
2
维,这两个变量的值都为
-1 int rows, cols;
//
指向数据的指针
uchar* data;
//
指向引用计数的指针
//
如果数据是由用户分配的,则为
NULL
int* refcount;
//
其他成员变量和成员函数
...
};
3.3
创建
Mat
对象
Mat
是一个非常优秀的图像类,它同时也是一个通用的矩阵类,可以用来
创建和操 作多维矩阵。有多种方法创建一个
Mat
对象。
3.3.1
构造函数方法
Mat
类提供了一系列构造函数,可以方便的根据需要创建
Mat
对象。下面
是一个使用构造函数创建对象的例子。
Mat M(3,2, CV_8UC3, Scalar(0,0,255));
cout <<
第一行代码创建一个行数(高度)为
3
,列数(宽度)为
2
的图像,图像
元素是
8
位无符号整数类型,且有三个通道。图像的所有像素值被初始化为
(0,
0, 255)
。由于
OpenCV
中默认的颜色顺序为
BGR
,因此这是一个全红色的图像。
第二行代码是输出
Mat
类的实例
M
的所有像素值。
Mat
重定义了
<<
操作符,
使用这个操作符,可以方便地输出所有像素值,而不需要使用
for
循环逐个像
素输出。
图
3.3
例程输出内容
该段代码的输出如图
3.3
所示。
常用的构造函数有:
?
?
?
?
?
?
?
?
Mat::Mat()
?
Mat::Mat(int rows, int cols, int type)
?
Mat::Mat(Size size, int type)
?
创建行数为
rows
,列数为
col
,类型为
type
的图像;
创建大小为
size
,类型为
type
的图像;
无参数构造方法;
?
?
?
Mat::Mat(int rows, int cols, int type, const Scalar& s)
?
24
?
?
?
?
Mat::Mat(Size size, int type, const Scalar& s)
?
Mat::Mat(const Mat& m)
?
创建行数为
rows
,列数为
col
,类型为
type
的图像,并将所有元素初始
化为值
s
;
创建大小为
size
,类型为
type
的图像,并将所有元素初始化为值
s
;
?
?
?
将
m
赋值给新创建的对象,此处不会对图像数据进行复制,
m
和新对
?
象共用图像数据;
Mat::Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP)
Mat::Mat(Size size, int type, void* data, size_t step=AUTO_STEP)
?
?
?
?
创建行数为
rows
,列数为
col
,类型为
type
的图像,此构造函数不创建
图像数据所需内存,而是直接使用
data
所指内存,图像的行步长由
?
step
指定。
创建大小为
size
,类型为
type
的图像,此构造函数不创建图像数据所
?
需内存,而是直接使用
data
所指内存,图像的行步长由
step
指定。
?
?
?
?
Mat::Mat(const Mat& m, const Range& rowRange, const Range& colRange)
?
Mat::Mat(const Mat& m, const Rect& roi)
?
创建的新图像为
m
的一部分,具体的范围由
rowRange
和
colRange
指
定,此构造函数也不进行图像数据的复制操作,新图像与
m
共用图像
?
数据;
?
创建的新图像为
m
的一部分,具体的范围
roi
指定,此构造函数也不进
?
行图像数据的复制操作,新图像与
m
共用图像数据。
这些构造函数中,很多都涉及到类型
type
。
type
可以是
CV_8UC1
,
CV_16SC1
,
…
,
CV_64FC4
等。里面的
8U
表示
8
位无符号整数,
16S
表示
16
位有
符号整数,
64F
表示
64
位浮点数(即
double
类型);
C
后面的数表示通道数,例
如
C1
表示一个通道的图像,
C4
表示
4
个通道的图像,以此类推。
如果你需要更多的通道数,需要用宏
CV_8UC(n)
,例如:
Mat M(3,2, CV_8UC(5));//
创建行数为
3
,列数为
2
,通道数为
5
的图像
3.3.2 create()
函数创建对象
除了在构造函数中可以创建图像,也可以使用
Mat
类的
create()
函数创建图
像。如果
create()
函数指定 的参数与图像之前的参数相同,则不进行实质的内存
申请操作;如果参数不同,则减少原始数据内存的索 引,并重新申请内存。使
用方法如下面例程所示:
Mat M(2,2, CV_8UC3);//
构造函数创建图像
(3,2, CV_8UC2);//
释放内存重新创建图像
25
-卵巢癌晚期症状
-卵巢癌晚期症状
-卵巢癌晚期症状
-卵巢癌晚期症状
-卵巢癌晚期症状
-卵巢癌晚期症状
-卵巢癌晚期症状
-卵巢癌晚期症状
本文更新与2021-02-24 02:50,由作者提供,不代表本网站立场,转载请注明出处:http://www.xapfxb.com/yuer/456953.html
-
上一篇:压疮的预防及护理
下一篇:原发性肾病综合征护理个案