计算机视觉-基本的图像操作和处理

文章目录

  • 一、 Matplotlib
    • 1.绘制图像,点和线
    • 2.图像轮廓和直方图
    • 3.交互式标注
  • 二、NumPy
    • 1.图像数组表示
    • 2.灰度变换
    • 3.图像缩放
    • 4.直方图均衡化
    • 5.图像平均
    • 6.图像的主成分分析
  • 三、Scipy
    • 1.高斯图像模糊
    • 2.图像导数
  • 四、图像去噪

一、 Matplotlib

Matplotlib可以处理数学运算,绘制图表,或者在图像上绘制点,直线和曲线时, Matplotlib是比PIL更强大的绘图工具,可以绘制出高质量的图表。

1.绘制图像,点和线

点和线可以表示一些事物,比如对应点,兴趣点以及检测的物体

from PIL import Image
from pylab import *
#1.2.1绘制图像点和线
# 读取图像到数组中
im =array(Image.open('D:\PyCharmProjects\one\image\JMU.jpg'))
#绘制图像
imshow(im)
#一些点
x=[100,100,400,400]
y=[200,500,200,500]
#使用红色星状标记绘制点
plot(x,y,'r*')
#绘制连接前两个点的线
plot(x[:2],y[:2])
#添加标题,显示绘制的图像
title('Plotting:"JMU.jpg"')
# # 坐标不显示
# axis('off')
show()

运行结果
计算机视觉-基本的图像操作和处理_第1张图片
绘图时,可以控制图像的颜色和样式,一些短命令如下面三个表
表1:用PyLab库绘图的基本颜色格式命令
计算机视觉-基本的图像操作和处理_第2张图片
表2:用PyLab库绘图的基本线型格式命令
计算机视觉-基本的图像操作和处理_第3张图片

表3:用PyLab库绘图的基本绘制标记格式命令
计算机视觉-基本的图像操作和处理_第4张图片

2.图像轮廓和直方图

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

from PIL import Image
from pylab import *
##1.2.2图形轮廓和直方图
# 读取图像到数组中,并转成灰度图像
im =array(Image.open('D:\PyCharmProjects\one\image\JMU.jpg').convert('L'))
#新建一个图像
figure()
#不使用颜色信息
gray()
#在原点的左上角显示轮廓图像
contour(im,origin='image')
axis('equal')
axis('off')
figure()
hist(im.flatten(),128)
show()

结果如下
计算机视觉-基本的图像操作和处理_第5张图片
这里用PIL的convert()方法将图像转换成灰度图像。
图像的直方图用来表征该图像像素值的分布情况。用一定数目的小区间(bin)来指定表征像素值的范围,每个小区间会得到落入该小区间表示范围的像素数目。该(灰度)图像的直方图可以使用 hist() 函数绘制:

figure()
hist(im.flatten(),128)
show()

hist() 函数的第二个参数指定小区间的数目。需要注意的是,因为 hist() 只接受一维数组作为输入,所以我们在绘制图像直方图之前,必须先对图像进行压平处理。flatten() 方法将任意数组按照行优先准则转换成一维数组。图为等轮廓线和直方图图像。

3.交互式标注

用户和某些应用交互,如一副图像中标记一些点,或者标注一些训练数据等。

from PIL import Image
from pylab import *
##1.2.3交互式标注
im=array(Image.open('D:\PyCharmProjects\one\image\JMU.jpg'))
imshow(im)
print('Please click 3 points')
x=ginput(3)
print('you clicked:',x)
show()

结果如下
计算机视觉-基本的图像操作和处理_第6张图片
在图中点击三个点,就出现如下的三个坐标
在这里插入图片描述

二、NumPy

NumPy是Python科学计算工具包,如数组对象(用来表示向量,矩阵,图像等)以及线性代数函数。
以及数组对象(如矩阵乘积,转置,解方程系统,向量乘积和归一化),这为图像变形,对变化进行建模,图像分类,图像聚类等提供了基础。

1.图像数组表示

当载入图像时,我们通过调用array()方法将图像转换成NumPy的数组对象(多维的,可以用来表示向量,矩阵和图像)。一个数组对象很像一个列表(或者列表的列表),但是数组中所有元素必须具有相同的数据类型。

from PIL import Image
from pylab import *
#1.3.1图像数组表示
im=array(Image.open('D:\PyCharmProjects\one\image\JMU.jpg'))
print(im.shape,im.dtype)
im=array(Image.open('D:\PyCharmProjects\one\image\JMU.jpg').convert('L'),'f')
print(im.shape,im.dtype)

结果如下
计算机视觉-基本的图像操作和处理_第7张图片
图像载入并将其转换成数组中,数组类型是uint8。
对图像进行灰度处理,在创建数组时使用额外的参数"f",可以将数据类型转换成浮点型

2.灰度变换

考虑任意f,将0…255区间(或者0…1区间)映射到自身(输出区间的范围和输入区间的范围相同)

from PIL import Image
from pylab import *
#1.3.2灰度变换
im=array(Image.open('D:\PyCharmProjects\one\image\JMU.jpg').convert('L'))
im2=255-im  #对图像进行反向处理
im3=(100.0/255)*im+100 # 将图像像素值变换到100-200区间
im4=255.0*(im/255.0)**2 # 对图像像素值求平方后得到的图像
print (int(im.min()),int(im.max()))

结果如下
在这里插入图片描述

3.图像缩放

from PIL import Image
from pylab import *
# 1.3.3图像缩放
def imressize(im,sz):
    pil_im=Image.fromarray(uint8(im))
    return array(pil_im.resize(sz))

4.直方图均衡化

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

from PIL import Image
import matplotlib.pyplot as plt
import numpy as np

def histogram_equalization(img: np, nbr_bins=256):
    imhist, bins = np.histogram(img.flatten())
    cdf = imhist.cumsum() # 累计分布函数
    # 归一化
    cdf = 255 * cdf / cdf[-1]
    # 使用累积分布函数进行线性插值,计算新的像素值
    img2 = np.interp(img.flatten(), bins[:-1], cdf)
    return img2.reshape(img.shape), cdf


img = Image.open(r"D:\PyCharmProjects\one\image\JMU.jpg").convert('L')
img2, cdf = histogram_equalization(np.array(img))
plt.figure()
plt.gray()
# 绘制子图
plt.subplot(232)
# 变换函数
plt.plot(cdf)
plt.subplot(231)
plt.hist(np.array(img).flatten(), 256)
# 关闭坐标轴,对上一个子图有效
plt.axis('off')
plt.subplot(233)
plt.hist(np.array(img2).flatten(), 256)
plt.axis('off')
plt.subplot(234)
plt.imshow(img)
plt.axis('off')
plt.subplot(236)
plt.imshow(img2)
plt.axis('off')
# 保存绘制图像
plt.savefig("D:\PyCharmProjects\one\image\JMUU.jpg")
plt.show()

结果如下
计算机视觉-基本的图像操作和处理_第8张图片
左侧为原始图像和直方图,中间为灰度变换函数,右侧为直方图均衡化后的图像和相应直方图

5.图像平均

图像平均操作是减少图像噪声的一种简单操作

from PIL import Image
from pylab import *

# 1.3.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)
            # 返回unit8类型的平均像素
            return array(averageim,'uint8')

6.图像的主成分分析

图像的主成分分析(PCA)是一个非常有用的降维技巧。它可以在使用尽可能少维数的前提下,尽量
多地保持训练数据的信息,在此意义上是一个最佳技巧。即使是一幅100×100像素的小灰度图像,也有10000维,
可以看10000维空间中的一个点。一兆像素的图像具有百万维。由于图像具有很高的维数,在许多计算机视觉应用中,我们经常使用降维操作。PCA产生的投影矩阵可以被视为将原始坐标变换到现有的坐标系,坐标系中的各个坐标按照重要性递减排列。

为了对图像数据进行PCA 变换,图像需要转换成一维向量表示。我们可以使用NumPy 类库中的 flatten()方法进行变换。

将变平的图像堆积起来,我们可以得到一个矩阵,矩阵的一行表示一副图像。在计算主方向之前
前,所有的行图像按照平均图像进行了中心化。我们通常使用SVD方法来计算主成分。但当矩阵的
维数很大时,SVD 的计算非常慢,所以此时通常不使用 SVD分解。
下面是PCA操作代码

from PIL import Image
from pylab import *
def pca(X):
    """主成分分析:
        输入:矩阵X,其中该矩阵中存储训练数据,每一行为一条训数据
        返回:投影矩阵(按照维度的重要性排序),方差和均值
    """
    #获取维数
    num_data,dim=X.shape
    # 数据中心化
    mean_X=X.mean(axios=0)
    X=X-mean_X
    # PCA使用紧致技巧
    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
     # PCA-使用SVD方法
     else:
         U,S,V=linalg.svd(X)
         V=V[:num_data]# 仅仅返回前num_data维的数据才合理
    # 返回投影矩阵,方差和均值
    return V,S,mean_X

该函数首先通过减去每一维的均值将数据中心化,然后计算协方差矩阵对应最大特征值的特征向量,此时可以使用简明的技巧或者 SVD 分解。这里我们使用了 range() 函数,该函数的输入参数为一个整数 n,函数返回整数 0…(n-1) 的一个列表。你也可以使用 arange() 函数来返回一个数组,或者使用 xrange() 函数返回一个产生器(可能会提升速度)。我们在本书中贯穿使用 range() 函数。

如果数据个数小于向量的维数,我们不用 SVD 分解,而是计算维数更小的协方差矩阵 XXT 的特征向量。通过仅计算对应前 k(k 是降维后的维数)最大特征值的特征向量,可以使上面的 PCA 操作更快。由于篇幅所限,有兴趣的读者可以自行探索。矩阵 V 的每行向量都是正交的,并且包含了训练数据方差依次减少的坐标方向。
接下来对字体图像进行PCA变换

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() 函数

三、Scipy

1.高斯图像模糊

图像的高斯模糊是非常经典的图像卷积例子。本质上,图像模糊就是将(灰度)图像I 和一个高斯核进行卷积操作:
在这里插入图片描述
其中, ∗ 表示卷积操作;G 表示标准差为 σ 的二维高斯核,定义为:
在这里插入图片描述
高斯模糊通常是其他图像处理操作的一部分,比如图像插值操作,兴趣点计算以及很多其他应用。

from PIL import Image
from numpy import *
from scipy.ndimage import filters
import matplotlib.pyplot as plt #使用 matplotlib 来显示图片,可以让图片显示到jupyter的页面
im = array(Image.open('D:\PyCharmProjects\one\image\JMU.jpg').convert('L'))
im2 = filters.gaussian_filter(im,2)
im3 = filters.gaussian_filter(im,5)
fig = plt.figure()
ax1 = fig.add_subplot(131)
ax1.imshow(im)
ax2 = fig.add_subplot(132)
ax2.imshow(im2)
ax3 = fig.add_subplot(133)
ax3.imshow(im3)
plt.show()

结果如下
计算机视觉-基本的图像操作和处理_第9张图片
左边是原始图像,中间的是σ=2的高斯滤波器,右边为σ=5的高斯滤波器

2.图像导数

计算机视觉-基本的图像操作和处理_第10张图片
对于 Dx 和 Dy,可以选择 Sobel 滤波器:
在这里插入图片描述
在这里插入图片描述
或者Prewitt 滤波器:
在这里插入图片描述
在这里插入图片描述

# 1.4.2图像导数
from PIL import Image
from pylab import *
from scipy.ndimage import filters
import numpy

im = array(Image.open('D:\PyCharmProjects\one\image\JMU.jpg').convert('L'))
gray()

subplot(1, 4, 1)
axis('off')
title('(a)')
imshow(im)

# Sobel 导数滤波器
imx = zeros(im.shape)
filters.sobel(im, 1, imx)
subplot(1, 4, 2)
axis('off')
title('(b)')
imshow(imx)

imy = zeros(im.shape)
filters.sobel(im, 0, imy)
subplot(1, 4, 3)
axis('off')
title('(c)')
imshow(imy)

mag = 255-numpy.sqrt(imx**2 + imy**2)
subplot(1, 4, 4)
title('(d)')
axis('off')
imshow(mag)

show()

结果如下
计算机视觉-基本的图像操作和处理_第11张图片
使用Sobel导数滤波器计算导数图像:(a)原始灰度图像;(b)x导数图像;(c)y导数图像;(d)梯度大小图像

四、图像去噪

图像去噪是在去除图像噪声的同时,尽可能地保留图像细节和结构地处理技术,以下给出使用ROF去噪模型,
ROF去噪模型的性质:使处理后的图像更平滑,同时保持图像边缘和结构信息。
一幅灰度图像I的全变差(TV)定义为梯度范数之和。在连续表示的情况下,全变差表示为:
在这里插入图片描述
在离散表示的情况下,全变差表示为:
在这里插入图片描述
其中,上面的式子是在所有图像坐标x=[x,y]上取和。在Chambolle提出的ROF模型里,目标函数为寻找降噪后的图像U,使下式最小
在这里插入图片描述

其中范数|| I-U ||是去噪后图像U和原始图像I差异的度量。本质上该模型使去噪后的图像像素值“平坦”变化,但在图像区域的边缘上,允许去噪后的图像像素值“跳跃”变化。

from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
from scipy.ndimage import filters


def de_noise(img, U_init, tolerance=0.1, tau=0.125, tv_weight=100):
    """使用A.Chambolle(2005)在公式(11)中的计算步骤实现Rudin-Osher-Fatemi(ROF)去噪模型
        输入:含有噪声的输入图像(灰度图像),U的初始值,TV正则项权值,步长,停业条件
        输出:去噪和去除纹理后的图像,纹理残留
        """
    U = U_init
    # 对偶域的X,Y分量
    Px = Py = img
    error = 1
    while error > tolerance:
        Uold = U
        # 原始变量梯度
        gradUx = np.roll(U, -1, axis=1)-U   # 变量U梯度的x分量
        gradUy = np.roll(U, -1, axis=0)-U   # 变量U梯度的y分量

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

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

        # 更新原始变量
        RxPx = np.roll(Px, 1, axis=1)  # 将x分量向x轴正方向平移
        RyPy = np.roll(Py, 1, axis=0)  # 将y分量向y轴正方向平移

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

        # 更新误差
        error = np.linalg.norm(U - Uold)/np.sqrt(img.shape[0] * img.shape[1])

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


if __name__ == '__main__':
    im = np.zeros((500, 500))
    im[100:400,100:400] = 128
    im[200:300, 200:300] = 255
    im = im + 30 * np.random.standard_normal((500, 500))

    U, T = de_noise(im, im)
    G = filters.gaussian_filter(im, 10)
    plt.figure()
    plt.gray()
    plt.subplot(221).set_title("Original image")
    plt.axis('off')
    plt.imshow(im)
    plt.subplot(222).set_title("Gauss blurred image")
    plt.axis('off')
    plt.imshow(G)
    plt.subplot(223).set_title("ROF")
    plt.axis('off')
    plt.imshow(U)
    plt.savefig('tmp.jpg')
    plt.show()

结果如下
计算机视觉-基本的图像操作和处理_第12张图片

你可能感兴趣的:(计算机视觉,python,图像处理)