文章目录
- 1、PIL与Matplotlib
- 1.1 图像的显示
- 1.2 基本图像操作
- 1.3 绘制点、线
- 2、numpy
- 2.1 对图像像素值进行处理
- 2.2 直方图均衡
- 2.3 图像平均
- 2.4 PCA
- 3、Scipy
- 3.1 图像模糊
- 3.2 图像导数
- 3.3 形态学:对象计数
- 4、图像去噪
1、PIL与Matplotlib
1.1 图像的显示
一般,图像的显示方法有两种,一种img.show()的方式将图像显示出来,这种方法只能利用电脑上的图片等进行观察,另一种方法是使用 plt.imshow() 方法进行画图,它在显示可以将灰度图像按照灰度值的高低映射成彩色图像。
#法一
from PIL import Image
img=Image.open('d:/imdata/coins.png')
img.show()
#法二
from PIL import Image
import matplotlib.pyplot as plt
img=Image.open('d:/coins.png')
plt.figure("coins")
plt.imshow(img)
plt.show()
如上图,经过matplotlib工具提供的函数进行图像显示时,灰度图会被映射为彩色图像。要想显示出灰度图像,只需将plt.imshow(img)改为plt.imshow(img,cmap=‘gray’)即可。
1.2 基本图像操作
借助python工具,我们可以对图像进行一些简单的处理,如旋转、调整图像尺寸、反向处理、灰度变换、复制粘贴等等。
from PIL import Image
import matplotlib.pyplot as plt
from numpy import *
img =Image.open('d:/imdata/onion.png')
plt.figure()# 子图
plt.subplot(231)# 原图
plt.imshow(img)
plt.subplot(232)# 将图像缩放至 256 * 256
plt.imshow(img.resize((256, 256)))
plt.subplot(233)# 将图像转为灰度图
plt.imshow(img.convert('L'),cmap='gray')
plt.subplot(234)# 旋转图像
plt.imshow(img.rotate(45))
img2 =255-array(Image.open('d:/imdata/onion.png'))
plt.subplot(235)
plt.imshow(img2)
#复制图像某一区域
box=(50,50,100,100)
region=img.crop(box)
#旋转后粘贴到原区域
region=region.transpose(Image.ROTATE_180)
img.paste(region,box)
plt.subplot(236)
plt.imshow(img)
plt.show()
1.3 绘制点、线
可以用plot()函数进行点、线的绘制。如:
from PIL import Image
import matplotlib.pyplot as plt
from numpy import *
#读取图像到数组中并绘制图像
im=array(Image.open('d:\imdata\onion.png'))
plt.imshow(im)
#选取一些点用红色星来标记
x=[50,50,100,100]
y=[50,100,50,100]
plt.plot(x, y, 'r*')
#绘制连接前两个点的线,默认蓝色
plt.plot(x[:2],y[:2])
plt.show()
2、numpy
numpy工具可以将图像转为数组对象,方便我们进行后续操作,是非常有用的一个工具包。
2.1 对图像像素值进行处理
from PIL import Image
import matplotlib.pyplot as plt
from numpy import *
im=array(Image.open('d:\imdata\onion.png').convert('L'))
plt.subplot(131)
plt.imshow(im,cmap='gray')
#将图像像素值变换到200~250之间
im2=(50/255)*im+200
plt.subplot(132)
plt.imshow(im2,cmap='gray')
#对图像像素值求平方后得到的图像
im3=255*(im/255)**2
plt.subplot(133)
plt.imshow(im3,cmap='gray')
#array()变换的反操作,用fromarray()函数完成
pil_im=Image.fromarray(im)
plt.show()
2.2 直方图均衡
from PIL import Image
import matplotlib.pyplot as plt
from numpy 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
im = array(Image.open('d:/imdata/onion.png').convert('L'))
im2,cdf=histeq(im)
#显示中文
plt.rcParams['font.sans-serif']=['SimHei']
plt.figure()
plt.subplot(2, 2, 1)
plt.axis('off')
plt.gray()
plt.title("原始图像")
plt.imshow(im)
plt.subplot(2, 2, 2)
plt.axis('off')
plt.title("直方图均衡化后的图像")
plt.imshow(im2)
plt.subplot(2, 2, 3)
plt.axis('off')
plt.title("原始直方图")
plt.hist(im.flatten(), 128, density=True)
plt.subplot(2, 2, 4)
plt.axis('off')
plt.title("均衡化后的直方图")
plt.hist(im2.flatten(), 128, density=True)
plt.show()
2.3 图像平均
图像平均操作是减少图像噪声的一个简单方式,对于一些具有相同大小的图像,我们可以将其相加,然后除以图像的数目,就可以得到平均图像。
def compute_average(imlist):
averageim=array(Image.open(imlist[0]),’f’)
for inname in imlist[1:]:
try:
averageim+=array(Image.open(imname))
except:
print imname + ‘....skipped’
averageim/=len(imlist)
return array(averageim,’uint8’)
2.4 PCA
PCA是一个非常有用的降维技巧,它可以在使用尽可能少维数的前提下尽量多的保持训练数据的信息。
def pca(X):
#获取维数
num_data,dim=X.shape
#数据中心化
mean_X=X.mean(axis=0)
X=X-mean_X
if dim>num_data:
#矩阵相乘
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:
U,S,V=linalg.svd(X)
V=V[:num_data]
return V,S,mean_X
3、Scipy
scipy提供了很多高效的操作,可以实现数值积分、优化、统计、信号处理等,对我们来说是一个非常重要的工具包。
3.1 图像模糊
高斯模糊是非常经典的图像卷积例子,在其他图像处理操作中也经常出现,下面给大家展示一下。
from PIL import Image
from matplotlib import pyplot as plt
from numpy import *
from scipy.ndimage import filters
#灰度图像
img=array(Image.open('d:/imdata/onion.png').convert('L'))
#后一个参数表示标准差
img2=filters.gaussian_filter(img,5)
#彩色图像
im=array(Image.open('d:/imdata/onion.png'))
im2=zeros(im.shape)
for i in range(3):
im2[:,:,i]=filters.gaussian_filter(im[:,:,i],5)
im2=uint8(im2)
#显示中文
plt.rcParams['font.sans-serif']=['SimHei']
plt.figure()
plt.subplot(2, 2, 1)
plt.title("原始图像")
plt.imshow(img,cmap='gray')
plt.subplot(2, 2, 2)
plt.title("模糊后的图像")
plt.imshow(img2,cmap='gray')
plt.subplot(2, 2, 3)
plt.title("原始图像")
plt.imshow(im)
plt.subplot(2, 2, 4)
plt.title("模糊后的图像")
plt.imshow(im2)
plt.show()
3.2 图像导数
Scipy模块提供了prewitt、sobel等滤波器,可以比较容易的求出图像的导数。这些算子我们在学习数字图像处理时已经了解过了,在这里就不再一一阐述。
from PIL import Image
from matplotlib import pyplot as plt
from numpy import *
from scipy.ndimage import filters
im=array(Image.open('d:/imdata/onion.png').convert('L'))
#sobel
imx=zeros(im.shape)
#第二个参数表示选择x或y方向导数
filters.sobel(im,1,imx)
imy=zeros(im.shape)
filters.sobel(im,0,imy)
magniyude=sqrt(imx**2+imy**2)
plt.rcParams['font.sans-serif']=['SimHei']
plt.figure()
plt.subplot(2, 2, 1)
plt.title("原始图像")
plt.imshow(im,cmap='gray')
plt.subplot(2, 2, 2)
plt.title("x导数图像")
plt.imshow(imx,cmap='gray')
plt.subplot(2, 2, 3)
plt.title("y导数图像")
plt.imshow(imy,cmap='gray')
plt.subplot(2, 2, 4)
plt.title("梯度图像")
plt.imshow(magniyude,cmap='gray')
plt.show()
3.3 形态学:对象计数
形态学通常用于处理二值图像。scipy.ndmage的morphology模块可以实现形态学操作、measurements模块可以实现二值图像的计数和度量功能。
im=array(Image.open('d:/imdata/onion.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
4、图像去噪
图像去噪是在去除图像噪声的同时,尽可能地保留图像细节和结构的处理技术。图像去噪对于很多应用来说都非常重要。我们这里使用 ROF(Rudin-Osher-Fatemi)去噪模型,ROF 模型具有很好的性质:使处理后的图像更平滑,可同时保持图像边缘和结构信息。
from matplotlib import pyplot as plt
from numpy import *
from numpy import random
from scipy.ndimage import filters
def denoise(im,U_init,tolerance=0.1,tau=0.125,tv_weight=100):
m,n=im.shape#噪声图像的大小
U=U_init
Px=im
Py=im
error=1
while(error>tolerance):
Uold=U
GradUx=roll(U,-1,axis=1)-U
GradUy = roll(U, -1, axis=0) - U
Pxnew=Px+(tau/tv_weight)*GradUx
Pynew = Py + (tau / tv_weight) * GradUy
NormNew=maximum(1,sqrt(Pxnew**2+Pynew**2))
Px=Pxnew/NormNew
Py = Pynew / NormNew
RxPx=roll(Px,1,axis=1)
RyPy=roll(Py,1,axis=0)
DivP=(Px-RxPx)+(Py-RyPy)
U=im+tv_weight*DivP
error=linalg.norm(U-Uold)/sqrt(n*m)
return U,im-U
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=denoise(im,im)
G=filters.gaussian_filter(im,10)
plt.rcParams['font.sans-serif']=['SimHei']
plt.figure()
plt.subplot(1, 3, 1)
plt.title("原始图像")
plt.imshow(im,cmap='gray')
plt.subplot(1, 3, 2)
plt.title("rof去噪图像")
plt.imshow(U,cmap='gray')
plt.subplot(1, 3, 3)
plt.title("高斯去噪图像")
plt.imshow(G,cmap='gray')
plt.show()
可以发现,经过rof去噪的图像的边缘依然很清晰,而经过高斯去噪的图像的边缘就很难分辨了。