一,基本的图像操作和处理

文章目录

    • 1.1 PIL:Python图像处理类库
    • 1.2Matplotlib
      • 1.2.1 绘制图像,点和线
      • 1.2.2 图像轮廓和直方图
      • 1.2.3交互式标注
    • 1.3 NumPy
      • 1.3.1 图像数组表示
      • 1.3.2灰度变换
      • 1.3.3直方图均衡化
      • 1.3.4图像平均
      • 1.3.5 图像的主成分分析(PCA)
      • 1.3.6使用pickle模块
    • 1.4 SciPy
      • 1.4.1 图像模糊
      • 1.4.2 图像导数
      • 1.4.3 形态学:对象计数
    • 1.5高级示例:图像去噪

1.1 PIL:Python图像处理类库

PIL(Python Imaging Libarary Python,图像处理类库)提供了通用的图像处理功能,以及大量有用的基本图像处理操作,比如图像的缩放,裁剪,旋转,颜色变换等。
· 利用PIL(Python图像处理类库),从PIL中导入图像

from PIL import Image

· PIL的 open() 函数用于创建PIL图像对象。

 pil_im=Image.open('C:\\experiment\\test1.jpg')

· save() 方法用于保存图像到具有指定文件名的文件。

tuxiang=pil_im.save('C:\\experiment\\test1.png','png')

· convert() 方法可以实现图像颜色的转换

pil_im=Image.open('C:\\experiment\\test1.jpg').convert('L')

· thumbnail() 方法接受一个元组参数,然后将图像转换成符合元组参数指定大小的缩略图

pil_im.thumbnail((128,128))

· crop() 方法可以从一幅图像中裁剪指定区域:

box=(100,100,400,400)
region=pil_im.crop(box)

· paste() 方法可以将该区域放回去,还能使用tranpose 旋转代码中获取的区域

region=region.transpose(Image.ROTATE_180)
pil_im.paste(region,box)

· **resize()**方法可以调整一幅图像的尺寸,使用元组参数,指定新图像的大小。调用rotate()方法,可以使用逆时针方式表示旋转角度来旋转图像。

out=pil_im.resize(128,128)

基于python的PIL库学习,综合实例

from PIL import Image
>>> im=Image.open('C:\\experiment\\test7.jpg')
>>> im=Image.open('C:\\experiment\\test7.jpg').convert('L')
>>> box=(100,100,200,200)
>>> region=im.crop(box)
>>> region=region.transpose(Image.ROTATE_180)
>>> im.paste(region,box)
>>> im.show()

结果如下:
原始图像
一,基本的图像操作和处理_第1张图片
转换颜色
一,基本的图像操作和处理_第2张图片
将box区域进行裁剪,再旋转180 后放入图像中
一,基本的图像操作和处理_第3张图片

实验总结:
在截取图像时,box的取值很重要,取值错误,会报错:SystemError: tile cannot extend outside image box四元组的坐标依次是(left, top, left+width, top+height)。其他函数实验过程较为简单,直接输入函数,参数即可。

1.2Matplotlib

Matplotlib具有比PIL更强大的绘图功能,优势在于可以绘制出较好的饼状图,条形图,散点图,点和直线曲线。

1.2.1 绘制图像,点和线

 from PIL import Image
>>> from pylab import *
>>> im = array(Image.open('C:\\experiment\\test1.jpg'))
>>> imshow(im)

>>> x=[100,100,200,200]
>>> y=[200,300,200,300]
>>> plot(x,y,'r*')
[]
>>> plot(x[:2],y[:2])
[]
>>> show()

一,基本的图像操作和处理_第4张图片
实验分析:
实验内容:代码首先绘制出原始图像,然后在给定点坐标上绘制红色星状标记点,然后连线。
关于show(),show()命令首先打开图形用户界面,然后新建一个图像窗口,该GUI界面会循环阻断脚本,然后暂停,在每个脚本里,只能调用一次show(),通常结尾处使用。
一,基本的图像操作和处理_第5张图片
一,基本的图像操作和处理_第6张图片
一,基本的图像操作和处理_第7张图片

1.2.2 图像轮廓和直方图

绘制轮廓需要对每个坐标[x,y]的像素值施加同一个阈值,所以首先将其灰度化。

from PIL import Image
>>> from pylab import *
>>> im=array(Image.open('C:\\experiment\\test8.jpg').convert('L'))
>>> figure()
>>> gray() >>> contour(im,origin='image') >>> axis('equal') (0.5, 399.5, 0.5, 270.5) >>> axis('off') (0.5, 399.5, 0.5, 270.5) >>> figure()
>>> hist(im.flatten(),128) >show()

图像轮廓
一,基本的图像操作和处理_第8张图片
图像直方图
一,基本的图像操作和处理_第9张图片
使用hist () 函数来绘制直方图。图像的直方图来表征图像像素值的分布情况。用一定数目的小区间来指定表征像素值的范围,每个小区间会得到落入该小区间表示范围的像素数目。

1.2.3交互式标注

有时用户需要和某些应用交互,例如在一幅图像中标记一些点,或者标注一些训练数据。pylab库中,ginput()函数可以实现交互式标注。

from PIL import Image
from pylab import *
 
 im=im=array(Image.open('C:\\experiment\\test8.jpg'))
 imshow(im)
 print'please click 3 point'
 x=ginput(3)
 print'you click:',x
 show()

上面的脚本首先绘制一幅图像,然后等待用户在绘图窗口空间点击三次。程序将这些点的坐标自动保存在X列表。

1.3 NumPy

1.3.1 图像数组表示

NumPy中的数组对象是多维的,可以用来表示向量,矩阵和图像。一个数组对象很像一个列表,但是数组中所有的元素必须有相同的数据类型。

from PIL import Image
>>> from pylab import *
>>> im=array(Image.open('C:\\experiment\\test8.jpg'))
>im=array(Image.open('C:\\experiment\\test8.jpg').convert('L'),'f')

得到的结果

(271L, 400L) uint8
(271L, 400L) float32

实验分析:每行的第一个元组表示图像数组的大小(行、列、颜色通道),紧接着的字符串表 示数组元素的数据类型。因为图像通常被编码成无符号八位整数(uint8),所以在第一种情况下,载入图像并将其转换到数组中,数组的数据类型为“uint8”。在第二种情况下,对图像进行灰度化处理,并且在创建数组时使用额外的参数“f”;该参数将数据类型转换为浮点型。

1.3.2灰度变换

将图像读入NumPy数组对象后,可以对他们执行任意数学操作,一个简单的例子就是灰度变换。考虑任意函数,输出区间映射到自身,即输出区间与输入区间范围相同。

from PIL import Image
from numpy import *

im = array(Image.open("").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())




一,基本的图像操作和处理_第10张图片
一,基本的图像操作和处理_第11张图片

1.3.3直方图均衡化

直方图均衡化是指将一幅图像的灰度直方图变平,使变换后的图像中每个灰度值的分布概率都相同。在对图像做进一步处理之前,直方图均衡化通常是对图像灰度值进行归一化的一个非常好 的方法,并且可以增强图像的对比度。

from PIL import Image
>>> from numpy import *
>>> from pylab import *
>>> def histeq(im,nbr_bins=256):
	imhist,bins=histogram(im.flatten(),nbr_bins,normed=True)
	cdf=imhist.cumsum()
	cdf=255*cdf / cdf[-1]
	im2=interp(im.flatten(),bins[:-1],cdf)
	return im2.reshape(im.shape),cdf

>>> im1 = Image.open('C:\\experiment\\jianjiji.jpg')
>>> im_gray = im1.convert('L')
>>> im = array(im1,'f')
>>> arr = im.flatten()
>>> figure()
>>> hist(arr,256) >im2,cdf = histeq(im) > figure()
>>> hist(im2.flatten(),256) >show()

一,基本的图像操作和处理_第12张图片

1.3.4图像平均

图像平均操作是减少图像噪声的以一种简单方式,通常用于艺术特效。假设图像具有相同的大小,可以将图像简单相加,然后除以图像的数目,来计算平均图像。

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')

该函数包括一些基本的异常处理技巧,可以自动跳过不能打开的图像。我们还可以使用 mean() 函数计算平均图像。mean() 函数需要将所有的图像堆积到一个数组中;也就是说,如果有很多图像,该处理方式需要占用很多内存。

1.3.5 图像的主成分分析(PCA)

PCA(Principal Component Analysis,主成分分析)是一个非常有用的降维技巧。它可以在使用尽可能少维数的前提下,尽量多地保持训练数据地信息。PCA产生地投影矩阵可以被视为将原始坐标变换到现有坐标系,坐标系中的各个坐标按照重要性递减排列。
为了对图像数据进行PCA变换,图像需要转换成一维向量表示。可以使用NumPy类库中的flatten()方法进行变换。
将变平的图像堆积起来,得到一个矩阵,矩阵的一行表示一幅图像。在计算主方向之前,所有的行图像按照平均图像进行了中心化。

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


1.3.6使用pickle模块

pickle模块可以接受几乎所有的python对象,并且将其转换成字符串表示,这个过程叫做封装。从字符串表示中重构该对象,叫做拆封。这些字符串表示可以方便地存储和传输。多个对象可以保存在同一个文件中,pickle模块中由很多不同的协议可以生成.pkl文件。在其他Python会话中载入数据,需要使用函数load()即可。

#保存均值和主成分数据
f=open('font_pca_modes.pkl','wb')
pickle.dump(immean,f)
pickle.dump(V,f)
f.close()

#载入均值和主成分数据
f=open('font_pca_modes.pkl','rb')
immean=pickle.load(f)
V=pickle.load(f)
f.close()

savetxt('test.txt',x,'%i')    #保存一个数组x到文件里

x=loadtxt('test.txt')   #读取数组x
# 打开文件并保存
with open('font_pca_modes.pkl', 'wb') as f:
pickle.dump(immean,f)
pickle.dump(V,f)

# 打开文件并载入
with open('font_pca_modes.pkl', 'rb') as f:
immean = pickle.load(f)
V = pickle.load(f)

1.4 SciPy

1.4.1 图像模糊

一,基本的图像操作和处理_第13张图片

from PIL import Image
from numpy import *
from scipy.ndimage import filters

im=array(Image.open('').convert('L'))
im2=filters.gaussian_filter(im,5)   #"5"参数位标准差

随着标准差的增加,图像被模糊的程度越大,细节丢失越多。
一,基本的图像操作和处理_第14张图片
如果模糊一幅彩色图像,只需要简单地对每个颜色通道进行高斯模糊。

im=array(Image.open())
im2=zeros(im.shape)
for i in rang(3):
im2[:,:,i]=filters.gaussian_filter(im[:,:i],5)

1.4.2 图像导数

强度的变化可以用灰度图像I(对于彩色图像,通常对每个颜色通道分别计算导数)的x 和 y方向导数Ix和Iy进行描述。
图像的梯度向量为:
在这里插入图片描述
梯度有两个重要的属性,一是梯度的大小:
在这里插入图片描述
它描述了图像强度变化的强弱,一是梯度的角度:
在这里插入图片描述
描述了图像中在每个点(像素)上强度变化最大的方向。NumPy 中的 arctan2() 函数 返回弧度表示的有符号角度,角度的变化区间为 -π…π。
我们可以用离散近似的方式来计算图像的导数。图像导数大多数可以通过卷积简单地实现:
在这里插入图片描述
对于 Dx 和 Dy,可以选择 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)

1.4.3 形态学:对象计数

形态学(或数学形态学)是度量和分析基本形状的图像处理方法的基本框架与集合。 形态学通常用于处理二值图像,但是也能够用于灰度图像。二值图像是指图像的每 个像素只能取两个值,通常是 0 和 1。二值图像通常是,在计算物体的数目,或者度量其大小时,对一幅图像进行阈值化后的结果。

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

一,基本的图像操作和处理_第15张图片
在这里插入图片描述

1.5高级示例:图像去噪

图像去噪是在去除图像噪声的同时,尽可能地保留图像细节和结构的处理技术。这里使用ROF (Rudin-Osher-Fatemi)去噪模型。ROF 模型具有很好的性质:使处理后的图像更平滑,同时保持图像边缘和结构信息。
ROF模型:
一幅灰度图像I的全变差(TV)定义为梯度范数之和。在连续表示的情况下,全变差表示为:
在这里插入图片描述
在离散表示的情况下,全变差表示为:
在这里插入图片描述
其中,上面的式子是在所有图像坐标x=[x,y]上取和。在Chambolle提出的ROF模型里,目标函数为寻找降噪后的图像U,使下式最小:
在这里插入图片描述
其中范数|| I-U ||是去噪后图像U和原始图像I差异的度量。本质上该模型使去噪后的图像像素值“平坦”变化,但在图像区域的边缘上,允许去噪后的图像像素值“跳跃”变化。

from numpy import *

def denoise(im,U_init,tolerance=0.1,tau=0.125,tv_weight=100):
  """ 使用A. Chambolle(2005)在公式(11)中的计算步骤实现Rudin-Osher-Fatemi(ROF)去噪模型

    输入:含有噪声的输入图像(灰度图像)、U 的初始值、TV 正则项权值、步长、停业条件

    输出:去噪和去除纹理后的图像、纹理残留"""

m,n = im.shape # 噪声图像的大小

# 初始化
U = U_init
Px = im # 对偶域的x 分量
Py = im # 对偶域的y 分量
error = 1

while (error > tolerance):
  Uold = U

  # 原始变量的梯度
  GradUx = roll(U,-1,axis=1)-U # 变量U 梯度的x 分量
  GradUy = roll(U,-1,axis=0)-U # 变量U 梯度的y 分量

  # 更新对偶变量
  PxNew = Px + (tau/tv_weight)*GradUx
  PyNew = Py + (tau/tv_weight)*GradUy
  NormNew = maximum(1,sqrt(PxNew**2+PyNew**2))

  Px = PxNew/NormNew # 更新x 分量(对偶)
  Py = PyNew/NormNew # 更新y 分量(对偶)

  # 更新原始变量
  RxPx = roll(Px,1,axis=1) # 对x 分量进行向右x 轴平移
  RyPy = roll(Py,1,axis=0) # 对y 分量进行向右y 轴平移

  DivP = (Px-RxPx)+(Py-RyPy) # 对偶域的散度
  U = im + tv_weight*DivP # 更新原始变量

  # 更新误差
  error = linalg.norm(U-Uold)/sqrt(n*m);

return U,im-U # 去噪后的图像和纹理残余


from numpy import *
from numpy import random
from scipy.ndimage import filters
import rof

# 使用噪声创建合成图像
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)

# 保存生成结果
from scipy.misc import imsave
imsave('synth_rof.pdf',U)
imsave('synth_gaussian.pdf',G)

show()

噪声图像
一,基本的图像操作和处理_第16张图片
高斯模糊
一,基本的图像操作和处理_第17张图片
ROF去噪
一,基本的图像操作和处理_第18张图片

你可能感兴趣的:(一,基本的图像操作和处理)