描述
开 本: 16开纸 张: 胶版纸包 装: 平装-胶订是否套装: 否国际标准书号ISBN: 9787302510482
本书主要介绍了视觉库OpenCV,NVIDIA公司推出的CUDA,并结合传统的图像处理算法,介绍了如何使用GPU去加速传统图像处理算法。其中二三章主要介绍OpenCV的基础知识,环境搭建和简单应用。第四章主要介绍了CUDA的基础知识,环境搭建和简单应用。第五章主要介绍了如何编译OpenCV和CUDA,并给出了一些简单的CUDA加速图像处理的算法。该书浅显易懂,适合没有基础的读者快速上手。
本书主要介绍图像处理和GPU加速的基本原理、主要技术和典型应用。全书共分为5章,详细的叙述了OpenCV的环境搭建,OpenCV在图像处理算法中的应用,OpenCV如何与CUDA进行编译,以及如何使用编译后的OpenCV库驱动GPU加速传统的图像处理算法。 本书可作为信号处理、通信工程、计算机应用、广播电视、自动控制、生医工程、地理信息等领域的工程技术人员、大专、本科院校相关专业的高年级学生研究图像处理技术的参考书。
目录
第1章并行图像处理概述
1.1计算机的构成
1.1.1计算机硬件构成
1.1.2显卡和GPU
1.1.3显卡的发展史
1.2并行计算
1.3并行图像处理
1.3.1并行图像处理的应用背景
1.3.2并行图像处理的原理
1.3.3并行图像处理的加速效果
1.4并行图像处理硬件平台
1.5并行图像处理软件平台
1.5.1开发平台——Visual Studio
1.5.2计算机视觉库——OpenCV
1.5.3统一设备架构——CUDA
1.5.4并行编程开发工具——TBB
1.5.5跨平台编译工具——CMake
1.6常用软硬件搭配方案
1.7本书介绍
1.8本章小结
参考文献
第2章OpenCV及环境搭建
2.1OpenCV的发展历程
2.2开发平台——Visual Studio 2010
2.2.1Visual Studio简介
2.2.2安装Visual Studio 2010
2.3搭建OpenCV 2.4.9
2.3.1步OpenCV的下载和安装
2.3.2第二步OpenCV的环境变量配置
2.3.3第三步工程项目内包含目录的配置
2.3.4第四步库目录的配置
2.3.5第五步附加依赖项的配置
2.3.6第六步清单项配置
2.3.7第七步Release配置
2.3.8第八步加入OpenCV动态链接库
2.3.9第九步环境测试
2.4OpenCV基本架构
2.5OpenCV环境搭建中常见的问题及解决方案
2.5.1无法启动程序
2.5.2文件缺少MSVCP110D.dll
2.5.3Cannot find or open the PDB file
2.5.4文件缺少tbb_debug.dll
2.5.5应用程序无法启动0xc000007b
2.5.6找不到头文件
2.5.7无法打开lib文件
2.5.8指针越界cv::Exception
2.5.9×86与x64类型冲突
2.6本章小结
2.7参考文献
第3章OpenCV常用函数和应用实例
3.1OpenCV常用函数
3.1.1Mat类
3.1.2imread函数
3.1.3imshow函数
3.1.4imwrite函数
3.2反向算法
3.3图像融合
3.3.1覆盖型图像融合
3.3.2线性图像混合
3.3.3动画效果的线性混合
3.4图像去噪
3.4.1均值滤波
3.4.2高斯滤波
3.4.3非局部均值滤波
3.5双目视觉测量物体深度
3.5.1双目视觉原理
3.5.2双目视觉标定
3.5.3OpenCV实现
3.6本章小结
3.7参考文献
第4章GPU和CUDA的介绍和应用
4.1CUDA的介绍
4.2GPU的内部结构
4.2.1GPU内部结构的简单介绍
4.2.2GPU的架构
4.2.3常见GPU的挑选
4.3并行处理介绍
4.4CUDA环境搭建
4.4.1CUDA的下载
4.4.2CUDA的安装
4.4.3CUDA在VS中的测试
4.4.4CUDA项目的创建
4.5CUDA C语言
4.5.1C语言小扩展集
4.5.2运行时库
4.6程序示例
4.6.1Hello World实现
4.6.2参数传递
4.6.3同步函数
4.7线程层次
4.7.1核函数调用和线程层次介绍
4.7.2矢量求和
4.7.3数据较多的矢量求和
4.7.4不同维度线程索引
4.8GPU的存储器
4.8.1寄存器
4.8.2局部存储器
4.8.3共享存储器
4.8.4常数存储器
4.8.5纹理存储器
4.8.6全局存储器
4.8.7页锁定存储器
4.8.8可分页存储器
4.9本章小结
参考文献
第5章基于GPU的并行图像处理
5.1CMake和TBB的安装
5.1.1安装CMake
5.1.2安装TBB
5.2并行OpenCV库的生成
5.3VS内的OpenCV环境搭建及环境测试
5.3.1常用工程文件的配置
5.3.2分别配置项目文件
5.4GPU图像处理实例
5.4.1反向算法
5.4.2图像加法、减法
5.4.3图像腐蚀、膨胀
5.4.4非局部均值算法
5.5本章小结
参考文献
前言
随着大数据时代的来临,越来越多的图像需要实时处理。随之而来的使用C 编程的机器视觉库OpenCV以及驱动GPU的CUDA也变得越来越火热。
OpenCV是机器视觉领域非常著名的开源库,它几乎被应用到机器视觉的所有领域,其功能几乎涵盖每个研究方向。OpenCV包含了底层的图像处理、中层的图像分析以及高层的视觉技术。而且,其算法紧跟视觉前沿,将的算法纳入其中。特别是OpenCV 2系列的出现,可以使用C 进行编程,并且可以使用GPU为图像处理进行加速。OpenCV在图像界是相当重要的工具,也是很多图像领域研究人员极力推荐的库。
CUDA作为一种并行计算架构,是以GPU为数据并行计算设备的软硬件体系。CUDA以C语言为基础,可以直接用C语言写出在显示芯片上执行的程序,而不需要去学习特定的显示芯片的指令或特殊的结构。因此,CUDA被广泛应用在视频编解码、金融、地质勘探、科学计算等领域。
作为并行图像处理的入门级教材,本书将并行计算架构CUDA和机器视觉库OpenCV结合,以大量示例程序为主线,详细介绍了如何搭建OpenCV环境,如何使用Cmake编译CUDA和OpenCV,以及环境搭建过程中可能出现的错误和解决方案。编写本书的初衷是希望更多初步接触GPU和图像处理的读者可以快速搭建好环境并快速了解OpenCV和CUDA的基础知识,节省入门消耗的时间。
由衷感谢我的导师宋清洋对于我学业和生活上的支持与鼓励,以及对这本书的付出。感谢栾峰老师对我学业上的指点,没有他的指点也就不会有这本书的诞生。感谢我的好兄弟郑建斌和学姐包锡伟在我学习图像处理的过程中对我的指导。
真心希望读者可以轻松地入门并行图像处理技术。由于作者水平有限,书中难免有不足之处,恳请读者批评指正。
王泽宇
2019年3月于东北大学
第3章OpenCV常用函数和应用实例
本章主要介绍OpenCV的常用函数、变量以及基本数据结构。在此基础上,给出部分应用示例,详细讲解反向、滤波、双目视觉测深度算法,为灵活使用OpenCV打下基础。
3.1OpenCV常用函数
本节主要针对OpenCV中常用的,也是核心的Mat类、imread函数、imshow函数以及imwrite函数进行介绍。
3.1.1Mat类
说到Mat类就必须要介绍一下OpenCV 2系列。在OpenCV 1系列的函数库中,函数都是基于C接口构建的,使用名为IplImage的C语言结构体在内存中存储图像,用法类似于C语言中的指针,在使用函数之前先为变量开辟内存,使用之后释放内存,在算法复杂度较高的情况下,指针的使用会引起内存混乱。而在OpenCV 2系列中,C 的出现带来了全新的Mat类,使OpenCV能执行自动的内存管理,也就是说,在使用OpenCV时不必再进行手动开辟内存、管理内存等烦琐的工作,大大减少了开发者的工作量。自动开辟指的是程序自动根据需要使用的内存空间,合理开辟内存,不会造成资源的浪费,当然如果必要,也可以手动开辟内存空间[1]。
1. Mat类的定义
官方手册上Mat的定义是: Mat类用于表示一个多维度的单通道或者多通道的稠密数组,能够用来保存实数或复数的向量、矩阵、灰度或彩色图像、立体元素、点云、张量以及直方图等[2]。
在使用的过程中只需要记住两点:
(1) Mat类用来保存多维度的矩阵;
(2) Mat类不需要手动开辟内存,也不需要手动释放内存。
2. Mat的数据结构
Mat的数据结构主要包括两个部分: Header和Pointer。其中Header主要包含矩阵的大小、存储方式、存储地址等信息,而Pointer是存储指向像素值的指针。
Mat类的常见属性如下:
(1) data。
data是uchar型的指针,也就是上述指向矩阵内数据的指针。
(2) dims。
dims指的是矩阵的维度,如: 一维数组dims=1; 二维矩阵dims=2等。
(3) rows、cols。
rows指矩阵的行数,cols指矩阵的列数。需要注意的是,如果是多通道的彩色图像,rows和cols分别表示的是图像中纵向的像素点数量和横向像素点数量,这与通道数没有关系。
(4) channels。
channels指矩阵的通道数,如果读入的是图像,也指图像的通道数。通常单通道的图像为灰度图像,彩色图像有三通道的RGB(Red、Green、Blue)图像和四通道的RGBA(Red、Green、Blue、Alpha)图像。
(5) type。
type表示矩阵中元素的类型以及矩阵的通道数,属于预定义的常量,其命名的规则为[3]:
CV_ 位数 数据类型 通道数
如: CV_8UC1表示8位、unsigned integer无符号型、单通道;
CV_16SC2表示16位、singed integer有符号整数、双通道;
CV_64FC4表示64位、float浮点型、四通道。
其具体的型号如表31所示。
表31type常量
CV_8UC1CV_8UC2CV_8UC3CV_8UC4
CV_8SC1CV_8SC2CV_8SC3CV_8SC4
CV_16UC1CV_16UC2CV_16UC3CV_16UC4
CV_16SC1CV_16SC2CV_16SC3CV_16SC4
CV_32SC1CV_32SC2CV_32SC3CV_32SC4
CV_32FC1CV_32FC2CV_32FC3CV_32FC4
CV_64FC1CV_64FC2CV_64FC3CV_64FC4
(6) depth。
depth指矩阵中元素一个通道内的数据类型,这个和上面的type型类似,相比于type更加简单。depth常用常量如表32所示。
表32depth常量
CV_8UCV_8SCV_8F
CV_16UCV_16SCV_8F
CV_32UCV_32SCV_32F
CV_64UCV_64SCV_64F
(7) elemSize。
elemSize是指矩阵中一个元素占用的字节数,其值为:
elemSize=通道数×位数÷8
如: CV_64FC4; elemSize=4×64÷8=32bytes。
(8) elemSize1。
elemSize1指矩阵元素一个通道占用的字节数,相比于elemSize仅少了通道数,如: CV_64FC4; elemSize1=64÷8=8bytes。
下面的程序详细示范了Mat属性的使用方法及效果:
#include
#include
usingnamespace cv;
usingnamespace std;
void main()
{
Mat img(3, 4, CV_16UC4, Scalar_(1, 2, 3, 4));
cout << img << endl;
cout <
cout <
cout <
cout <
cout <
cout <
cout <
cout <
getchar();
}
该程序定义了一个3行4列4通道16位unchar型矩阵,存放的数值依次为1、2、3、4。运行结果如图31所示。
图31Mat属性测试结果图
除以上介绍的几种Mat属性外,下面还要特别指出三种易混淆的Mat属性: step、step1和size。不过在此之前需要知道OpenCV内对于维度的定义。
OpenCV对于维度的定义是: 矩阵的深度为维,矩阵的高度为第二维,矩阵的宽度为第三维。用一个例子来进行说明,如图32所示,该矩阵高度为4,宽度为5,深度为3。矩阵的面就是其维,也就是矩阵深度,例子中该值为3; 矩阵中每个面上的每一行为第二维,也就是矩阵高度,例子中该值为4; 矩阵的每一行中的每一个点是第三维,也就是矩阵的宽度,例子中该值为5,如图33所示。
图32三维矩阵示意图
图33OpenCV对三维矩阵的维度划分
(9) size。
size表示每一维元素的个数,通常情况下会使用size[0]、size[1]和size[2]来分别表示矩阵的维、第二维和第三维。使用如图32所示的矩阵,对应的取值为size[0]=3,size[1]=4,size[2]=5。
(10) step
step表示的是每一维的元素的大小,单位是字节。step与size用法类似,也是用step[0]、step[1]和step[2]。step[0]表示维的元素的大小,即每个面的元素的总字节数; step[1]表示第二维的元素的大小,即面上的每一行的元素的总字节数; step[2]表示第三维元素的大小,即每一行中的一个元素的总字节数。
那么对于之前的矩阵,其step值为:
step[2]=3×8÷8=3;
step[1]=step[2]×5 = 3×8÷8×5 = 15;
step[0]=step[1]×4 = 3×8÷8×5×4 = 60;
需要补充的是,如果矩阵是二维矩阵,那么step[0]仍然表示一维元素的大小,但是这个时候,就不是面,而是单个面中的线,也就是一行元素所占的字节数量。同理,step[1]表示二维元素的大小,即矩阵中一个元素的大小,而step[2]则没有意义。
(11) step1。
step1表示每一维元素的通道总数,同样的step1(0)是一维元素的通道总数,即每一个面上所有元素的通道数; step1(1)是二维元素的通道总数,即每一个面上的每一行的元素的通道数; step1(2)是三维元素的通道总数,即每一行上,每一个元素的通道数。还是用前面提到的三维矩阵来举例,那么有[4]:
step1(2)=3; //三通道
step1(1)=3×5 = 15;
step1(0)=3×5×4= 60;
通过以下程序来解释一下size、step和step1的区别,程序如下:
#include
#include
usingnamespace cv;
usingnamespace std;
void main()
{
int matSize[]={3,4,5}; //定义维为3;第二维为4;第三维为5
Mat img(3,matSize,CV_8UC3, Scalar::all(0));
cout <
cout <
cout <
cout <
cout <
cout <
cout <
cout <
cout <
cout <
cout <
cout <
getchar();
}
程序运行结果如图34所示。
图34Mat中size、step和step1的区别
评论
还没有评论。