基本的图像处理和操作——NumPy

NumPy

NumPy是非常有名的Python科学计算工具包,其中包含了大量有用的思想,比如数组对象(用来表示向量、矩阵、图像等)以及线性代数函数。

1.1图像数组表示

载入图像时,通过调用array()方法将图像转换成NumPy的数组对象。数组中所有的元素必须具有相同的数据类型。

from PIL import Image
from pylab import *
im = array(Image.open('FatherAndSon.jpg'))
print(im.shape,im.dtype)

#提取指定位置的value
value = im[1,1,2]
print(value)

#创建数组时使用额外的参数“f”;该参数将数据类型转换为浮点型
im = array(Image.open('FatherAndSon.jpg').convert('L'),'f')
print(im.shape,im.dtype)

切片式访问数组指定位置的元素:

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])#倒数第二行

 

1.2图像灰度变换

注意img如果是uint16的矩阵而不转为uint8的话,Image.fromarray这句会报错。如下:
raise TypeError("Cannot handle this data type")
TypeError: Cannot handle this data type

参考链接:https://www.jianshu.com/p/18dabefa6778

将数组转化为图片,参考链接:https://blog.csdn.net/zgcr654321/article/details/88015327

from PIL import Image
from pylab import *
import numpy as np

im = array(Image.open('FatherAndSon.jpg'))
print(im.dtype)
m,n,s = im.shape
#对图像进行反相处理
im1 = 255*np.ones((m,n,s))
im1 = im1 - im
print(im1.dtype)

im11 = 100*np.ones((m,n,s))
im2 = (100.0/255) * im + im11
im3 = 255*(im/255)**2         # 对图像像素值求平方后得到的图像

#由于图像的数据类型为uint8类型,而数组im、im1、im2、im3为float64,所以需要转换为uint8类型
#将数组转化为图片
img = Image.fromarray(np.uint8(im)).convert('RGB')
img1 = Image.fromarray(np.uint8(im1)).convert('RGB')
img11 = Image.fromarray(np.uint8(im2)).convert('RGB')
img111 = Image.fromarray(np.uint8(im3)).convert('RGB')

#保存处理后的图像
img.save("原图.jpg","JPEG")
img1.save("反相.jpg","JPEG")
img11.save("100…200.jpg","JPEG")
img111.save("平方.jpg","JPEG")

FatherAndSon.jpg
反相.jpg

 

 

 

 

 

 

 

100…200.jpg
平方.jpg

 

 

 

 

 

 

 array() 变换的相反操作可以使用 PIL 的 fromarray() 函数完成:
pil_im = Image.fromarray(im)
通过一些操作将“uint8”数据类型转换为其他数据类型,比如代码示例中的im,那么在创建 PIL 图像之前,需要将数据类型转换回来:
pil_im = Image.fromarray(uint8(im))
如果你并不十分确定输入数据的类型,安全起见,应该先转换回来。注意, NumPy总是将数组数据类型转换成能够表示数据的“最低”数据类型。对浮点数做乘积或除法操作会使整数类型的数组变成浮点类型。

 1.3图像缩放

图像缩放函数

def imreszie(im,sz):
    """使用PIL对象重新定义图像数组的大小"""
    pil_im = Image.fromarray(uint8(im))
    return array(pil_im.resize(sz))

1.4图像直方图均衡化

 直方图均衡化函数

#直方图均衡化函数
#该函数有两个输入参数,一个是灰度图像,一个是直方图中使用小区间的数目
#该函数返回直方图均衡化后的图像,以及用来做像素值映射的累积分布函数
#函数中使用到累积分布函数的最后一个元素(下标为-1),目的是将其归一化到0……1范围内
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(),bins[:-1],cdf)
    return im.reshape(im.shape),cdf
    

图像灰度变换中一个非常有用的例子就是直方图均衡化。直方图均衡化是指将一幅图像的灰度直方图变平,使变换后的图像中每个灰度值的分布概率都相同。在对图像做进一步处理之前,直方图均衡化通常是对图像灰度值进行归一化的一个非常好的方法,并且可以增强图像的对比度。
        在这种情况下,直方图均衡化的变换函数是图像中像素值的累积分布函数(cumulative distribution function,简写为 cdf,将像素值的范围映射到目标范围的归一化操作)。

 1.5图像平均

      图像平均操作是减少图像噪声的一种简单方式,通常用于艺术特效。

#图像平均函数
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')

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

       PCA(Principal Component Analysis,主成分分析)是一个非常有用的降维技巧。它可以在使用尽可能少维数的前提下,尽量多地保持训练数据的信息,在此意义上是一个最佳技巧。即使是一幅 100×100 像素的小灰度图像,也有 10 000 维,可以看成 10 000 维空间中的一个点。一兆像素的图像具有百万维。由于图像具有很高的维数,在许多计算机视觉应用中,我们经常使用降维操作。PCA 产生的投影矩阵可以被视为将原始坐标变换到现有的坐标系,坐标系中的各个坐标按照重要性递减排列。为了对图像数据进行 PCA 变换,图像需要转换成一维向量表示。我们可以使用NumPy 类库中的 flatten() 方法进行变换。
        将变平的图像堆积起来,我们可以得到一个矩阵,矩阵的一行表示一幅图像。在计算主方向之前,所有的行图像按照平均图像进行了中心化。我们通常使用 SVD(SingularValue Decomposition,奇异值分解)方法来计算主成分;但当矩阵的维数很大时,SVD 的计算非常慢,所以此时通常不使用 SVD 分解。

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

该函数首先通过减去每一维的均值将数据中心化,然后计算协方差矩阵对应最大特征值的特征向量,此时可以使用简明的技巧或者 SVD 分解。这里我们使用了range() 函数,该函数的输入参数为一个整数 n,函数返回整数 0...(n-1) 的一个列表。你也可以使用 arange() 函数来返回一个数组,或者使用 xrange() 函数返回一个产生器(可能会提升速度)。我们在本书中贯穿使用 range() 函数。
如果数据个数小于向量的维数,我们不用 SVD 分解,而是计算维数更小的协方差矩阵 XX T 的特征向量。通过仅计算对应前 k(k 是降维后的维数)最大特征值的特征向量,可以使上面的 PCA 操作更快。由于篇幅所限,有兴趣的读者可以自行探索。矩阵 V 的每行向量都是正交的,并且包含了训练数据方差依次减少的坐标方向。
 

1.7pickle模块

       如果想要保存一些结果或者数据以方便后续使用,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 模块完全兼容。关于 pickle 模块的更多内容,参见 pickle 模块文档页 http://docs.python.org/library/pickle.html。

 

       使用with语句处理文件的读写操作可以自动打开和关闭文件(即使在文件打开时发生错误)。

#打开文件并保存
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)

       上面的例子乍看起来可能很奇怪,但 with() 确实是个很有用的思想。如果你不喜欢它,可以使用之前的 open 和 close 函数。作为 pickle 的一种替代方式, NumPy 具有读写文本文件的简单函数。如果数据中不包含复杂的数据结构,比如在一幅图像上点击的点列表, NumPy 的读写函数会很有用。保存一个数组 x 到文件中,可以使用:
                savetxt('test.txt',x,'%i')
      最后一个参数表示应该使用整数格式。类似地,读取可以使用:
                 x = loadtxt('test.txt')
       还可以从在线文档 http://docs.scipy.org/doc/numpy/reference/generated/numpy.loadtxt.html 了解更多内容。最后, NumPy 有专门用于保存和载入数组的函数。你可以在上面的在线文档里查看关于 save() 和 load() 的更多内容。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值