Python计算机视觉编程1.4  SciPy_Python计算机视觉编程1.4  SciPy试读-查字典图书网
查字典图书网
当前位置: 查字典 > 图书网 > 编程 > Python计算机视觉编程 > 1.4  SciPy

Python计算机视觉编程——1.4  SciPy

SciPy(http://scipy.org/) 是建立在NumPy 基础上, 用于数值运算的开源工具包。SciPy 提供很多高效的操作,可以实现数值积分、优化、统计、信号处理,以及对我们来说最重要的图像处理功能。接下来,本节会介绍SciPy 中大量有用的模块。SciPy 是个开源工具包,可以从http://scipy.org/Download 下载。 1.4.1  图像模糊 图像的高斯模糊是非常经典的图像卷积例子。本质上,图像模糊就是将(灰度)图像I 和一个高斯核进行卷积操作: Iσ = I*Gσ 其中* 表示卷积操作;Gσ 是标准差为σ 的二维高斯核,定义为: G 21 e ()/x y 2 2 2 2 rv = v v - + 高斯模糊通常是其他图像处理操作的一部分,比如图像插值操作、兴趣点计算以及很多其他应用。 SciPy 有用来做滤波操作的scipy.ndimage.filters 模块。该模块使用快速一维分离的方式来计算卷积。你可以像下面这样来使用它: from PIL import Image from numpy import * from scipy.ndimage import filters im = array(Image.open('empire.jpg').convert('L')) im2 = filters.gaussian_filter(im,5) 上面guassian_filter() 函数的最后一个参数表示标准差。 图1-9 显示了随着σ 的增加,一幅图像被模糊的程度。σ 越大,处理后的图像细节丢失越多。如果打算模糊一幅彩色图像,只需简单地对每一个颜色通道进行高斯模糊: im = array(Image.open('empire.jpg')) im2 = zeros(im.shape) for i in range(3): im2[:,:,i] = filters.gaussian_filter(im[:,:,i],5) im2 = uint8(im2) 在上面的脚本中,最后并不总是需要将图像转换成uint8 格式,这里只是将像素值用八位来表示。我们也可以使用: im2 = array(im2,'uint8') 来完成转换。 关于该模块更多的内容以及不同参数的选择,请查看 http://docs.scipy.org/doc /scipy/ reference/ndimage.html 上SciPy 文档中的scipy.ndimage 部分。 图1-9:使用scipy.ndimage.filters 模块进行高斯模糊:(a)原始灰度图像;(b)使用σ=2 的高斯滤波器;(c)使用σ=5 的高斯滤波器;(d)使用σ=10 的高斯滤波器 1.4.2  图像导数 整本书中可以看到,在很多应用中图像强度的变化情况是非常重要的信息。强度的变化可以用灰度图像I(对于彩色图像,通常对每个颜色通道分别计算导数)的x 和y 方向导数Ix 和Iy 进行描述。 图像的梯度向量为[, ] I I I x y T d = 。梯度有两个重要的属性,一是梯度的大小: I I I x y 2 2 d = + 它描述了图像强度变化的强弱,一是梯度的角度: α=arctan2(Iy, Ix) 描述了图像中在每个点(像素)上强度变化最大的方向。NumPy 中的arctan2() 函数返回弧度表示的有符号角度,角度的变化区间为-π...π。 我们可以用离散近似的方式来计算图像的导数。图像导数大多数可以通过卷积简单地实现: Ix=I*Dx 和Iy=I*Dy 对于Dx 和Dy,通常选择Prewitt 滤波器: 或者Sobel 滤波器: 这些导数滤波器可以使用scipy.ndimage.filters 模块的标准卷积操作来简单地实现,例如: from PIL import Image from numpy import * from scipy.ndimage import filters im = array(Image.open('empire.jpg').convert('L')) # Sobel 导数滤波器 imx = zeros(im.shape) filters.sobel(im,1,imx) imy = zeros(im.shape) filters.sobel(im,0,imy) magnitude = sqrt(imx**2+imy**2) 上面的脚本使用Sobel 滤波器来计算x 和y 的方向导数,以及梯度大小。sobel() 函数的第二个参数表示选择x 或者y 方向导数,第三个参数保存输出的变量。图1-10 显示了用Sobel 滤波器计算出的导数图像。在两个导数图像中,正导数显示为亮的像素,负导数显示为暗的像素。灰色区域表示导数的值接近于零。 图1-10:使用Sobel 导数滤波器计算导数图像:(a)原始灰度图像;(b)x 导数图像;(c) y 导数图像;(d)梯度大小图像 上述计算图像导数的方法有一些缺陷:在该方法中,滤波器的尺度需要随着图像分辨率的变化而变化。为了在图像噪声方面更稳健,以及在任意尺度上计算导数,我们可以使用高斯导数滤波器: Ix=I*Gσx 和Iy=I*Gσy 其中,Gσx 和Gσy 表示Gσ 在x 和y 方向上的导数,Gσ 为标准差为σ 的高斯函数。 我们之前用于模糊的filters.gaussian_filter() 函数可以接受额外的参数,用来计算高斯导数。可以简单地按照下面的方式来处理: sigma = 5 # 标准差 imx = zeros(im.shape) filters.gaussian_filter(im, (sigma,sigma), (0,1), imx) imy = zeros(im.shape) filters.gaussian_filter(im, (sigma,sigma), (1,0), imy) 该函数的第三个参数指定对每个方向计算哪种类型的导数,第二个参数为使用的标准差。你可以查看相应文档了解详情。图1-11 显示了不同尺度下的导数图像和梯度大小。你可以和图1-9 中做相同尺度模糊的图像做比较。 图1-11:使用高斯导数计算图像导数:x 导数图像(上),y 导数图像(中),以及梯度大小图像(下);(a)为原始灰度图像,(b)为使用σ=2 的高斯导数滤波器处理后的图像,(c)为使用σ=5 的高斯导数滤波器处理后的图像,(d)为使用σ=10 的高斯导数滤波器处理后的图像 1.4.3  形态学:对象计数 形态学(或数学形态学)是度量和分析基本形状的图像处理方法的基本框架与集合。形态学通常用于处理二值图像,但是也能够用于灰度图像。二值图像是指图像的每个像素只能取两个值,通常是0 和1。二值图像通常是,在计算物体的数目,或者度量其大小时,对一幅图像进行阈值化后的结果。你可以从http://en.wikipedia.org/ wiki/Mathematical_morphology 大体了解形态学及其处理图像的方式。 scipy.ndimage 中的morphology 模块可以实现形态学操作。你可以使用scipy. ndimage 中的measurements 模块来实现二值图像的计数和度量功能。下面通过一个简单的例子介绍如何使用它们。 考虑在图1-12a1 里的二值图像,计算该图像中的对象个数可以通过下面的脚本实现: from scipy.ndimage import measurements,morphology # 载入图像,然后使用阈值化操作,以保证处理的图像为二值图像 im = array(Image.open('houses.png').convert('L')) im = 1*(im<128) labels, nbr_objects = measurements.label(im) print "Number of objects:", nbr_objects 注1: 这个图像实际上是图像“分割”后的结果。如果你想知道该图像是如何创建的,可以查看9.3 节。 上面的脚本首先载入该图像,通过阈值化方式来确保该图像是二值图像。通过和1 相乘,脚本将布尔数组转换成二进制表示。然后,我们使用label() 函数寻找单个的物体,并且按照它们属于哪个对象将整数标签给像素赋值。图1-12b 是labels 数组的图像。图像的灰度值表示对象的标签。可以看到,在一些对象之间有一些小的连接。进行二进制开(binary open)操作,我们可以将其移除: # 形态学开操作更好地分离各个对象 im_open = morphology.binary_opening(im,ones((9,5)),iterations=2) labels_open, nbr_objects_open = measurements.label(im_open) print "Number of objects:", nbr_objects_open binary_opening() 函数的第二个参数指定一个数组结构元素。该数组表示以一个像素为中心时,使用哪些相邻像素。在这种情况下,我们在y 方向上使用9 个像素(上面4 个像素、像素本身、下面4 个像素),在x 方向上使用5 个像素。你可以指定任意数组为结构元素,数组中的非零元素决定使用哪些相邻像素。参数iterations 决定执行该操作的次数。你可以尝试使用不同的迭代次数iterations 值, 看一下对象的数目如何变化。你可以在图1-12c 与图1-12d 中查看经过开操作后的图像,以及相应的标签图像。正如你想象的一样,binary_closing() 函数实现相反的操作。我们将该函数和在morphology 和measurements 模块中的其他函数的用法留作练习。你可以从scipy.ndimage 模块文档http://docs.scipy.org/doc/scipy/reference/ ndimage.html 中了解关于这些函数的更多知识。 图1-12:形态学示例。使用二值开操作将对象分开,然后计算物体的数目:(a)为原始二值图像;(b)为对应原始图像的标签图像,其中灰度值表示物体的标签;(c)为使用开操作后的二值图像;(d)为开操作后图像的标签图像 1.4.4  一些有用的SciPy模块 SciPy 中包含一些用于输入和输出的实用模块。下面介绍其中两个模块:io 和misc。 1. 读写.mat文件 如果你有一些数据,或者在网上下载到一些有趣的数据集,这些数据以Matlab的.mat 文件格式存储,那么可以使用scipy.io 模块进行读取。 data = scipy.io.loadmat('test.mat') 上面代码中,data 对象包含一个字典,字典中的键对应于保存在原始.mat 文件中的变量名。由于这些变量是数组格式的,因此可以很方便地保存到.mat 文件中。你仅需创建一个字典(其中要包含你想要保存的所有变量),然后使用savemat() 函数: data = {} data['x'] = x scipy.io.savemat('test.mat',data) 因为上面的脚本保存的是数组x,所以当读入到Matlab 中时,变量的名字仍为x。关于scipy.io 模块的更多内容, 请参见在线文档http://docs.scipy.org/doc/scipy/ reference/io.html。 2. 以图像形式保存数组 因为我们需要对图像进行操作,并且需要使用数组对象来做运算,所以将数组直接保存为图像文件1 非常有用。本书中的很多图像都是这样的创建的。 imsave() 函数可以从scipy.misc 模块中载入。要将数组im 保存到文件中,可以使用下面的命令: from scipy.misc import imsave imsave('test.jpg',im) scipy.misc 模块同样包含了著名的Lena 测试图像: lena = scipy.misc.lena() 该脚本返回一个512×512 的灰度图像数组。 注1: 所有Pylab 图均可保存为多种图像格式,方法是点击图像窗口中的“保存”按钮。

展开全文

推荐文章

猜你喜欢

附近的人在看

推荐阅读

拓展阅读

《Python计算机视觉编程》其他试读目录

• 1.1  PIL:Python图像处理类库
• 1.2  Matplotlib
• 1.3  NumPy
• 1.4  SciPy [当前]
• 1.5  高级示例:图像去噪