NumPy
Numpy是一个基础的Python科学计算工具包,它包含了:
- 强大的N维数组对象
- 复杂的函数
- 用于融合C/C++和Fortran的工具
- 实用的线性代数、傅里叶变换、随机数功能
使用array()方法将图像转换成NumPy的数组对象,第一个参数是数组式的对象,第二个可选参数data-type默认为可以存储该对象的最小数据类型,使用‘f’时可将数据类型转换为浮点型
from PIL import Image
from pylab import *
im = array(Image.open('C:/Users/0AQZ0/Documents/exercisecode/Python/PyCV/Images/002.jpg'))
print(im.shape, im.dtype)
im = array(Image.open('C:/Users/0AQZ0/Documents/exercisecode/Python/PyCV/Images/002.jpg').convert('L'),'f')
print(im.shape, im.dtype)
输出结果:
(874, 650, 3) uint8
(874, 650) float32
第一个元组表示图像数组的大小(行、列、颜色通道),由于灰度图像没有颜色信息,所以没有颜色通道。第二个字符串表示数据类型
为什么导入pylab模块?因为Pylab中包含NumPy的一些内容
数组中的元素可以使用下标访问,多个数组元素可以使用数组切片方式访问
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列
im[:,-1] #最后一列
im[-2,:] #倒数第二行
将图像转换为NumPy数组对象后,可以进行任意的数学操作,例如图像的灰度变换。图像的灰度变换就是使用任意函数f,使得(0,255)区间映射到它自身
from PIL import Image
from numpy import *
im = array(Image.open('C:/Users/0AQZ0/Documents/exercisecode/Python/PyCV/Images/002.jpg').convert('L'))
im2 = 255 - im #反相处理
im3 = (100.0/255) * im +100 #变换到(100,200)区间
im4 = 255.0 * (im/255.0)**2 #二次函数变换,使暗的像素值更小
array()方法的相反操作是PIL的fromarry()方法,将数组逆映射为PIL图像
pil_im = Image.fromarray(im)
对浮点数做乘积或者除法操作时,会将整数型数组变为浮点型,所以逆映射前要转换数据类型
pil_im = Image.fromarray(unit8(im))
定义图像缩放函数,并添加到imtool.py文件中
def imresize(im,sz):
"""使用PIL对象重新定义图像数组的大小"""
pil_im = Image.fromarray(unit8(im))
return array(pil_im.resize(sz))
直方图均衡化是指将一幅图像的灰度直方图变平,使每个灰度值的分布概率相同,可以增强图像对比度
定义histeq()函数来获得直方图均衡化后的图像,以及像素值的累积分布函数,第一个参数是灰度图像,第二个是直方图中使用的小区间数目
def histeq(im,nbr_bins=256):
"""对一幅灰度图像进行直方图均衡化"""
#计算图像的直方图
imhist,bins = histogram(im.flatten(),nbr_bins,normed=True)
cdf = imhist.cumsum() #cumulative distribution function
cdf = 255 * cdf /cdf[-1] #归一化
#使用累积分布函数的线性插值,计算新的像素值
im2 = interp(im.flatten(),nins[:-1],cdf)
return im2.reshape(im.shape),cdf
图像平均是减少图像噪声的一种方式,即从图像列表中计算出一副平均图像,具体地说可以通过简单的相加,然后除以图像的数目来实现
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)
#将浮点型转换为unit8型
return array(averageim, 'unit8')
使用mean()方法也可以计算平均图像,但是需要占用很多内存
主成分分析PCA(Principal Component Analysis)是降维的一种技巧,即在使用尽可能少维数的情况下,尽量多地保留训练数据的信息,PCA产生的投影矩阵可以将原始坐标变换到现有的坐标系,坐标系中的各个坐标按重要性递减排列
进行PCA变换时,先使用NumPy的flatten()方法将图像转换成一维向量,再堆积成一个矩阵,矩阵的一行表示一幅图像,然后所有的行图像进行中心化,计算协方差矩阵对应的最大特征值的特征向量,再使用简明的技巧(维数较高时)或者SVD分解(维数较低时)
奇异值分解SVD(Singular Value Decomposition)可以计算主成分,当矩阵的维数很大时计算非常慢
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:
#维数高时使用紧致技巧
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:
#维数较低使用SVD方法
U,S,V = linalg.svd(X)
V = V[:num_data] #仅返回前num_data维的数据
#返回投影矩阵、方差、均值
return V,S,mean_X
计算图像主成分的脚本:
from PIL import Image
from numpy import *
from pylab import *
import pca
im = array(Image.open(imlist[0]))
m,n = im.shape[0:2] #获取图像的大小
imnbr = len(imlist) #获取图像的数目
#创建矩阵,保存压平后的图像数据
immatrix = array([array(Image.open(im)).flatten() for im in imlist],'f')
#执行PCA操作
V,S,immean = pca.pca(immatrix)
#显示均值图像和前7个模式
figure()
gray()
subplot(2,4,1)
imshow(immean.reshape(m,n))
for i in range(7):
subplot(2,4,i+2)
imshow(V[i].reshape(m,n))
show()
reshape()方法可以将一维图像重新转换为二维图像
PyLab的subplot()方法可以在一个窗口中放置多个图像
NumPy中的savetxt()方法和loadtxt()方法可以读写文本文件,savetxt()方法中最后一个参数表示使用整数格式
savetxt('text.txt',x,'%i')
x = loadtxt('test.txt')