学习python计算机视觉编程,首先就要了解一下图像处理的一些基础知识,本文结合实例介绍一些图像处理的基础知识,如:读取图像、灰度变换、图像转换和缩放、PCA等,包含PIL、Matplotlib、NumPy库和SciPy模块。下面让我们一起来学习一下吧!
注:博主所用的是win10+python2.7
第1章 基本的图像操作和处理
1.1 PIL:Python图像处理类库
PIL(Python Imaging Library,图像处理库)提供了通用的图像处理功能,以及大量有用的基本图像操作,比如图像缩放、裁剪、旋转、颜色转换等。PIL库下载地址[www.pythonware.com/products/pil/]。
下面举一个利用PIL读取图像的例子:
# -*- coding: utf-8 -*-
from PIL import Image
from pylab import *
# 添加中文字体支持
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
figure()
pil_im = Image.open('d:/Eating.jpg')
gray()
subplot(121)
title(u'原图',fontproperties=font)
axis('off')
imshow(pil_im)
pil_im = Image.open('d:/Eating.jpg').convert('L')#将图像转化成灰度图
subplot(122)
title(u'灰度图',fontproperties=font)
axis('off')
imshow(pil_im)
show()
1.1.1 转换图像格式——save()
方法
利用save()
方法,PIL可以将图片保存为很多不同的图像格式。
下面举一个将一个文件夹的jpg图像转换成png图像的例子:
from PCV.tools.imtools import get_imlist #导入原书的PCV模块
from PIL import Image
import os
import pickle
filelist = get_imlist('D:/test/test1') #获取D:/test/test1文件夹下的图片文件名(包括后缀名)
imlist = file('D:/test/imlist.txt','w') #将获取的图片文件列表保存到imlist.txt中
pickle.dump(filelist,imlist) #序列化
imlist.close()
for infile in filelist:
outfile = os.path.splitext(infile)[0] + ".png" #分离文件名与扩展名
if infile != outfile:
try:
Image.open(infile).save(outfile)
except IOError:
print ("cannot convert"), infile
1.1.2 创建缩略图——thumbnail()方法
利用PIL可以很容易的创建缩略图,设置缩略图的大小,并用元组保存起来,调用thumnail()方法即可生成缩略图。
1.1.3 拷贝并粘贴区域——crop()方法
调用crop()方法即可从一幅图像中进行区域拷贝,拷贝出区域后,可以对区域进行旋转等变换。。
1.1.4 调整尺寸及旋转——rotate()方法
要对一幅图像的尺寸进行调整,可以调用resize()方法,元组中放置的便是你要调整尺寸的大小。
下面举一个对图像进行灰度化、拷贝粘贴、缩略图、调整尺度、旋转90度的例子:
# -*- coding: utf-8 -*-
from PIL import Image
from pylab import *
# 添加中文字体支持
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
figure()
# 显示原图
pil_im = Image.open('d:\Eating.jpg')
print (pil_im.mode, pil_im.size, pil_im.format)
subplot(231)
title(u'原图', fontproperties=font)
axis('off')
imshow(pil_im)
# 显示灰度图
pil_im = Image.open('d:\Eating.jpg').convert('L')
gray()
subplot(232)
title(u'灰度图', fontproperties=font)
axis('off')
imshow(pil_im)
#拷贝粘贴区域
pil_im = Image.open('d:\Eating.jpg')
box = (100,100,200,200)
region = pil_im.crop(box)
region = region.transpose(Image.ROTATE_180)
pil_im.paste(region,box)
subplot(233)
title(u'拷贝粘贴区域', fontproperties=font)
axis('off')
imshow(pil_im)
# 缩略图
pil_im = Image.open('d:\Eating.jpg')
size = 64, 64
pil_im.thumbnail(size)
print (pil_im.size)
subplot(234)
title(u'缩略图', fontproperties=font)
axis('off')
imshow(pil_im)
pil_im.save('d:\Eating1.jpg') #保存缩略图
# 调整图像尺寸
pil_im = Image.open('d:\Eating.jpg')
pil_im = pil_im.resize(size)
print (pil_im.size)
subplot(235)
title(u'调整尺寸后的图像', fontproperties=font)
axis('off')
imshow(pil_im)
# 旋转图像90°
pil_im = Image.open('d:\Eating.jpg')
pil_im = pil_im.rotate(90)
subplot(236)
title(u'旋转90°后的图像', fontproperties=font)
axis('off')
imshow(pil_im)
show()
1.2 Matplotlib库
当在处理数学及绘图或在图像上描点、画直线、曲线时,Matplotlib是一个很好的绘图库,它比PIL库提供了更有力的特性。Matplotlib是开源的,可以在[matplotlib.sourceforge.net]上下载,并且它还提供了详细的文档及教程。。
1.2.1 画图、描点和线
虽然Matplotlib可以创建漂亮的条状图、饼图、散点图等,但是在很多计算机视觉应用场合,其实只用到了一些常用的命令。
下面举一个在图像上描一些点和画一条直线的例子:
# -*- coding: utf-8 -*-
from PIL import Image
from pylab import *
# 添加中文字体支持
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
im = array(Image.open('d:\Eating.jpg'))
figure()
# 画有坐标轴的
subplot(121)
imshow(im)
x = [50, 150, 50, 150]
y = [50, 125, 125, 50]
plot(x, y, 'r*')
plot(x[:2], y[:2])
title(u'绘图: "Eating.jpg"', fontproperties=font)
# 不显示坐标轴
subplot(122)
imshow(im)
x = [50, 150, 50, 150]
y = [50, 125, 125, 59]
plot(x, y, 'r*')
plot(x[:2], y[:2])
axis('off') #显示坐标轴
title(u'绘图: "Eating.jpg"', fontproperties=font)
show()
注:axis('off')可以使坐标轴不显示
绘图时还有很多可选的颜色和样式:
plot(x,y) #默认为蓝色实线
plot(x,y,'r*') #红色星状标记
plot(x,y,'go-') #带有圆圈标记的绿线
plot(x,y,'ks:') #带有正方形标记的黑色虚线
符号 | 颜色 |
---|---|
‘b’ | 蓝色 |
‘g’ | 绿色 |
‘r’ | 红色 |
‘c’ | 青色 |
‘m’ | 品红 |
‘y’ | 黄色 |
‘w’ | 白色 |
‘k’ | 黑色 |
符号 | 线型 |
---|---|
‘-‘ | 实线 |
‘–’ | 虚线 |
‘:’ | 点线 |
符号 | 标记 |
---|---|
‘.’ | 点 |
‘o’ | 圆圈 |
’s’ | 正方形 |
‘*’ | 星型 |
‘+’ | 加号 |
‘*’ | 叉号 |
1.2.2 图像轮廓和直方图
运用convert()方法可以将图像转换成灰度图,运用hist()函数可以绘制一个图像的直方图。
下面举一个显示图像轮廓和直方图的例子:
# -*- coding: utf-8 -*-
from PIL import Image
from pylab import *
# 添加中文字体支持
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
im = array(Image.open('d:\Eating.jpg').convert('L')) # 打开图像,并转成灰度图像
figure()
subplot(121)
gray()
contour(im, origin='image')
axis('equal')
axis('off')
title(u'图像轮廓', fontproperties=font)
subplot(122)
hist(im.flatten(), 128)
title(u'图像直方图', fontproperties=font)
plt.xlim([0,260])
plt.ylim([0,1100])
show()
注:flatten()方法可以将任意数组按照行优先准则转化成一维数组。
1.2.3 交互注释——ginput()函数
有时,用户需要和应用进行交互,比如在图像中用点做标识,或者在一些训练数据中进行注释。PyLab库中的ginput()函数可以完成该任务。
下面是举一个在等待用户在图像上点击三次后,输出三个点击点的坐标[x,y]自动保存在x列表的例子:
from PIL import Image
from pylab import *
im = array(Image.open('d:\Eating.jpg'))
imshow(im)
print 'Please click 3 points'
imshow(im)
x = ginput(3)
print 'You clicked:', x
show()
输出:
1.3 NumPy库
NumPy是Python一个流行的用于科学计算包。它包含了很多诸如矢量、矩阵、图像等其他非常有用的对象和线性代数函数。NumPy可以在scipy.org/Download]下载,在线文档包含了很多常见问题的答案。
1.3.1 图像数组表示
在前面载入图像的示例中,我们将图像用array()函数转为NumPy数组对象,但是并没有提到它表示的含义。数组就像列表一样,只不过它规定了数组中的所有元素必须是相同的类型。下面的例子用于说明图像数组表示:
# -*- coding: utf-8 -*-
from PIL import Image
from pylab import *
im = array(Image.open('d:\Eating.jpg'))
print (im.shape, im.dtype)
im = array(Image.open('d:\Eating.jpg').convert('L'),'f')
print (im.shape, im.dtype)
输出:
1.3.2 灰度变换
在读入图像到NumPy数组后,就可以对它进行任何我们想要的操作了。对图像进行灰度变换便是一个简单的例子。
这里给出一些进行灰度变换的例子:
# -*- coding: utf-8 -*-
from PIL import Image
from numpy import *
from pylab import *
im = array(Image.open('d:\Eating.jpg').convert('L'))
print (int(im.min()), int(im.max()))
im2 = 255 - im # invert image
print (int(im2.min()), int(im2.max()))
im3 = (100.0/255) * im + 100 # clamp to interval 100...200
print (int(im3.min()), int(im3.max()))
im4 = 255.0 * (im/255.0)**2 # squared
print (int(im4.min()), int(im4.max()))
figure()
gray()
subplot(1, 3, 1)
imshow(im2)
axis('off')
title(r'$f(x)=255-x$')
subplot(1, 3, 2)
imshow(im3)
axis('off')
title(r'$f(x)=\frac{100}{255}x+100$')
subplot(1, 3, 3)
imshow(im4)
axis('off')
title(r'$f(x)=255(\frac{x}{255})^2$')
show()
输出:
上图输出原图和变化后的图像像素值的最大值和最小值。
其中,左边的图是对图像进行反处理后的图像,中间的图是将图像像素值变换到100-200区间后的图像,右边的图是将图像像素求平方后得到的图像。
1.3.3 直方图均衡化
图像灰度变换中一个极其有用的例子是直方图均衡化。图像均衡化作为预处理操作,在归一化图像强度时是一个很好的方式,并且通过直方图均衡化可以增加图像对比度。
下面是一个对图像直方图进行均衡化处理的例子:
# -*- coding: utf-8 -*-
from PIL import Image
from pylab import *
from PCV.tools import imtools
# 添加中文字体支持
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
im = array(Image.open('d:\Eating.jpg').convert('L')) # 打开图像,并转成灰度图像
#im = array(Image.open('../data/AquaTermi_lowcontrast.JPG').convert('L'))
im2, cdf = imtools.histeq(im)
figure()
subplot(2, 2, 1)
axis('off')
gray()
title(u'原始图像', fontproperties=font)
imshow(im)
subplot(2, 2, 2)
axis('off')
title(u'直方图均衡化后的图像', fontproperties=font)
imshow(im2)
subplot(2, 2, 3)
axis('off')
title(u'原始直方图', fontproperties=font)
#hist(im.flatten(), 128, cumulative=True, normed=True)
hist(im.flatten(), 128, normed=True)
subplot(2, 2, 4)
axis('off')
title(u'均衡化后的直方图', fontproperties=font)
#hist(im2.flatten(), 128, cumulative=True, normed=True)
hist(im2.flatten(), 128, normed=True)
show()
由上图对比,可以明显看出,直方图经过均衡化后图像的对比度明显增强。
1.3.4 图像平均
图像平均操作是一种图像降噪的简单方法,经常用于产生艺术效果。假设所有的图像具有相同的尺寸,我们可以对图像相同位置的像素相加取平均,
下面是举一个对三张图像取平均的例子:
# -*- coding: utf-8 -*-
from PCV.tools.imtools import get_imlist
from PIL import Image
from pylab import *
from PCV.tools import imtools
# 添加中文字体支持
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
filelist = get_imlist('D:/test/test1') #获取D:/test/test1文件夹下的图片文件名(包括后缀名)
avg = imtools.compute_average(filelist)
for impath in filelist:
im1 = array(Image.open(impath))
subplot(2, 2, filelist.index(impath)+1)
imshow(im1)
imNum=str(filelist.index(impath)+1)
title(u'待平均图像'+imNum, fontproperties=font)
axis('off')
subplot(2, 2, 4)
imshow(avg)
title(u'平均后的图像', fontproperties=font)
axis('off')
show()
1.3.5 对图像进行主成分分析
主成分分析是一项有用的降维技术。它可以在使用尽可能少维数的前提下,尽量多地保持训练数据的信息,在此意义上是一个最佳技巧。即使是一幅 100×100 像素的小灰度图像,也有 10 000 维,可以看成 10 000 维空间中的一个点。一兆像素的图像具有百万维。由于图像具有很高的维数,在许多计算机视觉应用中,我们经常使用降维操作。PCA 产生的投影矩阵可以被视为将原始坐标变换到现有的坐标系,坐标系中的各个坐标按照重要性递减排列。
下面举一个利用PCA降维的例子:
# -*- coding: utf-8 -*-
import pickle
from PIL import Image
from numpy import *
from pylab import *
from PCV.tools import imtools, pca
# Uses sparse pca codepath.
#imlist = imtools.get_imlist('../data/selectedfontimages/a_selected_thumbs')
# 获取图像列表和他们的尺寸
imlist = imtools.get_imlist('D:/test/image3') # fontimages.zip is part of the book data set
im = array(Image.open(imlist[0])) # open one image to get the size
m, n = im.shape[:2] # get the size of the images
imnbr = len(imlist) # get the number of images
print "The number of images is %d" % imnbr
# Create matrix to store all flattened images
immatrix = array([array(Image.open(imname)).flatten() for imname in imlist], 'f')
# PCA降维
V, S, immean = pca.pca(immatrix)
# 保存均值和主成分
#f = open('../ch01/font_pca_modes.pkl', 'wb')
#pickle.dump(immean,f)
#pickle.dump(V,f)
#f.close()
# Show the images (mean and 7 first modes)
# This gives figure 1-8 (p15) in the book.
figure()
gray()
subplot(2, 4, 1)
axis('off')
imshow(immean.reshape(m, n))
for i in range(7):
subplot(2, 4, i+2)
imshow(V[i].reshape(m, n))
axis('off')
show()
注:reshape()函数可以将一维重新转换成二维图像。
1.4 SciPy模块
SciPy是一个开源的数学工具包,它是建立在NumPy的基础上的。它提供了很多有效的常规操作,包括数值综合、最优化、统计、信号处理以及图像处理。正如接下来所展示的,SciPy库包含了很多有用的模块。SciPy库可以在[http://scipy.org/Download]下载。
1.4.1 图像模糊
图像的高斯模糊是非常经典的图像卷积例子。本质上,图像模糊就是将(灰度)图像II 和一个高斯核进行卷积操作:
滤波操作模块——scipy.ndimage.filters
该模块可以使用快速一维分离的方式来计算卷积
下面举一个对图像进行不同程度模糊的例子:
# -*- coding: utf-8 -*-
from PIL import Image
from pylab import *
from scipy.ndimage import filters
# 添加中文字体支持
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
#im = array(Image.open('board.jpeg'))
im = array(Image.open('D:/Eating.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)
#如果是彩色图像,则分别对三个通道进行模糊
#for bi, blur in enumerate([2, 5, 10]):
# im2 = zeros(im.shape)
# for i in range(3):
# im2[:, :, i] = filters.gaussian_filter(im[:, :, i], blur)
# im2 = np.uint8(im2)
# subplot(1, 4, 2 + bi)
# axis('off')
# imshow(im2)
show()
上面第一幅图为待模糊图像,第二幅用高斯标准差为2进行模糊,第三幅用高斯标准差为5进行模糊,最后一幅用高斯标准差为10进行模糊。关于该模块的使用以及参数选择的更多细节,可以参阅SciPy scipy.ndimage文档[docs.scipy.org/doc/scipy/reference/ndimage.html]。
1.4.2 图像差分
图像强度的改变是一个重要的信息,被广泛用以很多应用中。
下面举一个利用Sobel倒数滤波器计算倒数图像的例子:
# -*- coding: utf-8 -*-
from PIL import Image
from pylab import *
from scipy.ndimage import filters
import numpy
# 添加中文字体支持
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
im = array(Image.open('D:/Eating.jpg').convert('L'))
gray()
subplot(1, 4, 1)
axis('off')
title(u'(a)原图', fontproperties=font)
imshow(im)
# Sobel derivative filters
imx = zeros(im.shape)
filters.sobel(im, 1, imx)
subplot(1, 4, 2)
axis('off')
title(u'(b)x方向差分', fontproperties=font)
imshow(imx)
imy = zeros(im.shape)
filters.sobel(im, 0, imy)
subplot(1, 4, 3)
axis('off')
title(u'(c)y方向差分', fontproperties=font)
imshow(imy)
#mag = numpy.sqrt(imx**2 + imy**2)
mag = 255-numpy.sqrt(imx**2 + imy**2)
subplot(1, 4, 4)
title(u'(d)梯度幅度', fontproperties=font)
axis('off')
imshow(mag)
show()
下面再举一个高斯差分的例子:
# -*- coding: utf-8 -*-
from PIL import Image
from pylab import *
from scipy.ndimage import filters
import numpy
# 添加中文字体支持
#from matplotlib.font_manager import FontProperties
#font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
def imx(im, sigma):
imgx = zeros(im.shape)
filters.gaussian_filter(im, sigma, (0, 1), imgx)
return imgx
def imy(im, sigma):
imgy = zeros(im.shape)
filters.gaussian_filter(im, sigma, (1, 0), imgy)
return imgy
def mag(im, sigma):
# there's also gaussian_gradient_magnitude()
#mag = numpy.sqrt(imgx**2 + imgy**2)
imgmag = 255 - numpy.sqrt(imgx ** 2 + imgy ** 2)
return imgmag
im = array(Image.open('D:/Eating.jpg').convert('L'))
figure()
gray()
sigma = [2, 5, 10]
for i in sigma:
subplot(3, 4, 4*(sigma.index(i))+1)
axis('off')
imshow(im)
imgx=imx(im, i)
subplot(3, 4, 4*(sigma.index(i))+2)
axis('off')
imshow(imgx)
imgy=imy(im, i)
subplot(3, 4, 4*(sigma.index(i))+3)
axis('off')
imshow(imgy)
imgmag=mag(im, i)
subplot(3, 4, 4*(sigma.index(i))+4)
axis('off')
imshow(imgmag)
show()
其中,第一行为σ=2的高斯导数滤波器处理后的图像;第二行为σ=5的高斯导数滤波器处理后的图像;第三行为σ=10的高斯导数滤波器处理后的图像。
1.5 更高级的例子:图像降噪
我们以一个非常有用的例子结束本章。图像降噪是一个在尽可能保持图像细节和结构信息时去除噪声的过程。我们采用Rudin-Osher-Fatemi de-noising(ROF)模型。图像去噪可以应用于很多场合,它涵盖了从你的度假照片使之更好看到卫星照片质量提高。
下面我们看一个图像降噪的综合实例:
# -*- coding: utf-8 -*-
from PIL import Image
from pylab import *
from numpy import *
from numpy import random
from scipy.ndimage import filters
from scipy.misc import imsave
from PCV.tools import rof
""" This is the de-noising example using ROF in Section 1.5. """
# 添加中文字体支持
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"c:\windows\fonts\SimSun.ttc", size=14)
im = array(Image.open('d:/Eating.jpg').convert('L'))
U,T = rof.denoise(im,im)
G = filters.gaussian_filter(im,10)
# save the result
#imsave('synth_original.pdf',im)
#imsave('synth_rof.pdf',U)
#imsave('synth_gaussian.pdf',G)
# plot
figure()
gray()
subplot(1,3,1)
imshow(im)
#axis('equal')
axis('off')
title(u'原噪声图像', fontproperties=font)
subplot(1,3,2)
imshow(G)
#axis('equal')
axis('off')
title(u'高斯模糊后的图像', fontproperties=font)
subplot(1,3,3)
imshow(U)
#axis('equal')
axis('off')
title(u'ROF降噪后的图像', fontproperties=font)
show()
其中第一幅图示原噪声图像,中间一幅图示用标准差为10进行高斯模糊后的结果,最右边一幅图是用ROF降噪后的图像。在去除噪声的同时,ROF降噪能够保持边缘和图像结构。
参考:http://yongyuan.name/pcvwithpython/chapter1.html
https://blog.csdn.net/jiaoyangwm/article/details/79293272