前言
今天,图像和视频无处不在,在线照片分享网站和社交网络上的图像有数十亿之多。几乎对于任意可能的查询图像,搜索引擎都会给用户返回检索的图像。实际上,几乎所有手机和计算机都有内置的摄像头,所以在人们的设备中,有几 G 的图像和视频是一件很寻常的事。计算机视觉就是用计算机编程,并设计算法来理解在这些图像中有什么。计算机视觉的有力应用有图像搜索、机器人导航、医学图像分析、照片管理等。
本书旨在为计算机视觉实战提供一个简单的切入点,让学生、研究者和爱好者充分理解其基础理论和算法。本书中的编程语言是 Python,Python 自带了很多可以免费获取的强大而便捷的图像处理、数学计算和数据挖掘模块,可以免费获取。
写作本书的时候,我遵循了以下原则:
- 鼓励探究式学习,让读者在阅读本书的时候,在计算机上跟着书中示例进行练习。
- 推广和使用免费且开源的软件,设立较低的学习门槛。显然,我们选择了 Python。
- 保持内容完整性和独立性。本书没有介绍计算机视觉的全部内容,而是完整呈现并解释所有代码。你应该能够重现这些示例,并可以直接在它们之上构建其他应用。
- 内容追求广泛而非详细,且相对于理论更注重鼓舞和激励。
总之,如果你对计算机视觉编程感兴趣,希望它能给你带来启发。
环境搭建
环境:python3
依赖库:PIL、numpy、pylab
计算机视觉简介
计算机视觉是一门对图像中信息进行自动提取的学科。信息的内容相当广泛,包括三维模型、照相机位置、目标检测与识别,以及图像内容的分组与搜索等。本书中,我们使用广义的计算机视觉概念,包括图像扭曲、降噪和增强现实等①。计算机视觉有时试图模拟人类视觉,有时使用数据和统计方法,而有时几何是解决问题的关键。在本书中,我们试图对此进行全面介绍。
实用计算机视觉混合了编程、建模和数学技巧,有时很难掌握。本着“力求简单,又不影响理解”的精神,有意用最少的理论来展示这些内容。书中对于数学知识的介绍是为了帮助读者理解算法,有些章(主要是第 4 章和第 5 章)无法避免地涉及很多数学理论。只要读者愿意,可以跳过这些数学理论,直接使用示例代码。
注 1:这些例子生成新的图像,并且比实际地从图像中提取信息需要更多的图像处理。
Python和NumPy
Python 是一门编程语言,其使用贯穿了全书的示例代码。Python 是一种简洁明了的语言,对于输入 / 输出、数字、图像及绘图都具有良好的支持。这门语言的一些特性需要我们逐渐适应,比如缩进和紧凑语法。要运行代码示例,你需要安装 Python 2.6 或之后的版本,因为只有这些版本才提供本书中用到的很多工具包。Python 3.x 版本与 2.x 版本有很多语法差异,并且不兼容 2.x 版本,也不兼容我们所需的工具包。
熟悉一些基本 Python 操作会更容易理解这些内容。对于 Python 初学者,我建议读一下 Mark Lutz 的书 Learning Python[20] 和 http://www.python.org/ 上的在线文档。在进行计算机视觉编程的时候,我们需要在向量、矩阵的表示上进行操作,这可以通过 Python 的 NumPy 模块处理;在该模块中,向量和矩阵是用 array 类型表示的。对于图像,我们也将采用这种类型的表示。Travis Oliphant 的免费电子书 Guide to NumPy[24] 是一本不错的 NumPy 参考手册;http://numpy.scipy.org/ 上的文档对于刚接触 NumPy 的读者来说是一个很好的起点。对于结果的可视化,我们会用到Matplotlib 模块;而对于更高级的数学,我们会用到 SciPy 模块。这些就是你会用到的核心模块,详见第 1 章。除了这些核心模块,对于某些特殊目的,比如读取 JSON 或 XML、载入并保存数据、生成图、图形编程、Web 演示、分类器等,我们还会用到很多其他免费模块。
这些模块只有在特殊的应用和演示中才需要,如果你对于某种应用不感兴趣,可以跳过。这里有必要提一下 IPython,它是一个交互式 Python 壳,使调试和实验变得更简单。对应文档及下载地址见 http://ipython.org/。
第一章 基本的图像操作和处理
本章讲解操作和处理图像的基础知识,将通过大量示例介绍处理图像所需的 Python工具包,并介绍用于读取图像、图像转换和缩放、计算导数、画图和保存结果等的基本工具。这些工具的使用将贯穿本书的剩余章节。
1.1 PIL:Python图像处理类库
PIL(Python Imaging Library Python,图像处理类库)
提供了通用的图像处理功能,以及大量有用的基本图像操作,比如图像缩放、裁剪、旋转、颜色转换等。PIL 是免费的,可以从 http://www.pythonware.com/products/pil/ 下载。
利用 PIL 中的函数,我们可以从大多数图像格式的文件中读取数据,然后写入最常见的图像格式文件中。PIL 中最重要的模块为 Image。要读取一幅图像,可以使用:
from PIL import Image pil_im = Image.open('empire.jpg')
上述代码的返回值 pil_im 是一个 PIL 图像对象。
图像的颜色转换可以使用 convert() 方法来实现。要读取一幅图像,并将其转换成灰度图像,只需要加上 convert(‘L’),如下所示:
pil_im = Image.open('empire.jpg').convert('L')
在 PIL 文档中有一些例子,参见 http://www.pythonware.com/library/pil/handbook/
index.htm。这些例子的输出结果如图 1-1 所示。
完整代码:
from PIL import Image pil_im = Image.open('data/empire.jpg') # pil_im = Image.open('data/empire.jpg').convert('L') pil_im.show()
1.1.1 转换图像格式
通过 save() 方法,PIL 可以将图像保存成多种格式的文件。下面的例子从文件名列
表(filelist)中读取所有的图像文件,并转换成 JPEG 格式:
(完整代码)
from PIL import Image import os filelist = ['data/empire.jpg'] for infile in filelist: outfile = os.path.splitext(infile)[0] + "_out.jpg" if infile != outfile: try: Image.open(infile).save(outfile) except IOError: print("cannot convert:"+ infile)
PIL 的 open() 函数用于创建 PIL 图像对象,save() 方法用于保存图像到具有指定文
件名的文件。除了后缀变为“.jpg”,上述代码的新文件名和原文件名相同。PIL 是
个足够智能的类库,可以根据文件扩展名来判定图像的格式。
PIL 函数会进行简单的检查,如果文件不是 JPEG 格式,会自动将其转换成 JPEG 格式;如果转换失败,它会在控制台输出一条报告失败的消息。
本书会处理大量图像列表。下面将创建一个包含文件夹中所有图像文件的文件名列
表。首先新建一个文件,命名为 imtools.py,来存储一些经常使用的图像操作,然
后将下面的函数添加进去:
import os def get_imlist(path): """ 返回目录中所有 JPG 图像的文件名列表 """ return [os.path.join(path,f) for f in os.listdir(path) if f.endswith('.jpg')]
1.1.2 创建缩略图
使用 PIL 可以很方便地创建图像的缩略图。thumbnail() 方法接受一个元组参数(该
参数指定生成缩略图的大小),然后将图像转换成符合元组参数指定大小的缩略图。
例如,创建最长边为 128 像素的缩略图,可以使用下列命令:
pil_im.thumbnail((128,128))
完整代码
from PIL import Image pil_im = Image.open('data/empire.jpg') pil_im.thumbnail((128, 128)) pil_im.show()
效果
1.1.3 复制和粘贴图像区域
使用 crop() 方法可以从一幅图像中裁剪指定区域:
box = (100,100,400,400) region = pil_im.crop(box)
该区域使用四元组来指定。四元组的坐标依次是(左,上,右,下)。PIL 中指定
坐标系的左上角坐标为(0,0)。
我们可以旋转上面代码中获取的区域,然后使用paste() 方法将该区域放回去,具体实现如下:
region = region.transpose(Image.ROTATE_180) pil_im.paste(region,box)
完整代码:
from PIL import Image pil_im = Image.open('data/empire.jpg') box = (100,100,400,400) region = pil_im.crop(box) region = region.transpose(Image.ROTATE_180) pil_im.paste(region, box) pil_im.show()
1.1.4 调整尺寸和旋转
要调整一幅图像的尺寸,我们可以调用 resize() 方法。该方法的参数是一个元组,
用来指定新图像的大小:
out = pil_im.resize((128,128))
要旋转一幅图像,可以使用逆时针方式表示旋转角度,然后调用 rotate() 方法:
out = pil_im.rotate(45)
完整代码:
from PIL import Image pil_im = Image.open('data/empire.jpg') box = (100,100,400,400) out = pil_im.resize((128,128)) out.show() out = pil_im.rotate(45) out.show() pil_im.show()
1.2 Matplotlib
我们处理数学运算、绘制图表,或者在图像上绘制点、直线和曲线时,Matplotlib是个很好的类库,具有比 PIL 更强大的绘图功能。Matplotlib 可以绘制出高质量的图表,就像本书中的许多插图一样。Matplotlib 中的 PyLab 接口包含很多方便用户创建图像的函数。Matplotlib 是开源工具,可以从 http://matplotlib.sourceforge.net/免费下载。该链接中包含非常详尽的使用说明和教程。下面的例子展示了本书中需要使用的大部分函数。
1.2.1 绘制图像、点和线
尽管 Matplotlib 可以绘制出较好的条形图、饼状图、散点图等,但是对于大多数计算机视觉应用来说,仅仅需要用到几个绘图命令。最重要的是,我们想用点和线来表示一些事物,比如兴趣点、对应点以及检测出的物体。
下面是用几个点和一条线绘制图像的例子:
from PIL import Image from pylab import * # 读取图像到数组中 im = array(Image.open('data/empire.jpg')) # 绘制图像 imshow(im) # 一些点 x = [100,100,400,400] y = [200,500,200,500] # 使用红色星状标记绘制点 plot(x,y,'r*') # 绘制连接前两个点的线 plot(x[:2],y[:2]) # 添加标题,显示绘制的图像 title('Plotting: "empire.jpg"') show()
上面的代码首先绘制出原始图像,然后在 x 和 y 列表中给定点的 x 坐标和 y 坐标上绘制出红色星状标记点,最后在两个列表表示的前两个点之间绘制一条线段(默认为蓝色)。
该例子的绘制结果如图 1-2 所示。show() 命令首先打开图形用户界面(GUI),然后新建一个图像窗口。该图形用户界面会循环阻断脚本,然后暂停,直到最后一个图像窗口关闭。在每个脚本里,你只能调用一次 show() 命令,而且通常是在脚本的结尾调用。注意,在 PyLab 库中,我们约定图像的左上角为坐标原点。
图像的坐标轴是一个很有用的调试工具;但是,如果你想绘制出较美观的图像,加上下列命令可以使坐标轴不显示:
axis('off')
上面的命令将绘制出如图 1-2 右边所示的图像。
图 1-2:Matplotlib 绘图示例。带有坐标轴和不带坐标轴的包含点和一条线段的图像
在绘图时,有很多选项可以控制图像的颜色和样式。最有用的一些短命令如表 1-1、表 1-2 和表 1-3 所示。
使用方法见下面的例子:
from PIL import Image from pylab import * # 读取图像到数组中 im = array(Image.open('data/empire.jpg')) # 绘制图像 imshow(im) # 一些点 x = [100,100,400,400] y = [200,500,200,500] plot(x,y) # 默认为蓝色实线 # plot(x,y,'r*') # 红色星状标记 # plot(x,y,'go-') # 带有圆圈标记的绿线 # plot(x,y,'ks:') # 带有正方形标记的黑色虚线 # 绘制连接前两个点的线 plot(x[:2],y[:2]) # 添加标题,显示绘制的图像 title('Plotting: "empire.jpg"') # axis('off') show()
默认为以下蓝色实线