PIL(Python Imaging Library,图像处理库)提供了通用的图像处理功能,以及大量有用的基本图像操作。PIL库已经集成在Anaconda库中,推荐使用Anaconda,简单方便,常用库都已经集成。
(1)读入图片,这是所有操作中的基本中的基本操作:
from PIL import Image
from pylab import *
# 添加中文字体支持
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
figure()
pil_im = Image.open('D:\Data\school.jpg')
gray()
subplot(121)
title(u'原图',fontproperties=font)
axis('off')
imshow(pil_im)
pil_im = Image.open('D:\Data\school.jpg').convert('L')
subplot(122)
title(u'灰度图',fontproperties=font)
axis('off')
imshow(pil_im)
标题安装PCV库的方法和步骤
下载PCV库文件数据
将下载的文件解压
打开cmd,执行如下指令:
(1)执行cd命令,转到你所解压到的PCV的文件夹中。
(2)输入python setup.py install。
(3)重启命令行,输入import PCV,如果没有报错,则说明PCV库安装成功。
PIL中的open()函数用于创建PIL图像对象,sace()方法用于保存如下到指定文件名的文件夹,上述过程将后缀变为.png,但文件名不变。
示例:
from PCV.tools.imtools import get_imlist #导入原书的PCV模块
from PIL import Image
import os
import pickle
filelist = get_imlist('D:/Python Computer Vision/') #获取图片文件名(包括后缀名)
imlist = open('D:/Python Computer Vision/imlist.txt','wb+')
#将获取的图片文件列表保存到imlist.txt中
pickle.dump(filelist,imlist) #序列化
imlist.close()
for infile in filelist:
outfile = os.path.splitext(infile)[0] + ".png" #分离文件名与扩展名
if infile != outfile:
try:
Image.open(infile).save(outfile)
except IOError:
print ("cannot convert", infile)
from PIL import Image
from pylab import *
im = Image.open('D:\Data\school.jpg', "r")
school = im.save('D:\Data\School-.png', 'png')
school.show()
处理效果:
分析:
PIL中的open()函数用于创建PIL图像对象,sace()方法用于保存如下到指定文件名的文件夹,上述过程将后缀变为.png,但文件名不变。代码将jpg图像重新保存成png格式。注意,保存文件的文件名很重要,除非指定格式,否则这个库将会以文件名的扩展名作为格式保存。
利用PIL可以很容易的创建缩略图,设置缩略图的大小,并用元组保存起来,调用thumnail() 方法即可生成缩略图。创建缩略图的代码:
thumbnail(size,resample)
thumbnail方法是原地操作,返回值是None。第一个参数是指定的缩略图的大小,第二个是采样的,有Image.BICUBIC,PIL.Image.LANCZOS,PIL.Image.BILINEAR,PIL.Image.NEAREST这四种采样方法。默认是Image.BICUBIC。
例如创建最长边为128像素的缩略图:
pil_im.thumbnail((128,128))
例程:
from PIL import Image
from pylab import *
im = Image.open('D:\Data\school.jpg', "r")
subplot(121)
title('(original)')
axis('off')
imshow(im)
im.save('D:\Data\school.png', 'png')
im.thumbnail((128, 128), resample=Image.BICUBIC)
subplot(122)
title('(breviary)')
axis('off')
imshow(im)
show()
处理效果:
分析:
改变像素后,缩略图像比原图模糊,整体信息还在。
调用crop() 方法即可从一幅图像中进行区域拷贝,拷贝出区域后,可以对区域进行旋转等变换。
剪裁指定区域:
from PIL import Image
from pylab import *
im = Image.open('D:\Data\school.jpg', "r")
subplot(121)
title('(original)')
axis('off')
imshow(im)
box = (90,130,200,220)
subplot(122)
title('(copy)')
axis('off')
imshow(im.crop(box))
show()
处理效果:
分析:
box是一个有四个数字的元组(upper_left_x,upper_left_y,lower_right_x,lower_right_y),分别表示裁剪矩形区域的左上角x,y坐标,右下角的x,y坐标,规定图像的最左上角的坐标为原点(0,0),宽度的方向为x轴,高度的方向为y轴,每一个像素代表一个坐标单位。crop()返回的仍然是一个Image对象。
目标区域由四元组来指定,坐标依次为(左,上,右,下),PIL中指定坐标系的左上角坐标为(0,0),可以旋转后利用paste() 放回去,具体实现如下:
region=region.transpose(Image.ROTATE_180)
pil_im.paste(region,box)
from PIL import Image
from pylab import *
im = Image.open('D:\Data\school.jpg', "r")
subplot(131)
title('(original)')
axis('off')
imshow(im)
box = (90,130,200,220)
subplot(132)
title('(copy)')
axis('off')
imshow(im.crop(box))
region = im.crop(box)
im.paste(region,(200,220),None)
subplot(133)
title('(past)')
axis('off')
imshow(im)
show()
处理效果:
分析:
将region图像粘贴到左上角为(200,220)的位置 。region是要粘贴的Image对象,box是要粘贴的位置,可以是一个两个元素的元组,表示粘贴区域的左上角坐标,也可以是一个四个元素的元组,表示左上角和右下角的坐标。如果是四个元素元组的话,box的size必须要和region的size保持一致,否则将会被转换成和region一样的size。
(1)要调整一幅图像的尺寸,我们可以调用resize()方法。该方法的参数是一个元组,用来指定新图像的大小:
resize(size,resample,box)
from PIL import Image
from pylab import *
im = Image.open('D:\Data\collage.jpg', "r")
im.show()
im_resize = im.resize((200,200))
im_resize.show()
im_resize_box = im.resize((50,50),box = (1000,1000,1500,1500))
im_resize_box.show()
分析:
resize方法可以将原始的图像转换大小,size是转换之后的大小,可以看出图像越来越小,resample是重新采样使用的方法,默认PIL.Image.NEAREST,box是指定的要resize的图像区域 ,是一个用四个元组指定的区域。
(2)要旋转一幅图像,可以使用逆时针方式表示旋转角度,然后调用
out=pil_im.rotate(method)
im = Image.open('D:\Data\collage.jpg', "r")
subplot(331)
title('original')
axis('off')
imshow(im)
Image.FLIP_LEFT_RIGHT = im.transpose(Image.FLIP_LEFT_RIGHT)
subplot(332)
title('up')
axis('off')
imshow(Image.FLIP_LEFT_RIGHT)
Image.FLIP_TOP_BOTTOM = im.transpose(Image.FLIP_TOP_BOTTOM)
subplot(333)
title('down')
axis('off')
imshow(Image.FLIP_TOP_BOTTOM)
Image.ROTATE_45 = im.rotate(45)
subplot(334)
title('rotate-45')
axis('off')
imshow(Image.ROTATE_45)
Image.ROTATE_90 = im.transpose(Image.ROTATE_90)
subplot(335)
title('rotate-90')
axis('off')
imshow(Image.ROTATE_90)
Image.ROTATE_180 = im.transpose(Image.ROTATE_180)
subplot(336)
title('rotate-180')
axis('off')
imshow(Image.ROTATE_180)
Image.ROTATE_270 = im.transpose( Image.ROTATE_270)
subplot(337)
title('rotate-270')
axis('off')
imshow( Image.ROTATE_270)
Image.TRANSPOSE = im.transpose(Image.TRANSPOSE)
subplot(338)
title('left-h')
axis('off')
imshow(Image.TRANSPOSE)
Image.TRANSVERSE = im.transpose(Image.TRANSVERSE)
subplot(339)
title('right-h')
axis('off')
imshow(Image.TRANSVERSE)
show()
处理效果:
分析:
method表示选择什么样的翻转或者旋转方式,transpose() 方法可以将图片左右颠倒、上下颠倒、旋转 90°、旋转 180° 或旋转 270°。
from PIL import Image
from pylab import *
# 显示原图
pil_im = Image.open('D:\Data\collage.jpg')
print(pil_im.mode, pil_im.size, pil_im.format)
subplot(231)
title(u'原图', fontproperties=font)
axis('off')
imshow(pil_im)
# 显示灰度图
pil_im = Image.open('D:\Data\collage.jpg').convert('L')
gray()
subplot(232)
title(u'灰度图', fontproperties=font)
axis('off')
imshow(pil_im)
# 复制并粘贴区域
pil_im = Image.open('D:\Data\collage.jpg')
box = (100, 100, 400, 400)
region = pil_im.crop(box)
region = region.transpose(Image.ROTATE_180)
pil_im.paste(region, box)
subplot(233)
title(u'复制粘贴', fontproperties=font)
axis('off')
imshow(pil_im)
# 缩略图
pil_im = Image.open('D:\Data\collage.jpg')
size = 128, 128
pil_im.thumbnail(size)
print(pil_im.size)
subplot(234)
title(u'缩略图', fontproperties=font)
axis('off')
imshow(pil_im)
pil_im.save('D:\Data\collage-breviary.jpg')# 保存缩略图
#调整图像尺寸
pil_im=Image.open('D:\Data\collage.jpg')
pil_im=pil_im.resize(size)
print(pil_im.size)
subplot(235)
title(u'调整尺寸图',fontproperties=font)
axis('off')
imshow(pil_im)
#旋转图像45°
pil_im=Image.open('D:\Data\collage.jpg')
pil_im=pil_im.rotate(45)
subplot(236)
title(u'旋转45°图',fontproperties=font)
axis('off')
imshow(pil_im)
show()
处理数学运算、绘制图表,或者在图像上绘制点、直线和曲线时,Matplotlib 是个很好的类库,具有比 PIL 更强大的绘图功能。Matplotlib 可以绘制出高质量的 图表,就像本书中的许多插图一样。Matplotlib 中的 PyLab 接口包含很多方便用户 创建图像的函数。Matplotlib 是开源工具,可以从http://matplotlib.sourceforge.net/ 免费下载。
示例:
from PIL import Image
from pylab import *
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
# 读取图像到数组中
im = array(Image.open('D:\Data\school.jpg'))
figure()
# 绘制有坐标轴的
subplot(121)
imshow(im)
x = [100, 100, 400, 400]
y = [200, 500, 200, 500]
# 使用红色星状标记绘制点
plot(x, y, 'r*')
# 绘制连接两个点的线(默认为蓝色)
plot(x[:2], y[:2])
title(u'绘制empire.jpg', fontproperties=font)
# 不显示坐标轴的
subplot(122)
imshow(im)
x = [100, 100, 400, 400]
y = [200, 500, 200, 500]
plot(x, y, 'r*')
plot(x[:2], y[:2])
axis('off')
title(u'绘制empire.jpg', fontproperties=font)
show()
总结:
当在处理数学及绘图或在图像上描点、画直线、曲线时,Matplotlib是一个很好的绘图库,它比PIL库提供了更有力的特性。此外:
plot(x,y) #默认为蓝色实线
plot(x,y,'go-') #带有圆圈标记的绿线
plot(x,y,'ks:') #带有正方形标记的黑色虚线
在画图像轮廓前需要转换为灰度图像,因为轮廓需要获取每个坐标[x,y]位置的像素值。绘图都可以调用matplotlib.pyplot库来进行,其中的hist函数可以直接绘制直方图。
示例:
from PIL import Image
from pylab import *
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
# 打开图像,并转成灰度图像
im = array(Image.open('D:\Data\school.jpg').convert('L'))
# 新建一个图像
figure()
subplot(121)
# 不使用颜色信息
gray()
# 在原点的左上角显示轮廓图像
contour(im, origin='image')
axis('equal')
axis('off')
title(u'图像轮廓图', fontproperties=font)
subplot(122)
# 利用hist来绘制直方图
# 第一个参数为一个一维数组
# 因为hist只接受一维数组作为输入,所以要用flatten()方法将任意数组按照行优先准则转化成一个一维数组
# 第二个参数指定bin的个数
hist(im.flatten(), 128)
title(u'图像直方图', fontproperties=font)
# plt.xlim([0,250])
# plt.ylim([0,12000])
show()
n, bins, patches = plt.hist(arr, bins, normed, facecolor, alpha)
hist的参数非常多,但常用的就这五个,只有第一个是必须的,后面四个可选。
返回值 :
当需要和某些应用交互,例如在一幅图像中标记一些点,或者标注一些训练数据。PyLab 库中的 ginput() 函数就可以实现交互式标注。
示例:
from PIL import Image
from pylab import *
im = array(Image.open('D:\Data\collage.jpg'))
imshow(im)
print('Please click 3 points')
x = ginput(3)
print('you clicked:', x)
show()
在绘图窗口的图像区域点击三次。程序将这些点击的坐标 [x, y] 自动保存在 x 列表里:
NumPy(http://www.scipy.org/NumPy/)是非常有名的 Python 科学计算工具包,其中 包含了大量有用的思想,比如数组对象(用来表示向量、矩阵、图像等)以及线性 代数函数。
在前面图像的示例中,我们将图像用array()函数转为NumPy数组对象,但是并没有提到它表示的含义。数组就像列表一样,只不过它规定了数组中的所有元素必须是相同的类型,除非指定以外,否则数据类型灰按照数据类型自动确定。
(1)示例:
from PIL import Image
from pylab import *
im = array(Image.open('D:\Data\collage.jpg'))
print (im.shape, im.dtype)
im = array(Image.open('D:\Data\collage.jpg').convert('L'),'f')
print (im.shape, im.dtype)
输出:
解释:
第一个元组表示图像数组大小(行、列、颜色通道)
第二个字符串表示数组元素的数据类型,因为图像通常被编码为8位无符号整型;
(2)数组元素如何访问——使用下标访问:
value=im[i,j,k]
多个数组元素如何发给我——使用数组切片方式访问,返回的是以指定间隔下标访问该数组的元素值:
im[i,:] = im[j,:] #将第j行的数值赋值给第i行
im[:,j] = 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,:]/im[-2] #倒数第二行
将图像读入NumPy数组对象后,我们可以对它们执行任意数学操作,一个简单的例子就是图像的灰度变换,考虑任意函数,它将0~255映射到自身,也就是输出区间和输入区间相同。
示例:
from PIL import Image
from numpy import *
from pylab import *
im=array(Image.open('D:\Data\collage.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()
pil_im=Image.fromarray(im)
如果之前的操作将”uint8”数据类型转化为其他类型,则在创建PIL图像之前,需要将数据类型转换回来:
pil_im=Image.fromarray(uint8(im))
图像灰度变换中一个非常有用的例子就是直方图均衡化。直方图均衡化是指将一幅图像的灰度直方图变平,使变换后的图像中每个灰度值的分布概率都相同。在对图像做进一步处理之前,直方图均衡化通常是对图像灰度值进行归一化的一个非常好 的方法,并且可以增强图像的对比度。
下面的函数是直方图均衡化的具体实现:
def histeq(im,nbr_bins=256):
""" 对一幅灰度图像进行直方图均衡化"""
# 计算图像的直方图
imhist,bins = histogram(im.flatten(),nbr_bins,normed=True)
cdf = imhist.cumsum() # 累积分布函数
cdf = 255 * cdf / cdf[-1] # 归一化
# 此处使用到累积分布函数cdf的最后一个元素(下标为-1),其目的是将其归一化到0~1范围
# 使用累积分布函数的线性插值,计算新的像素值
im2 = interp(im.flatten(),bins[:-1],cdf)
return im2.reshape(im.shape), cdf
解释:
该函数有两个参数:灰度图像,直方图中使用的bin的数目
函数返回值: 均衡化后的图像,用来做像素值映射的累积分布函数
示例:
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('D:\Data\JM.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, normed=True)
subplot(2, 2, 4)
axis('off')
title(u'均衡化后的直方图', fontproperties=font)
#hist(im2.flatten(), 128, cumulative=True, normed=True)
hist(im2.flatten(), 128, normed=True)
show()
分析:
很明显直方图均衡化后图像的对比度增强了,原先图像灰色区域的细节部分变得清晰。
图像平均操作是减少图像噪声的一种简单方式,通常用于艺术特效。可以简单地从图像列表中计算出一幅平均图像。假设所有的图像具有相同的大小,可以将这些图像简单地相加,然后除以图像的数目,来计算平均图像。
示例:
from PCV.tools.imtools import get_imlist
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)
filelist = get_imlist('D:/Python Computer Vision/') # 获取D:/Python Computer Vision/文件夹下的图片文件名(包括后缀名)
avg = imtools.compute_average(filelist)
for impath in filelist:
im1 = array(Image.open(impath))
subplot(2, 2, filelist.index(impath) + 1)
imshow(im1)
imNum = str(filelist.index(impath) + 1)
title(u'待平均图像' + imNum, fontproperties=font)
axis('off')
subplot(2, 2, 4)
imshow(avg)
title(u'平均后的图像', fontproperties=font)
axis('off')
show()
分析:
该函数包括一些基本的异常处理技巧,自动跳过不能打开的图像。我们还可以使用 mean() 函数计算平均图像,但如果有很多图像,该处理方式需要占用很多内存。
PCA(Principal Component Analysis,主成分分析) 是一个非常有用的降维技巧。它可以在使用尽可能少维数的前提下,尽量多地保持训练数据的信息,在此意义上是一个最佳技巧。即使是一幅 100×100 像素的小灰度图像,也有 10 000 维,可以看成 10 000 维空间中的一个点。一兆像素的图像具有百万维。由于图像具有很高的维数,在许多计算机视觉应用中,我们经常使用降维操作。PCA 产生的投影矩阵可以被视为将原始坐标变换到现有的坐标系,坐标系中的各个坐标按照重要性递减排列。
为了对图像数据进行 PCA 变换,图像需要转换成一维向量表示。我们可以使用 NumPy 类库中的flatten() 方法进行变换。
将变平的图像堆积起来,我们可以得到一个矩阵,矩阵的一行表示一幅图像。在计算主方向之前,所有的行图像按照平均图像进行了中心化。我们通常使用== SVD(Singular Value Decomposition,奇异值分解)==方法来计算主成分;但当矩阵的维数很大时,SVD 的计算非常慢,所以此时通常不使用 SVD 分解。
PCA计算步骤(思想是把数据投影到方向向量使数据集的特征向量到方向向量的垂线长度最短)
去平均
计算协方差矩阵
计算协方差矩阵的特征向量和特征值
将特征值从小到大排列
保留最上面的n个特征向量
将数据转换到上述n个特征向量构建新的空间
示例:
from PIL import Image
from numpy import *
def pca(X):
""" 主成分分析:
输入:矩阵X ,其中该矩阵中存储训练数据,每一行为一条训练数据
返回:投影矩阵(按照维度的重要性排序)、方差和均值"""
# 获取维数
num_data,dim = X.shape
# 数据中心化
mean_X = X.mean(axis=0)
X = X - mean_X
if dim>num_data:
# PCA- 使用紧致技巧
M = dot(X,X.T) # 协方差矩阵
e,EV = linalg.eigh(M) # 特征值和特征向量
tmp = dot(X.T,EV).T # 这就是紧致技巧
V = tmp[::-1] # 由于最后的特征向量是我们所需要的,所以需要将其逆转
S = sqrt(e)[::-1] # 由于特征值是按照递增顺序排列的,所以需要将其逆转
for i in range(V.shape[1]):
V[:,i] /= S
else:
# PCA- 使用SVD 方法
U,S,V = linalg.svd(X)
V = V[:num_data] # 仅仅返回前nun_data 维的数据才合理
# 返回投影矩阵、方差和均值
return V,S,mean_X
如果想要保存一些结果或者数据以方便后续使用,Python 中的 pickle 模块非常有用。pickle模块可以接受几乎所有的 Python 对象,并且将其转换成字符串表示,该过程叫做封装(pickling)。从字符串表示中重构该对象,称为拆封(unpickling)。这些字符串表示可以方便地存储和传输。
例子。假设想要保存上一节字体图像的平均图像和主成分,可以这样来完成:
# 保存均值和主成分数据
f = open('font_pca_modes.pkl','wb')
pickle.dump(immean,f)
pickle.dump(V,f)
f.close()
对象可以保存到同一个文件中。pickle 模块中有很多不同的协议可以生成 .pkl 文件;如果不确定的话,最好以二进制文件的形式读取和写入。在其他 Python 会话中载入数据,只需要如下使用 load() 方法:
# 载入均值和主成分数据
f = open('font_pca_modes.pkl','rb')
immean = pickle.load(f)
V = pickle.load(f)
f.close()
注意,载入对象的顺序必须和先前保存的一样。Python 中有个用 C 语言写的优化版本,叫做cpickle 模块,该模块和标准 pickle 模块完全兼容。
示例:
# coding:utf-8
# pickle模块主要函数的应用举例
import pickle
dataList = [[1, 1, 'yes'],
[1, 1, 'yes'],
[1, 0, 'yes'],
[0, 1, 'no'],
[0, 1, 'no']]
dataDic = {
0: [1, 2, 3, 4],
1: ('a', 'b'),
2: {
'c': 'yes', 'd': 'no'}}
# 使用dump()将数据序列化到文件中
fw = open('dataFile.txt', 'wb')
# Pickle the list using the highest protocol available.
pickle.dump(dataList, fw, -1)
# Pickle dictionary using protocol 0.
pickle.dump(dataDic, fw)
fw.close()
# 使用load()将数据从文件中序列化读出
fr = open('dataFile.txt', 'rb')
data1 = pickle.load(fr)
print(data1)
data2 = pickle.load(fr)
print(data2)
fr.close()
# 使用dumps()和loads()举例
p = pickle.dumps(dataList)
print(pickle.loads(p))
p = pickle.dumps(dataDic)
print(pickle.loads(p))
SciPy(http://scipy.org/) 是建立在 NumPy 基础上,用于数值运算的开源工具包。SciPy 提供很多高效的操作,可以实现数值积分、优化、统计、信号处理,以及对我们来说最重要的图像处理功能。
图像的高斯模糊是非常经典的图像卷积例子。本质上,图像模糊就是将(灰度)图像I 和一个高斯核进行卷积操作:
I δ = I ∗ G δ I_\delta=I* G_\delta Iδ=I∗Gδ
其中, ∗ * ∗表示卷积, G δ G_\delta 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('D:\Data\school.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()
处理效果:
总结:
上面第一幅图为待模糊图像,第二幅用高斯标准差为2进行模糊,第三幅用高斯标准差为5进行模糊,最后一幅用高斯标准差为10进行模糊。图像显示随着 σ 的增加,一幅图像被模糊的程度。σ 越大,处理后的图像细节丢失越多。如果打算模糊一幅彩色图像,可以对每一个颜色通道进行高斯模糊。
在很多应用中图像强度的变化情况是非常重要的信息。强度的变化可以用灰度图像 I I I(对于彩色图像,通常对每个颜色通道分别计算导数)的 x x x 和 y y y方向导数 I x Ix Ix和 I y Iy Iy 进行描述。
图像的梯度向量为: ∇ I = [ I x , I y ] T ∇I = [I_x, I_y]^T ∇I=[Ix,Iy]T
描述图像在每个像素点上强度变化最大的方向
梯度有两个重要的属性:
∣ ∇ I ∣ = I x 2 + I y 2 |∇I| = \sqrt {I_x^2+I_y^2} ∣∇I∣=Ix2+Iy2
α = a r c t a n 2 ( I x , I y ) \alpha=arctan2(I_x, I_y) α=arctan2(Ix,Iy)
可以用离散近似的方式来计算图像的导数。图像导数大多数可以通过卷积简单地实现:
I x = I ∗ D x I_x=I*D_x Ix=I∗Dx, I y = I ∗ D y I_y=I*D_y Iy=I∗Dy
对于,通常选择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('D:\Data\school.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()
处理效果:
**缺陷:**在该方法中,滤波器的尺度需要随着图像分 辨率的变化而变化。为了在图像噪声方面更稳健,以及在任意尺度上计算导数,可以使用高斯导数滤波器:
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('D:\Data\school.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()
总结:
第一列为原始灰度图像分别使用σ=2 ,σ=5,σ=10的高斯导数滤波器处理后的图像。
第二列为x 导数图像分别使用σ=2 ,σ=5,σ=10的高斯导数滤波器处理后的图像。
第三列为y 导数图像分别使用σ=2 ,σ=5,σ=10的高斯导数滤波器处理后的图像。
第四列为梯度大小图像分别使用σ=2 ,σ=5,σ=10的高斯导数滤波器处理后的图像。
形态学(或数学形态学)是度量和分析基本形状的图像处理方法的基本框架与集合。形态学通常用于处理二值图像,但是也能够用于灰度图像。二值图像是指图像的每个像素只能取两个值,通常是 0 和 1。二值图像通常是,在计算物体的数目,或者度量其大小时,对一幅图像进行阈值化后的结果。
scipy.ndimage 中的 morphology 模块可以实现形态学操作
scipy.ndimage 中的measurements 模块来实现二值图像的计数和度量功能
from PIL import Image
from numpy import *
from scipy.ndimage import measurements, morphology
from pylab import *
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('D:\Data\pkq.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()
图像去噪是在去除图像噪声的同时,尽可能地保留图像细节和结构的处理技术。这里使用 ==ROF(Rudin-Osher-Fatemi)==去噪模型。 图像去噪对于很多应用来说都非常重要;这些应用范围很广,小到让假期照片看起来更漂亮,大到提高卫星图像的质量。ROF 模型具有很好的性质:使处理后的图像更平滑,同时保持图像边缘和结构信息。
from pylab import *
from numpy import *
from numpy import random
from scipy.ndimage import filters
from scipy.misc import imsave
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()