赞
踩
目录
读取一幅图像:
- from PIL import Image
- pil_im=Image.open('empire.jpg')
上述代码的返回值pil_im是一个PIL图像对象。
读取图像同时转化为灰度图像:
pil_im=Image.open('empire.jpg').convert('L')
转换为JPEG格式:
- from PIL import Image
- import os
-
- for infile infilelist:
- outfile=os.path.splitext(infile)[0]+".jpg"
- if infile !=outfile:
- try:
- Image.open(infile).save(outfile)
- except IOError:
- print "cannot convert",infile
PIL的open()函数用于创建PIL图像对象,save()方法一用于保存图像到具有指定文件名的文件。
下面将创建一个包含文件夹中所有图像的文件名列表,首先新建一个文件,命名为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')]
thumbnail()方法接受一个元组参数(该参数指定生成缩略图的大小),然后将图像转换成符合元组参数指定大小的缩略图。例如:
pil_im.thumbnail((128,128))
使用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)
调整图像尺寸:
out = pil_im.resize((128,128))
旋转图像:
out = pil_im.rotate(45)
一个使用点和线绘制图像的例子:
- from PIL import Image
- from pylab import *
- # 读取图像到数组中
- im = array(Image.open(r'G:\1.jpg'))
- # 绘制图像
- imshow(im)
- # 一些点
- x = [1000,4000,1000,4000]
- y = [500,500,3000,3000]
- # 使用红色星状标记绘制点
- plot(x,y,'r*')
- # 绘制连接前两个点的线
- plot(x[:2],y[:2])
- # 添加标题,显示绘制的图像
- title('Plotting: "empire.jpg"')
- show()
每个脚本只能调用一次show()命令,而且通常是在脚本的结尾调用。
关闭坐标轴显示:
axis('off')
绘图时控制图像颜色和样式的短命令:
- plot(x,y) # 默认为蓝色实线
- plot(x,y,'r*') # 红色星状标记
- plot(x,y,'go-') # 带有圆圈标记的绿线
- plot(x,y,'ks:') # 带有正方形标记的黑色虚线
绘制图像轮廓:
- from PIL import Image
- from pylab import *
- # 读取图像到数组中
- im = array(Image.open('2.jpg').convert('L'))
- # 新建一个图像
- figure()
- # 不使用颜色信息
- gray()
- # 在原点的左上角显示轮廓图像
- contour(im, origin='image')
- axis('equal')
- show()
绘制图像直方图:
- figure()
- hist(im.flatten(),128)
hist()只接受一维数组作为输入,所以在绘制图像直方图之前,必须先对图像进行压平处理。
绘制一幅图像,然后等待用户点击三次,依序将这些点击的坐标[x,y]自动保存在x列表里:
- from PIL import Image
- from pylab import *
- im = array(Image.open('8.jpg'))
- imshow(im)
- print ('Please click 3 points')
- x = ginput(3)
- print ('you clicked:',x)
- show()
Numpy中的数组对象是多维的,但是元素必须有相同的数据类型。
- im = array(Image.open('empire.jpg'))
- print im.shape, im.dtype
- im = array(Image.open('empire.jpg').convert('L'),'f')
- print im.shape, im.dtype
输出结果:
每行的第一个元组表示图像数组的大小(行、列、颜色通道),紧接着的字符串表示数组元素的数据类型。因为图像通常被编码成无符号八位整数(uint8),所以在第一种情况下,载入图像并将其转换到数组中,数组的数据类型为“uint8”。在第 二种情况下,对图像进行灰度化处理,并且在创建数组时使用额外的参数“f”;该参数将数据类型转换为浮点型。
数组中的元素可以使用下标访问。i,j为坐标,k为颜色通道。
value = im[i,j,k]
多个数组元素可以使用数组切片方式访问。切片方式返回的是以指定间隔下标访问该数组的元素值。下面是有关灰度图像的一些例子:
- im[i,:] = im[j,:] # 将第 j 行的数值赋值给第 i 行
- im[:,i] = 100 # 将第 i 列的所有数值设为 100
- im[:100,:50].sum() # 计算前 100 行、前 50 列所有数值的和
- im[50:100,50:100] # 50~100 行,50~100 列(不包括第 100 行和第 100 列)
- im[i].mean() # 第 i 行所有数值的平均值
- im[:,-1] # 最后一列
- im[-2,:] (or im[-2]) # 倒数第二行
如果仅使用一个下标,则该下标为行下标。
下面是对一幅图像进行灰度变换的一些例子:
- from PIL import Image
- from numpy import *
- from pylab import *
-
- im=array(Image.open('14.jpg').convert('L'))
- print(int(im.min()),int(im.max()))
-
- im2=255-im #对图像进行反向处理
- print(int(im2.min()),int(im2.max())) #查看最大/最小元素
-
- im3=(100.0/255)*im+100 #将图像像素值变换到100...200区间
- print(int(im3.min()),int(im3.max()))
-
- im4=255.0*(im/255.0)**2 #对像素值求平方后得到的图像
- print(int(im4.min()),int(im4.max()))
-
- figure()
- gray()
- subplot(131)
- imshow(im2)
- axis('off')
- title(r'$f(x)=255-x$')
-
- subplot(132)
- imshow(im3)
- axis('off')
- title(r'$f(x)=\frac{100}{255}x+100$')
-
- subplot(133)
- imshow(im4)
- axis('off')
- title(r'$f(x)=255(\frac{x}{255})^2$')
-
- show()
图像中最大和最小像素值:
array()变换的相反操作可以使用PIL的formarray()函数完成:
pil_im=Image.fromarray(im)
如果之前的操作将“uint8”数据类型转换为其他数据类型,那么在创建PIL图像之前,需要将数据类型转换回来:
pil_im=Image.fromarray(uint8(im))
Numpy总是将数组数据类型转换成能够表示数据的“最低”数据类型。对浮点数做乘积或除法操作会使整数类型的数组变成点类型。
想要对图像进行缩放处理没有现成简单的方法。我们可以使用之前PIL对图像对象转换的操作,写一个简单的用于图像缩放的函数。
- def imresize(im,sz):
- """ Resize an image array using PIL. """
- pil_im = Image.fromarray(uint8(im))
-
- return array(pil_im.resize(sz))
直方图均衡化是指将一幅图像的灰度直方图变平,使变换后的图像中每个灰度值的分布概率都相同。在对图像做进一步处理之前,直方图均衡化通常是对图像灰度值进行归一化的一个非常好的方法,并且可以增强图像的对比度。
直方图均衡化的变换函数是图像中像素值的累积分布函数:
- from PIL import Image
- from pylab import *
- from PCV.tools import imtools
- # 添加中文字体支持
- from matplotlib.font_manager import FontProperties
- font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
- im = array(Image.open('14.jpg').convert('L'))
- # 打开图像,并转成灰度图像
- #im = array(Image.open('../data/AquaTermi_lowcontrast.JPG').convert('L'))
- im2, cdf = imtools.histeq(im)
- figure()
- subplot(2, 2, 1)
- axis('off')
- gray()
- title(u'原始图像', fontproperties=font)
- imshow(im)
- subplot(2, 2, 2)
- axis('off')
- title(u'直方图均衡化后的图像', fontproperties=font)
- imshow(im2)
- subplot(2, 2, 3)
- axis('off')
- title(u'原始直方图', fontproperties=font)
- #hist(im.flatten(), 128, cumulative=True, normed=True)
- hist(im.flatten(), 128, density=True)
- subplot(2, 2, 4)
- axis('off')
- title(u'均衡化后的直方图', fontproperties=font)
- #hist(im2.flatten(), 128, cumulative=True, normed=True)
- hist(im2.flatten(), 128, density=True)
- show()
明显可以看出均衡化后的直方图有了明显变化,图像对比度也增加。此外,参考代码有一些改动:
normed=True
由于 Rectangle 这个库更新,现在已经没有normed属性了。需要将其改为如下形式:
density=True
图像平均操作是减少图像噪声的一种简单方式。我们可以简单地从图像列表中计算出一幅平均图像。下面的函数可以用于计算平均图像,将其添加到文件中:
- def compute_average(imlist):
- """ 计算图像列表的平均图像"""
-
- # 打开第一幅图像,将其存储在浮点型数组中
- averageim = array(Image.open(imlist[0]), 'f')
-
- for imname in imlist[1:]:
- try:
- averageim += array(Image.open(imname))
- except:
- print imname + '...skipped'
- averageim /= len(imlist)
-
- # 返回uint8 类型的平均图像
- return array(averageim, 'uint8')
PCA(Principal Component Analysis,主成分分析)是一个非常有用的降维技巧。它可以在使用尽可能少维数的前提下,尽量多地保持训练数据的信息,在此意义上是一个最佳技巧。即使是一幅 100×100像素的小灰度图像,也有10000维,可以看成10000维空间中的一个点。一兆像素的图像具有百万维。由于图像具有很高的维数,在许多计算机视觉应用中,我们经常使用降维操作。PCA 产生的投影矩阵可以被视为将原始坐标变换到现有的坐标系,坐标系中的各个坐标按照重要性递减排列。
为了对图像数据进行 PCA 变换,图像需要转换成一维向量表示。我们可以使用 NumPy 类库中的flatten()方法进行变换。
将变平的图像堆积起来,我们可以得到一个矩阵,矩阵的一行表示一幅图像。在计算主方向之前,所有的行图像按照平均图像进行了中心化。我们通常使用 SVD(Singular Value Decomposition,奇异值分解)方法来计算主成分;但当矩阵的维数很大时,SVD 的计算非常慢,所以此时通常不使用 SVD 分解。
该函数首先通过减去每一维的均值将数据中心化,然后计算协方差矩阵对应最大特征值的特征向量,此时可以使用简明的技巧或者 SVD 分解。这里我们使用了 range() 函数,该函数的输入参数为一个整数 n,函数返回整数 0…(n-1) 的一个列表。你也可以使用 arange() 函数来返回一个数组,或者使用 xrange() 函数返回一个产生器(可能会提升速度)。我们在本书中贯穿使用range() 函数。
如果数据个数小于向量的维数,我们不用 SVD 分解,而是计算维数更小的协方差矩阵 XXT 的特征向量。通过仅计算对应前 k(k 是降维后的维数)最大特征值的特征向量,可以使上面的 PCA 操作更快。由于篇幅所限,有兴趣的读者可以自行探索。矩阵 V 的每行向量都是正交的,并且包含了训练数据方差依次减少的坐标方向。
python中的pickle模块可以保存一些结果或者数据以便后续使用。pickle模块可以接受几乎所有的python对象,并且将其转换成字符串表示,这个过程叫做封装(pickling)。从字符串表示中重构该对象,称为拆封(unpickling)。这些字符串表示可以方便地存储和传输。
pickle模块中有很多不同的协议可以生成.pkl文件;如果不确定的话,最好以二进制文件的形式读取和写入。在其他python会话中载入数据,只需要使用load()方法。
with语句可以自动打开和关闭文件(即使在文件打开时发生错误)。
图像的高斯模糊是非常经典的图像卷积例子。本质上,图像模糊就是将(灰度)图像I和一个高斯核进行卷积操作:
其中*表示卷积操作;Gδ是标准差为δ的二位高斯核,定义为:
高斯模糊通常是其他图像处理操作的一部分,比如图像差值操作、兴趣点计算以及其他应用。
滤波操作:scipy.ndimage.filters
- from PIL import Image
- from numpy import *
- from pylab import *
- from scipy.ndimage import filters
- # 添加中文字体支持
- from matplotlib.font_manager import FontProperties
- font=FontProperties(fname=r"c:\windows\fonts\SimSun.ttc",size=14)
- im=array(Image.open('14.jpg').convert('L'))
- figure()
- gray()
- axis('off')
- subplot(141)
- axis('off')
- title(u'原图',fontproperties=font)
- imshow(im)
-
- for bi,blur in enumerate([2,5,10]):
- im2=zeros(im.shape)
- im2=filters.gaussian_filter(im,blur)
- im2=np.uint8(im2)
- imNum=str(blur)
- subplot(1,4,2+bi)
- axis('off')
- title(u'标准差为'+imNum,fontproperties=font)
- imshow(im2)
- show()
随着δ值增加,图像逐渐变模糊,图像细节丢失越多。
在很多应用中图像强度的变化情况是非常重要的信息。强度的变化可以用灰度图像I(对于彩色图像,通常对每个颜色通道分别计算导数)的x和y方向导数Ix和Iy进行描述。
梯度大小描述了图像强度变化的强弱:
梯度角度描述了图像在每个点(像素)上强度变化最大的方向:
Numpy中的arctan2()函数返回弧度表示的有符号角度,角度的变化区间为-π...π。
我们可以用离散近似的方式来计算图像的导数。图像导数大多数可以通过卷积简单地实现:
prewitt滤波器:
或者sobel滤波器:
这些导数滤波器可以使用scipy.ndimage.filters模块的标准卷积操作来简单地实现,例如:
- from PIL import Image
- from pylab import *
- from scipy.ndimage import filters
- import numpy
-
- # 添加中文字体支持
- from matplotlib.font_manager import FontProperties
- font=FontProperties(fname=r"c:\windows\fonts\SimSun.ttc",size=14)
-
- im=array(Image.open('14.jpg').convert('L'))
- gray()
-
- subplot(141)
- axis('off')
- title(u'(a)原图',fontproperties=font)
- imshow(im)
-
- # sobel derivative filters
- imx=zeros(im.shape)
- filters.sobel(im,1,imx)
- subplot(142)
- axis('off')
- title(u'(b)x方向差分',fontproperties=font)
- imshow(imx)
-
- imy=zeros(im.shape)
- filters.sobel(im,0,imy)
- subplot(143)
- axis('off')
- title(u'(c)y方向差分',fontproperties=font)
- imshow(imy)
-
- mag=255-numpy.sqrt(imx**2+imy**2)
- subplot(144)
- title(u'(d)梯度幅值',fontproperties=font)
- axis('off')
- imshow(mag)
-
- show()
上面的脚本使用Sobel滤波器计算x和y方向导数以及梯度大小。在导数图像中,正导数显示为亮的像素,负倒数显示为暗的像素,灰色区域表示导数的值接近于零。
高斯导数滤波器:
- from PIL import Image
- from pylab import *
- from scipy.ndimage import filters
- import numpy
-
- # 添加中文字体支持
- #from matplotlib.font_manager import FontProperties
- #font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
-
- def imx(im, sigma):
- imgx = zeros(im.shape)
- filters.gaussian_filter(im, sigma, (0, 1), imgx)
- return imgx
-
-
- def imy(im, sigma):
- imgy = zeros(im.shape)
- filters.gaussian_filter(im, sigma, (1, 0), imgy)
- return imgy
-
-
- def mag(im, sigma):
- # there's also gaussian_gradient_magnitude()
- #mag = numpy.sqrt(imgx**2 + imgy**2)
- imgmag = 255 - numpy.sqrt(imgx ** 2 + imgy ** 2)
- return imgmag
- im = array(Image.open('14.jpg').convert('L'))
- figure()
- gray()
- sigma = [2, 5, 10]
- for i in sigma:
- subplot(3, 4, 4*(sigma.index(i))+1)
- axis('off')
- imshow(im)
- imgx=imx(im, i)
- subplot(3, 4, 4*(sigma.index(i))+2)
- axis('off')
- imshow(imgx)
- imgy=imy(im, i)
- subplot(3, 4, 4*(sigma.index(i))+3)
- axis('off')
- imshow(imgy)
- imgmag=mag(im, i)
- subplot(3, 4, 4*(sigma.index(i))+4)
- axis('off')
- imshow(imgmag)
- show()
结果反映了x、y倒数图形及梯度大小图像,δ值越大模糊效果越强,图像细节丢失越多。
形态学(或数学形态学)是度量和分析基本形状的图像处理方法的基本框架与集合。形态学通常用于处理二值图像,但是也能够用于灰度图像。二值图像是指图像的每个像素只能取两个值,通常是0和1。二值图像通常是,在计算物体的数目,或者度量其大小时,对一幅图像进行阈值化后的结果。
scipy.ndimage中的morphology模块可以实现形态学操作,可以使用scipy.ndimage中的measurements模块来实现二值图像的计数和度量功能。
- 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
上述脚本:
- # 形态学开操作更好地分离各个对象
- 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()函数的第二个参数指定一个数组元素。该数组表示以一个像素为中心时,使用哪些相邻像素。参数iterations决定执行该操作的次数。
- from PIL import Image
- from numpy import *
- from scipy.ndimage import measurements, morphology
- from pylab import *
-
- """ This is the morphology counting objects example in Section 1.4. """
-
- # 添加中文字体支持
- from matplotlib.font_manager import FontProperties
- font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
-
- # load image and threshold to make sure it is binary
- figure()
- gray()
- im = array(Image.open('jishu.jpg').convert('L'))
- subplot(221)
- imshow(im)
- axis('off')
- title(u'原图', fontproperties=font)
- im = (im < 128)
-
- labels, nbr_objects = measurements.label(im)
- print ("Number of objects:", nbr_objects)
- subplot(222)
- imshow(labels)
- axis('off')
- title(u'标记后的图', fontproperties=font)
-
- # morphology - opening to separate objects better
- im_open = morphology.binary_opening(im, ones((9, 5)), iterations=2)
- subplot(223)
- imshow(im_open)
- axis('off')
- title(u'开运算后的图像', fontproperties=font)
-
- labels_open, nbr_objects_open = measurements.label(im_open)
- print ("Number of objects:", nbr_objects_open)
- subplot(224)
- imshow(labels_open)
- axis('off')
- title(u'开运算后进行标记后的图像', fontproperties=font)
-
- show()
随着迭代次数iterations值增加,对象数目逐渐减少,直到iterations=12时对象数目为0。
使用scipy.io模块读取.mat文件:
data = scipy.io.loadmat('test.mat')
上面代码中,data对象包含一个字典,字典中的键对应于保存在原始.mat文件中的变量名。由于这些变量是数组格式的,因此可以很方便地保存到.mat文件中。你仅需创建一个字典(其中要包含你想要保存的所有变量),然后使用savemat()函数:
- data = {}
- data['x'] = x
- scipy.io.savemat('test.mat',data)
因为上面的脚本保存的是数组x,所以当读入到Matlab中时,变量的名字仍为x。
imsave()函数可以从scipy.misc模块载入。要将数组im保存到文件中,可以使用下面的命令:
- from scipy.misc import imsave
- imsave('test.jpg',im)
图像去噪是在去除图像噪声的同时,尽可能地保留图像细节和结构的处理技术。我们这里使用 ROF(Rudin-Osher-Fatemi)去噪模型。
一幅(灰度)图像I的全变差定义为梯度范数之和。在连续表示的情况下,全变差表示为:
在离散表示的情况下,全变差表示为:
其中,上面的式子是在所有图像坐标x=[x,y]上取和。
在ROF模型里,目标函数为寻找降噪后的图像U,使下式最小:
- from pylab import *
- from numpy import *
- from numpy import random
- from scipy.ndimage import filters
- import imageio
- from PCV.tools import rof
-
- """ This is the de-noising example using ROF in Section 1.5. """
-
- # 添加中文字体支持
- from matplotlib.font_manager import FontProperties
- font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
-
- # create synthetic image with noise
- im = zeros((500,500))
- im[100:400,100:400] = 128
- im[200:300,200:300] = 255
- im = im + 30*random.standard_normal((500,500))
-
- U,T = rof.denoise(im,im)
- G = filters.gaussian_filter(im,10)
-
-
- # save the result
- #imsave('synth_original.pdf',im)
- #imsave('synth_rof.pdf',U)
- #imsave('synth_gaussian.pdf',G)
-
-
- # plot
- figure()
- gray()
-
- subplot(1,3,1)
- imshow(im)
- #axis('equal')
- axis('off')
- title(u'原噪声图像', fontproperties=font)
-
- subplot(1,3,2)
- imshow(G)
- #axis('equal')
- axis('off')
- title(u'高斯模糊后的图像', fontproperties=font)
-
- subplot(1,3,3)
- imshow(U)
- #axis('equal')
- axis('off')
- title(u'ROF降噪后的图像', fontproperties=font)
-
- show()
其中第一幅图示原噪声图像,中间一幅图示用标准差为10进行高斯模糊后的结果,最右边一幅图是用ROF降噪后的图像。上面原噪声图像是模拟出来的图像,现在我们在真实的图像上进行测试:
- from PIL import Image
- from pylab import *
- from numpy import *
- from numpy import random
- from scipy.ndimage import filters
- import imageio
- from PCV.tools import rof
-
- """ This is the de-noising example using ROF in Section 1.5. """
-
- # 添加中文字体支持
- from matplotlib.font_manager import FontProperties
- font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
-
- im = array(Image.open('jy.png').convert('L'))
-
- U,T = rof.denoise(im,im)
- G = filters.gaussian_filter(im,10)
-
-
- # save the result
- #imsave('synth_original.pdf',im)
- #imsave('synth_rof.pdf',U)
- #imsave('synth_gaussian.pdf',G)
-
-
- # plot
- figure()
- gray()
-
- subplot(1,3,1)
- imshow(im)
- #axis('equal')
- axis('off')
- title(u'原噪声图像', fontproperties=font)
-
- subplot(1,3,2)
- imshow(G)
- #axis('equal')
- axis('off')
- title(u'高斯模糊后的图像', fontproperties=font)
-
- subplot(1,3,3)
- imshow(U)
- #axis('equal')
- axis('off')
- title(u'ROF降噪后的图像', fontproperties=font)
-
- show()
上面的功能实现中,由于版本升级,参考代码中:
from scipy.misc import imsave
应更改为:
import imageio
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。