基本的图像操作和处理(实验一)

目录

一、读取并显示图片的三种方式(Pillow、matplotlib、opencv)

1.1 Pillow方式读取显示图片

1.2 matplotlib方式读取显示图片

1.3 opencv方式读取显示图片

 二、Pillow库(PIL)的用法介绍

2.1 安装Pillow

2.2 显示图片

 2.3 转换图片格式

2.3.1 save()方法

2.3.2 convert() 方法

2.4 创建缩略图

 2.5 复制和粘贴图像区域

2.5.1 crop()方法的使用

 2.5.2 paste()方法

2.6 调整尺寸和旋转

2.6.1 resize()方法

2.6.2 rotate()方法

三、Matplotlib库的用法介绍

3.1 绘制图像、点和线

3.1.1 imshow()绘制图像

3.1.2 plot(x,y,' ')绘制点

3.1.3 plot(x[:4],y[:4])绘制线

3.2 图像轮廓和直方图

3.2.1 contour()方法实现图像轮廓提取

 3.2.2 hist()函数绘制直方图

 3.3 交互式标注

四、NumPy库的用法介绍

4.1 图像数组表示

4.2 灰度变换

4.3 图像缩放

4.4 直方图均衡化

4.5 图像平均

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

 4.7 使用pickle模块

五、SciPy库的用法介绍

5.1 图像模糊

5.2 图像导数

5.3 形态学:对象计数

5.4 一些有用的SciPy模块

5.5 高级示例:图像去噪


一、读取并显示图片的三种方式(Pillow、matplotlib、opencv)

1.1 Pillow方式读取显示图片

实现代码:

from PIL import Image

pil_im = Image.open('E:\Junior_N\computerVision\imgTest\IMG20190831164243.jpg')
pil_im.show()

测试结果: 

1.2 matplotlib方式读取显示图片

实现代码:

import matplotlib.pyplot as plt

im = plt.imread('E:\Junior_N\computerVision\imgTest\IMG20190831164243.jpg')

plt.imshow(im)
plt.show()

测试结果:

1.3 opencv方式读取显示图片

实现代码:

import cv2

img = cv2.imread('E:\Junior_N\computerVision\imgTest\IMG20190831164243.jpg')
cv2.imshow('尚大楼', img)
cv2.waitKey(0)

测试结果:

从测试结果可以看出:图像只显示一小部分。

这是因为当图像尺寸大于屏幕可显示大小时,通过上述代码,显示的图片仅为原始图片的一部分。这是由于上述代码默认的窗口属性为cv2.WINDOW_AUTOSIZE(按照图片大小自动调整窗口大小),则当图片尺寸小于屏幕大小时,按图片尺寸设置窗口大小,显示一个完整的图片。当图片尺寸大于屏幕大小时,窗口依旧按照图片尺寸设置,则我们的屏幕不能显示整个窗口,从而产生图片显示不全的问题。这时,我们可以通过设置窗口属性,保证图片显示完整。

修改代码:

import cv2

im = cv2.imread('E:\Junior_N\computerVision\imgTest\IMG20190831164243.jpg')
cv2.namedWindow('img',cv2.WINDOW_NORMAL)
cv2.imshow('img',im)
cv2.waitKey(0)
cv2.destroyAllWindows()

测试结果:

 通过cv2.namedWindow(‘img’,cv2.WINDOW_NORMAL)设置窗口属性可以任意调整窗口大小,图片能够在屏幕上完整显示,但拖动窗口时会造成图像比例失真。

图片显示不全的主要原因是图片过大。顺着这个思路,我们可以通过主动调整图片大小,使其符合屏幕大小从而解决该问题。

修改代码:

import cv2

im = cv2.imread('E:\Junior_N\computerVision\imgTest\IMG20190831164243.jpg')
#cv2.namedWindow('img',cv2.WINDOW_NORMAL)
im = cv2.resize(im,(1920,1039))
cv2.imshow('img',im)
cv2.waitKey(0)
cv2.destroyAllWindows()

测试结果:

 二、Pillow库(PIL)的用法介绍

在Python2中,PIL(Python Imaging Library)是一个非常好用的图像处理库,但PIL不支持Python3,所以有人(Alex Clark和Contributors)提供了Pillow,可以在Python3中使用。

2.1 安装Pillow

pip install pillow

Pillow库安装成功后,导包时要用PIL来导入,而不能用pillow或Pillow。

import PIL
from PIL import Image

在Pillow库中,除了有二十多个模块,还支持非常多的插件。其中最常用的是Image模块中同名的Image类,其他很多模块都是在Image模块的基础上对图像做进一步的特殊处理,Image模块中会导入部分来使用。

2.2 显示图片

原图:(以下实验都使用此图)

代码实现:

from PIL import Image

image = Image.open('E:\Junior_N\computerVision\imgTest\IMG20190831164243.jpg')
image.show()

运行结果:

 2.3 转换图片格式

Pillow 库支持多种图片格式,可以直接使用 open() 方法来读取图片,并且无须考虑图片是何种类型。同时,Pillow 能够很轻松地实现图片格式之间的转换。下面是两种图片格式之间转换的方法。

2.3.1 save()方法

save() 方法用于保存图像,当不指定文件格式时,它会以默认的图片格式来存储;如果指定图片格式,则会以指定的格式存储图片。

save() 的语法格式如下:

Image.save(fp, format=None)

具体参数说明如下:
fp:图片的存储路径,包含图片的名称,字符串格式;
format:可选参数,可以指定图片的格式。 

实验代码:

from PIL import Image

image = Image.open('E:\Junior_N\computerVision\imgTest\IMG20190831164243.jpg')
image.save('E:\Junior_N\computerVision\imgTest\Lab_1\saveTestImg.bmp')
image.show()

运行结果:

  

2.3.2 convert() 方法

由于save()方法有些格式无法成功转换,故提供含有多个参数,比如 mode、matrix、dither 等的convert()方法,其中最关键的参数是 mode。

语法格式如下:

convert(mode,parms**)

mode:指的是要转换成的图像模式;
params:其他可选参数。

实验代码:

from PIL import Image

image = Image.open('E:\Junior_N\computerVision\imgTest\Lab_1\IMG20190831164243.png')
image = image.convert('RGB')
image.save('E:\Junior_N\computerVision\imgTest\Lab_1\saveTestImg2.jpg')
image.show()

运行结果:

此外,图像的颜色转换也可以使用convert()方法实现。要读取一幅图像,并将其转换成灰度图像,只需要加上convert('L')。

实验代码:

from PIL import Image

image = Image.open('E:\Junior_N\computerVision\imgTest\IMG20190831164243.jpg')
image = image.convert('L')
image.save('E:\Junior_N\computerVision\imgTest\Lab_1\convertTest1.jpg')
image.show()

运行结果:

2.4 创建缩略图

使用PIL可以很方便地创建图像的缩略图。thumbnail()方法接受一个元组参数(该元组参数指定生成缩略图的大小),然后将图像转换成符合元组参数指定大小的缩略图。

语法格式如下:

thumbnail(size,resample)

创建一个指定大小(size)的缩略图,需要注意的是,thumbnail方法是原地操作,返回值是None。第一个参数是指定的缩略图的大小,第二个是采样的方法。

例如,创建最长边为128像素的缩略图,可以使用下列命令:

image.thumbnail((128,128))

实验代码:

from PIL import Image

image = Image.open('E:\Junior_N\computerVision\imgTest\IMG20190831164243.jpg')
image.thumbnail((128,128))
image.save('E:\Junior_N\computerVision\imgTest\Lab_1\ thumbnailTest.jpg')
image.show()

运行效果:

 2.5 复制和粘贴图像区域

2.5.1 crop()方法的使用

Image 类提供的 crop() 函数允许我们以矩形区域的方式对原图像进行裁剪,函数的语法格式如下:

imageCopy = image.crop(box=None)

box:表示裁剪区域,默认为 None,表示拷贝原图像。

注意:box 是一个有四个数字的元组参数 (x_左上,y_左下,x1_右上,y1_右下),分别表示被裁剪矩形区域的左上角 x、y 坐标和右下角 x,y 坐标。默认 (0,0) 表示坐标原点,宽度的方向为 x 轴,高度的方向为 y 轴,每个像素点代表一个单位。

实验代码:(box值为默认None)

from PIL import Image

image = Image.open('E:\Junior_N\computerVision\imgTest\IMG20190831164243.jpg')
imageCopy = image.crop(box=None)
imageCopy.save('E:\Junior_N\computerVision\imgTest\Lab_1\imageCopyNoneTest.jpg')
imageCopy.show()

运行结果:

实验代码:box = (100,100,400,400)

from PIL import Image

image = Image.open('E:\Junior_N\computerVision\imgTest\IMG20190831164243.jpg')
box = (100,100,400,400)
imageCopy = image.crop(box)
imageCopy.save('E:\Junior_N\computerVision\imgTest\Lab_1\imageCopyTest.jpg')
imageCopy.show()

运行结果:

 2.5.2 paste()方法

paste()方法在原图上修改它的 Image 对象,它不会返回粘贴后图像的 Image 对象。如果想调用 paste(),但还要保持原始图像的未修改版本,就需要先复制图像,然后在副本上调用 paste()。

 paste() 方法语法格式如下所示:

paste(image, box=None, mask=None)

该函数的作用是将一张图片粘贴至另一张图片中。注意,粘贴后的图片模式将自动保持一致,不需要进行额外的转换。参数说明如下:

image:指被粘贴的图片。

box:指定图片被粘贴的位置或者区域,其参数值是长度为 2 或者 4 的元组序列,长度为 2 时,表示具体的某一点 (x,y);长度为 4 则表示图片粘贴的区域,此时区域的大小必须要和被粘贴的图像大小保持一致。

mask:可选参数,为图片添加蒙版效果。

实验代码:

from PIL import Image

image = Image.open('E:\Junior_N\computerVision\imgTest\IMG20190831164243.jpg')
imageCopy = image.copy()#复制一张图片副本
imageCopy = imageCopy.crop((0,0,200,100)) #对副本进行裁剪
# #创建一个新的图像作为蒙版,L模式,单颜色值
# image_new = Image.new(‘L’, (200, 100), 200)
imageCopy.paste(imageCopy,(100,100,300,200)) #mask=image_new
imageCopy.save('E:\Junior_N\computerVision\imgTest\Lab_1\imagePasteTest.jpg')
imageCopy.show()

运行效果:

2.6 调整尺寸和旋转

2.6.1 resize()方法

resize()方法的参数是一个元组,用来指定新图像的大小。

实验代码:

from PIL import Image

image = Image.open('E:\Junior_N\computerVision\imgTest\IMG20190831164243.jpg')
imageResize = image.resize((300,300))
imageResize.save('E:\Junior_N\computerVision\imgTest\Lab_1\imageResizeTest.jpg')
imageResize.show()

运行效果:

2.6.2 rotate()方法

rotate()方法可以实现一幅图像的旋转,其参数使用逆时针方式表示旋转角度。 

实验代码:(以逆时针旋转60°为例)

from PIL import Image

image = Image.open('E:\Junior_N\computerVision\imgTest\IMG20190831164243.jpg')
imageRotate = image.rotate(60)
imageRotate.save('E:\Junior_N\computerVision\imgTest\Lab_1\imageRotateTest.jpg')
imageRotate.show()

运行效果:

三、Matplotlib库的用法介绍

3.1 绘制图像、点和线

3.1.1 imshow()绘制图像

实验代码:

from PIL import Image
from pylab import *

#读取图像到数组中
image = array(Image.open('E:\Junior_N\computerVision\imgTest\IMG20190831164243.jpg'))
#绘制图像
imshow(image) 
#显示绘制的图像
show()

运行效果:

3.1.2 plot(x,y,' ')绘制点

在使用plot(x,y,' ')绘制点前需要先给出一些点的坐标,例如

x = [100,200,300,400]

y = [200,300,400,500]

plot(x,y,' ')绘制点语法:

plot(x,y,**kwargs)

具体参数解释如下: 

x,y表示需要绘制点的坐标。

**kwargs可以控制其颜色和样式。其部分短命令如下:

plot(x,y)        #默认为蓝色实线

plot(x,y,'r*')   #红色形状标记

plot(x,y,'go-')  #带有圆圈标记的绿线

plot(x,y,'ks:')   #带有正方形标记的黑色点线

实验代码:

#读取图像到数组中
image = array(Image.open('E:\Junior_N\computerVision\imgTest\IMG20190831164243.jpg'))
#绘制图像
imshow(image)

#需要绘制点的坐标
x = [100,200,300,400]
y = [200,300,400,500]

plot(x,y,'bo') #使用蓝色圆圈状标记绘制点

#显示绘制的图像
show()

运行效果:

3.1.3 plot(x[:4],y[:4])绘制线

实验代码:

from PIL import Image
from pylab import *

#读取图像到数组中
image = array(Image.open('E:\Junior_N\computerVision\imgTest\IMG20190831164243.jpg'))
#绘制图像
imshow(image)

#需要绘制点的坐标
x = [100,200,300,400]
y = [200,300,400,500]

plot(x,y,'bo') #使用蓝色圆圈状标记绘制点

plot(x[:4],y[:4]) #绘制连线将前四个点连成线
title('Plotting: "imagePlotTest.jpg"')

#显示绘制的图像
show()

运行效果:

 在PyLab库中约定图像的左上角为坐标原点,图像的坐标轴是一个很有用的调试工具,但也可以加上下列命令使坐标轴不显示:

axis('off')

其效果如下:

3.2 图像轮廓和直方图

3.2.1 contour()方法实现图像轮廓提取

绘制轮廓需要对每个坐标[x,y]的像素值施加同一个阈值,所以首先将图像灰度化。前面也提到使用PIL的convert()方法可以将图像转化为灰度图像。

实验代码:

from PIL import Image
from pylab import *

#将图像转化为灰度图并读取到数组中
image = array(Image.open('E:\Junior_N\computerVision\imgTest\IMG20190831164243.jpg').convert('L'))

#新建一个图像
figure()
#不使用颜色信息
gray()
#在原点的左上角显示轮廓图像
contour(image,origin='image')
axis('equal')
axis('off')

show()

运行结果;

 3.2.2 hist()函数绘制直方图

图像的直方图用来表征该图像像素的分布情况。用一定数目的小区间(bin)来指定表征像素值的范围,每个小区间会得到落入该小区间表示范围的像素数目。该(灰度)图像的直方图使用hist()函数绘制,hist()函数的第二个参数指定小区间的数目。需要注意的是,因为hist()只接受一维数组作为输入,所以我们在绘制图像直方图之前,必须先对图像进行压平处理。flatten()方法将任意数组按照行优先准测转换成一维数组。

实验代码:(结合上一部分得到的灰度图)

from PIL import Image
from pylab import *

#将图像转化为灰度图并读取到数组中
image = array(Image.open('E:\Junior_N\computerVision\imgTest\IMG20190831164243.jpg').convert('L'))

#新建一个图像
figure()
#不使用颜色信息
gray()
#在原点的左上角显示轮廓图像
contour(image,origin='image')
axis('equal')
axis('off')

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

运行结果:

 3.3 交互式标注

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

实验代码:

from PIL import Image
from pylab import *

image = array(Image.open('E:\Junior_N\computerVision\imgTest\IMG20190831164243.jpg'))
imshow(image)
print ('please click 4 points')
x = ginput(4)
print ('you clicked:',x)

show()

上面的代码首先绘制一幅图像,然后等待用户在绘制窗口的图像区域点击4次。程序将这些点击的坐标[x,y]自动保存在x列表里。 

运行效果:

四、NumPy库的用法介绍

4.1 图像数组表示

当载入图像时,通过array()方法将图像转换成NumPy的数组对象。NumPy中的数组对象是多维的,可以用来表示向量、矩阵和图像。一个数组对象很像一个列表(或者是列表的列表),但是数组中所有的元素必须具有相同的数据类型。除非创建数组对象时指定数据类型,否则数据类型会按照数据的类型自动确定。

PyLab实际上包含NumPy的一些内容,如数组类型。

测试代码:

from PIL import Image
from pylab import *

# from numpy import *

image = array(Image.open('E:\Junior_N\computerVision\imgTest\IMG20190831164243.jpg'))
print(image.shape,image.dtype)

image = array(Image.open('E:\Junior_N\computerVision\imgTest\IMG20190831164243.jpg').convert('L'),'f')
print(image.shape,image.dtype)

show()

运行结果:

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

数组中的元素可以使用下标访问。位于坐标i、j,以及颜色通道k的像素值可以像下面这样访问:

value = image[i,j,k]

多个数组元素可以使用数组切片方式访问。切片方式返回的是以指定间隔下标访问该数组的元素值。下面是有关灰度图像的一些例子:

image[i,:] = image[j,:]                       #将第j行的数值赋值给第i行
image[:,i] = 100                                #将第i列的所有数值设为100
image[:100, :50].sum()                     #计算前100行、前50列所有数值的和
image[50: 100, 50:100]                    # 50~100行, 50~100列(不包括第100行和第100列)
image[i].mean()                                #第i行所有数值的平均值
image[:,-1]                                        #最后一列
image[-2,:] (or image[-2])                 #倒数第二行


注意,示例仅仅使用一个下标访问数组。如果仅使用一个下标,则该下标为行下标。注意,在最后几个例子中,负数切片表示从最后一个元素逆向计数。我们将会频繁地使用切片技术访问像素值,这也是一个很重要的思想。

4.2 灰度变换

实验代码:

from PIL import Image
from pylab import *
from numpy import *

im = array(Image.open('E:\Junior_N\computerVision\imgTest\IMG20190831164243.jpg').convert('L'))
gray()
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()))

#figure()
subplot(2,2,1)
axis('off')
title('im')
imshow(im)

subplot(2,2,2)
axis('off')
title('f(x)= (100.0/255) * im + 100')
imshow(im2)

subplot(2,2,3)
axis('off')
title('f(x)= 255 - im')
imshow(im3)

subplot(2,2,4)
axis('off')
title('f(x)= 255.0 * (im/255.0)**2')
imshow(im4)

show()

运行结果:

 

 第一张是灰度图;第二张图是将灰度图像进行反相处理;第三张图将图像的像素值变换到 100...200区间;第四张图是对图像使用二次函数变换,使较暗的像素值变得更小。

4.3 图像缩放

把下面的函数添加到 imtool.py 文件里:
def imresize(im,sz):
    """ 使用 PIL 对象重新定义图像数组的大小 """
    pil_im = Image.fromarray(uint8(im))
    return array(pil_im.resize(sz))

4.4 直方图均衡化

直方图均衡化是指将一幅图像的灰度直方图变平,使变换后的图像中每个灰度值的分布概率都相同。在对图 像做进一步处理之前,直方图均衡化通常是对图像灰度值进行归一化的一个非常好的方法,并且可以增强图像的对比度。
把下面的函数添加到 imtool.py 文件里:
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 im2.reshape(im.shape), cdf
该函数有两个输入参数,一个是灰度图像,一个是直方图中使用小区间的数目。函
数返回直方图均衡化后的图像,以及用来做像素值映射的累积分布函数。注意,函
数中使用到累积分布函数的最后一个元素(下标为 - 1 ),目的是将其归一化到 0...1
范围。
测试代码:
im = array(Image.open('E:\Junior_N\computerVision\imgTest\IMG20190831164243.jpg').convert('L'))
im2,cdf = imtools.histeq(im)

figure()
subplot(2,2,1)
axis('off')
gray()
title("im")
imshow(im)

subplot(2,2,2)
axis('off')
title("im2")
imshow(im2)

subplot(2,2,3)
axis('off')
title("hist im")
hist(im.flatten(),128,density=True)

subplot(2,2,4)
axis('off')
title("hist im2")
hist(im2.flatten(),128,density=True)

show()

运行效果:

 可以看到,直方图均衡化后图像的对比度增强了,原先图像灰色区域的细节变得清晰。

4.5 图像平均

图像平均操作是减少图像噪声的一种简单方式,通常用于艺术特效。我们可以简单
地从图像列表中计算出一幅平均图像。假设所有的图像具有相同的大小,我们可以
将这些图像简单地相加,然后除以图像的数目,来计算平均图像。
下面的函数可以
用于计算平均图像,将其添加到 imtool.py 文件里:
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() 函数需要将所有的图像堆积到一个数组中;
也就是说,如果有很多图像,该处理方式需要占用很多内存。

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

PCA Principal Component Analysis ,主成分分析)是一个非常有用的降维技巧。它
可以在使用尽可能少维数的前提下,尽量多地保持训练数据的信息,在此意义上是
一个最佳技巧。即使是一幅 100 × 100 像素的小灰度图像,也有 10 000 维,可以看
10 000 维空间中的一个点。一兆像素的图像具有百万维。由于图像具有很高的维
数,在许多计算机视觉应用中,我们经常使用降维操作。 PCA 产生的投影矩阵可以
被视为将原始坐标变换到现有的坐标系,坐标系中的各个坐标按照重要性递减排列。
为了对图像数据进行 PCA 变换,图像需要转换成一维向量表示。我们可以使用
NumPy 类库中的 flatten() 方法进行变换。
将变平的图像堆积起来,我们可以得到一个矩阵,矩阵的一行表示一幅图像。在计算
主方向之前,所有的行图像按照平均图像进行了中心化。我们通常使用 SVD Singular
Value Decomposition ,奇异值分解)方法来计算主成分;但当矩阵的维数很大时,
SVD 的计算非常慢,所以此时通常不使用 SVD 分解。
下面就是 PCA 操作的代码:
#####################PCA主成分分析#########
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
该函数首先通过减去每一维的均值将数据中心化,然后计算协方差矩阵对应最大
特征值的特征向量,此时可以使用简明的技巧或者 SVD 分解。这里我们使用了
range() 函数,该函数的输入参数为一个整数 n ,函数返回整数 0...( n - 1) 的一个列
表。你也可以使用 arange() 函数来返回一个数组,或者使用 xrange() 函数返回一个
产生器(可能会提升速度)。

 4.7 使用pickle模块

pickle 模块可以接受几乎所有的 Python 对象,并且将其转换成字符串表示,该
过程叫做 封装 pickling )。从字符串表示中重构该对象,称为 拆封 unpickling )。
这些字符串表示可以方便地存储和传输。

五、SciPy库的用法介绍

SciPy http://scipy.org/ )是建立在 NumPy 基础上,用于数值运算的开源工具包。
SciPy 提供很多高效的操作,可以实现数值积分、优化、统计、信号处理,以及对
我们来说最重要的图像处理功能。

5.1 图像模糊

图像的 高斯模糊 是非常经典的图像卷积例子。本质上,图像模糊就是将(灰度)图
I 和一个高斯核进行卷积操作:
其中 * 表示卷积操作; G σ 是标准差为 σ 的二维高斯核,定义为 :
高斯模糊通常是其他图像处理操作的一部分,比如图像插值操作、兴趣点计算以及
很多其他应用。
SciPy 有用来做滤波操作的 scipy.ndimage.filters 模块。该模块使用快速一维分离
的方式来计算卷积。
代码:
from scipy.ndimage import filters

im = array(Image.open('E:\Junior_N\computerVision\imgTest\IMG20190831164243.jpg').convert('L'))

figure()
gray()
axis('off')
subplot(1,4,1)
axis('off')
title(u'原图',fontproperties=font)
imshow(im)

for bi,blur in enumerate([2,5,10]):
    im2=zeros(im.shape)
    im2=filters.gaussian_filter(im,blur)
    im2=np.uint8(im2)
    imNum=str(blur)
    subplot(1,4,2 + bi)
    axis('off')
    title(u'标准差为'+imNum,fontproperties=font)
    imshow(im2)

5.2 一些有用的SciPy模块

SciPy 中包含一些用于输入和输出的实用模块。下面介绍其中两个模块: io misc
1. 读写.mat文件
如果你有一些数据,或者在网上下载到一些有趣的数据集,这些数据以 Matlab的。
.mat 文件格式存储,那么可以使用 scipy.io 模块进行读取。
data = scipy.io.loadmat('test.mat')
上面代码中, data 对象包含一个字典,字典中的键对应于保存在原始 .mat 文件中的
变量名。由于这些变量是数组格式的,因此可以很方便地保存到 .mat 文件中。你仅
需创建一个字典(其中要包含你想要保存的所有变量),然后使用 savemat() 函数:
data = {}
data['x'] = x
scipy.io.savemat('test.mat',data)
因为上面的脚本保存的是数组 x ,所以当读入到 Matlab 中时,变量的名字仍为 x
关 于 scipy.io 模 块 的 更 多 内 容, 请 参 见 在 线 文 档 http://docs.scipy.org/doc/scipy/
reference/io.html
2. 以图像形式保存数组
因为我们需要对图像进行操作,并且需要使用数组对象来做运算,所以将数组直接
保存为图像文件 1 非常有用。本书中的很多图像都是这样的创建的。
imsave() 函数可以从 scipy.misc 模块中载入。要将数组 im 保存到文件中,可以使用
下面的命令:
from scipy.misc import imsave
imsave('test.jpg',im)
scipy.misc 模块同样包含了著名的 Lena 测试图像:
lena = scipy.misc.lena()
该脚本返回一个 512 × 512 的灰度图像数组。

5.3 高级示例:图像去噪

图像 去噪 是在去除图像噪声的同时,尽可能地保留图像细节和结构的处理技术。我们这里使用 ROF(Rudin-Osher-Fatemi 去噪模型
ROF 模型具有很好的性质:使处理后的图像更平滑,同时保持图像边缘和结构信息。
使用ROF模型实现去噪:
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  # 去噪后的图像和纹理残余

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值