python图片处理技术
用python简单处理图片(1):打开\显示\保存图像
一提到数字图像处理,可能大多数人就会想到matlab,但matlab也有自身的缺点:
1、不开源,价格贵
2、软件容量大。一般3G以上,高版本甚至达5G以上。
3、只能做研究,不易转化成软件。
因此,我们这里使用python这个脚本语言来进行数字图像处理。
要使用python,必须先安装python,一般是2.7版本以上,不管是在windows系统,还是linux系统,安装都是非常简单的。
要使用python进行各种开发,就必须安装对应的库。这和matlab非常相似,只是matlab里面叫工具箱(toolbox),而python里面叫库或包。安装这些库,一般都是使用pip来安装。
使用python进行数字图片处理,还得安装Pillow包。虽然python里面自带一个PIL(python images library), 但这个库现在已经停止更新了,所以使用Pillow, 它是由PIL发展而来的。
pip install Pillow
一、图片的打开与显示
from PIL import Image img=Image.open('d:/dog.png') img.show()
虽然使用的是Pillow,但它是由PIL fork而来,因此还是要从PIL中进行import. 使用open()函数来打开图片,使用show()函数来显示图片。
这种图片显示方式是调用操作系统自带的图片浏览器来打开图片,有些时候这种方式不太方便,因此我们也可以使用另上一种方式,让程序来绘制图片。
from PIL import Image import matplotlib.pyplot as plt img=Image.open('d:/dog.png') plt.figure("dog") plt.imshow(img) plt.show()
这种方法虽然复杂了些,但推荐使用这种方法,它使用一个matplotlib的库来绘制图片进行显示。matplotlib是一个专业绘图的库,相当于matlab中的plot,可以设置多个figure,设置figure的标题,甚至可以使用subplot在一个figure中显示多张图片。matplotlib 可以直接安装
pip install matplotlib
figure默认是带axis的,如果没有需要,我们可以关掉
plt.axis('off')
打开图片后,可以使用一些属性来查看图片信息,如
print img.size #图片的尺寸 print img.mode #图片的模式 print img.format #图片的格式
显示结果为:
(558, 450) RGBA PNG
二、图片的保存
img.save('d:/dog.jpg')
就一行代码,非常简单。这行代码不仅能保存图片,还是转换格式,如本例中,就由原来的png图片保存为了jpg图片。
python数字图像处理(2):图像的读取、显示与保存
skimage提供了io模块,顾名思义,这个模块是用来图片输入输出操作的。为了方便练习,也提供一个data模块,里面嵌套了一些示例图片,我们可以直接使用。
引入skimage模块可用:
1 | from skimage import io |
一、从外部读取图片并显示
读取单张彩色rgb图片,使用skimage.io.imread(fname)函数,带一个参数,表示需要读取的文件路径。显示图片使用skimage.io.imshow(arr)函数,带一个参数,表示需要显示的arr数组(读取的图片以numpy数组形式计算)。
from skimage import io img=io.imread('d:/dog.jpg') io.imshow(img)
读取单张灰度图片,使用skimage.io.imread(fname,as_grey=True)函数,第一个参数为图片路径,第二个参数为as_grey, bool型值,默认为False
from skimage import io img=io.imread('d:/dog.jpg',as_grey=True) io.imshow(img)
二、程序自带图片
skimage程序自带了一些示例图片,如果我们不想从外部读取图片,就可以直接使用这些示例图片:
astronaut | 宇航员图片 | coffee | 一杯咖啡图片 | lena | lena美女图片 |
camera | 拿相机的人图片 | coins | 硬币图片 | moon | 月亮图片 |
checkerboard | 棋盘图片 | horse | 马图片 | page | 书页图片 |
chelsea | 小猫图片 | hubble_deep_field | 星空图片 | text | 文字图片 |
clock | 时钟图片 | immunohistochemistry | 结肠图片 |
显示这些图片可用如下代码,不带任何参数
from skimage import io,data img=data.lena() io.imshow(img)
图片名对应的就是函数名,如camera图片对应的函数名为camera(). 这些示例图片存放在skimage的安装目录下面,路径名称为data_dir,我们可以将这个路径打印出来看看:
from skimage import data_dir print(data_dir)
显示为: D:\Anaconda3\lib\site-packages\skimage\data
也就是说,下面两行读取图片的代码效果是一样的:
from skimage import data_dir,data,io img1=data.lena() #读取lean图片 img2=io.imread(data_dir+'/lena.png') #读取lena图片
三、保存图片
使用io模块的imsave(fname,arr)函数来实现。第一个参数表示保存的路径和名称,第二个参数表示需要保存的数组变量。
from skimage import io,data img=data.chelsea() io.imshow(img) io.imsave('d:/cat.jpg',img)
保存图片的同时也起到了转换格式的作用。如果读取时图片格式为jpg图片,保存为png格式,则将图片从jpg图片转换为png图片并保存。
四、图片信息
如果我们想知道一些图片信息,可以在spyder编辑器的右上角显示:
也可以直接以程序方式打印输出
from skimage import io,data img=data.chelsea() io.imshow(img) print(type(img)) #显示类型 print(img.shape) #显示尺寸 print(img.shape[0]) #图片宽度 print(img.shape[1]) #图片高度 print(img.shape[2]) #图片通道数 print(img.size) #显示总像素个数 print(img.max()) #最大像素值 print(img.min()) #最小像素值 print(img.mean()) #像素平均值
结果输出:
<class 'numpy.ndarray'>
(300, 451, 3)
300
451
3
405900
231
0
115.305141661
用python简单处理图片(2):图像通道\几何变换\裁剪
一、图像通道
1、彩色图像转灰度图
from PIL import Image import matplotlib.pyplot as plt img=Image.open('d:/ex.jpg') gray=img.convert('L') plt.figure("beauty") plt.imshow(gray,cmap='gray') plt.axis('off') plt.show()
使用函数convert()来进行转换,它是图像实例对象的一个方法,接受一个 mode 参数,用以指定一种色彩模式,mode 的取值可以是如下几种:
· 1 (1-bit pixels, black and white, stored with one pixel per byte)
· L (8-bit pixels, black and white)
· P (8-bit pixels, mapped to any other mode using a colour palette)
· RGB (3x8-bit pixels, true colour)
· RGBA (4x8-bit pixels, true colour with transparency mask)
· CMYK (4x8-bit pixels, colour separation)
· YCbCr (3x8-bit pixels, colour video format)
· I (32-bit signed integer pixels)
· F (32-bit floating point pixels)
2、通道分离与合并
from PIL import Image import matplotlib.pyplot as plt img=Image.open('d:/ex.jpg') #打开图像 gray=img.convert('L') #转换成灰度 r,g,b=img.split() #分离三通道 pic=Image.merge('RGB',(r,g,b)) #合并三通道 plt.figure("beauty") plt.subplot(2,3,1), plt.title('origin') plt.imshow(img),plt.axis('off') plt.subplot(2,3,2), plt.title('gray') plt.imshow(gray,cmap='gray'),plt.axis('off') plt.subplot(2,3,3), plt.title('merge') plt.imshow(pic),plt.axis('off') plt.subplot(2,3,4), plt.title('r') plt.imshow(r,cmap='gray'),plt.axis('off') plt.subplot(2,3,5), plt.title('g') plt.imshow(g,cmap='gray'),plt.axis('off') plt.subplot(2,3,6), plt.title('b') plt.imshow(b,cmap='gray'),plt.axis('off') plt.show()
二、裁剪图片
从原图片中裁剪感兴趣区域(roi),裁剪区域由4-tuple决定,该tuple中信息为(left, upper, right, lower)。 Pillow左边系统的原点(0,0)为图片的左上角。坐标中的数字单位为像素点。
from PIL import Image import matplotlib.pyplot as plt img=Image.open('d:/ex.jpg') #打开图像 plt.figure("beauty") plt.subplot(1,2,1), plt.title('origin') plt.imshow(img),plt.axis('off') box=(80,100,260,300) roi=img.crop(box) plt.subplot(1,2,2), plt.title('roi') plt.imshow(roi),plt.axis('off') plt.show()
用plot绘制显示出图片后,将鼠标移动到图片上,会在右下角出现当前点的坐标,以及像素值。
三、几何变换
Image类有resize()、rotate()和transpose()方法进行几何变换。
1、图像的缩放和旋转
dst = img.resize((128, 128)) dst = img.rotate(45) # 顺时针角度表示
2、转换图像
dst = im.transpose(Image.FLIP_LEFT_RIGHT) #左右互换 dst = im.transpose(Image.FLIP_TOP_BOTTOM) #上下互换 dst = im.transpose(Image.ROTATE_90) #顺时针旋转 dst = im.transpose(Image.ROTATE_180) dst = im.transpose(Image.ROTATE_270)
transpose()和rotate()没有性能差别。
python数字图像处理(3):图像像素的访问与裁剪
图片读入程序中后,是以numpy数组存在的。因此对numpy数组的一切功能,对图片也适用。对数组元素的访问,实际上就是对图片像素点的访问。
彩色图片访问方式为:
img[i,j,c]
i表示图片的行数,j表示图片的列数,c表示图片的通道数(RGB三通道分别对应0,1,2)。坐标是从左上角开始。
灰度图片访问方式为:
gray[i,j]
例1:输出小猫图片的G通道中的第20行30列的像素值
from skimage import io,data img=data.chelsea() pixel=img[20,30,1] print(pixel)
输出为129
例2:显示红色单通道图片
from skimage import io,data img=data.chelsea() R=img[:,:,0] io.imshow(R)
除了对像素进行读取,也可以修改像素值。
例3:对小猫图片随机添加椒盐噪声
from skimage import io,data import numpy as np img=data.chelsea() #随机生成5000个椒盐 rows,cols,dims=img.shape for i in range(5000): x=np.random.randint(0,rows) y=np.random.randint(0,cols) img[x,y,:]=255 io.imshow(img)
这里用到了numpy包里的random来生成随机数,randint(0,cols)表示随机生成一个整数,范围在0到cols之间。
用img[x,y,:]=255这句来对像素值进行修改,将原来的三通道像素值,变为255
通过对数组的裁剪,就可以实现对图片的裁剪。
例4:对小猫图片进行裁剪
from skimage import io,data img=data.chelsea() roi=img[80:180,100:200,:] io.imshow(roi)
对多个像素点进行操作,使用数组切片方式访问。切片方式返回的是以指定间隔下标访问 该数组的像素值。下面是有关灰度图像的一些例子:
img[i,:] = im[j,:] # 将第 j 行的数值赋值给第 i 行 img[:,i] = 100 # 将第 i 列的所有数值设为 100 img[:100,:50].sum() # 计算前 100 行、前 50 列所有数值的和 img[50:100,50:100] # 50~100 行,50~100 列(不包括第 100 行和第 100 列) img[i].mean() # 第 i 行所有数值的平均值 img[:,-1] # 最后一列 img[-2,:] (or im[-2]) # 倒数第二行
最后我们再看两个对像素值进行访问和改变的例子:
例5:将lena图片进行二值化,像素值大于128的变为1,否则变为0
from skimage import io,data,color img=data.lena() img_gray=color.rgb2gray(img) rows,cols=img_gray.shape for i in range(rows): for j in range(cols): if (img_gray[i,j]<=0.5): img_gray[i,j]=0 else: img_gray[i,j]=1 io.imshow(img_gray)
这个例子,使用了color模块的rgb2gray()函数,将彩色三通道图片转换成灰度图。转换结果为float64类型的数组,范围为[0,1]之间。
例6:
from skimage import io,data img=data.chelsea() reddish = img[:, :, 0] >170 img[reddish] = [0, 255, 0] io.imshow(img)
这个例子先对R通道的所有像素值进行判断,如果大于170,则将这个地方的像素值变为[0,255,0], 即G通道值为255,R和B通道值为0。
用python简单处理图片(4):图像中的像素访问
前面的一些例子中,我们都是利用Image.open()来打开一幅图像,然后直接对这个PIL对象进行操作。如果只是简单的操作还可以,但是如果操作稍微复杂一些,就比较吃力了。因此,通常我们加载完图片后,都是把图片转换成矩阵来进行更加复杂的操作。
python中利用numpy库和scipy库来进行各种数据操作和科学计算。我们可以通过pip来直接安装这两个库
pip install numpy pip install scipy
以后,只要是在python中进行数字图像处理,我们都需要导入这些包:
from PIL import Image import numpy as np import matplotlib.pyplot as plt
打开图像并转化为矩阵,并显示:
from PIL import Image import numpy as np import matplotlib.pyplot as plt img=np.array(Image.open('d:/lena.jpg')) #打开图像并转化为数字矩阵 plt.figure("dog") plt.imshow(img) plt.axis('off') plt.show()
调用numpy中的array()函数就可以将PIL对象转换为数组对象。
查看图片信息,可用如下的方法:
print img.shape print img.dtype print img.size print type(img)
如果是RGB图片,那么转换为array之后,就变成了一个rows*cols*channels的三维矩阵,因此,我们可以使用
img[i,j,k]
来访问像素值。
例1:打开图片,并随机添加一些椒盐噪声
from PIL import Image import numpy as np import matplotlib.pyplot as plt img=np.array(Image.open('d:/ex.jpg')) #随机生成5000个椒盐 rows,cols,dims=img.shape for i in range(5000): x=np.random.randint(0,rows) y=np.random.randint(0,cols) img[x,y,:]=255 plt.figure("beauty") plt.imshow(img) plt.axis('off') plt.show()
例2:将lena图像二值化,像素值大于128的变为1,否则变为0
from PIL import Image import numpy as np import matplotlib.pyplot as plt img=np.array(Image.open('d:/pic/lena.jpg').convert('L')) rows,cols=img.shape for i in range(rows): for j in range(cols): if (img[i,j]<=128): img[i,j]=0 else: img[i,j]=1 plt.figure("lena") plt.imshow(img,cmap='gray') plt.axis('off') plt.show()
如果要对多个像素点进行操作,可以使用数组切片方式访问。切片方式返回的是以指定间隔下标访问 该数组的像素值。下面是有关灰度图像的一些例子:
img[i,:] = im[j,:] # 将第 j 行的数值赋值给第 i 行 img[:,i] = 100 # 将第 i 列的所有数值设为 100 img[:100,:50].sum() # 计算前 100 行、前 50 列所有数值的和 img[50:100,50:100] # 50~100 行,50~100 列(不包括第 100 行和第 100 列) img[i].mean() # 第 i 行所有数值的平均值 img[:,-1] # 最后一列 img[-2,:] (or im[-2]) # 倒数第二行
用python简单处理图片(5):图像直方图
我们先来看两个函数reshape和flatten:
假设我们先生成一个一维数组:
vec=np.arange(15) print vec
显示为:
[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14]
如果我们要把这个一维数组,变成一个3*5二维矩阵,我们可以使用reshape来实现
mat= vec.reshape(3,5) print mat
显示为
[[ 0 1 2 3 4] [ 5 6 7 8 9] [10 11 12 13 14]]
现在如果我们返过来,知道一个二维矩阵,要变成一个一维数组,就不能用reshape了,只能用flatten. 我们来看两者的区别
a1=mat.reshape(1,-1) #-1表示为任意,让系统自动计算 print a1 a2=mat.flatten() print a2
显示为:
a1: [[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14]] a2: [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14]
可以看出,用reshape进行变换,实际上变换后还是二维数组,两个方括号,因此只能用flatten.
我们要对图像求直方图,就需要先把图像矩阵进行flatten操作,使之变为一维数组,然后再进行统计。
一、画灰度图直方图
绘图都可以调用matplotlib.pyplot库来进行,其中的hist函数可以直接绘制直方图。
调用方式:
n, bins, patches = plt.hist(arr, bins=50, normed=1, facecolor='green', alpha=0.75)
hist的参数非常多,但常用的就这五个,只有第一个是必须的,后面四个可选
arr: 需要计算直方图的一维数组
bins: 直方图的柱数,可选项,默认为10
normed: 是否将得到的直方图向量归一化。默认为0
facecolor: 直方图颜色
alpha: 透明度
返回值 :
n: 直方图向量,是否归一化由参数设定
bins: 返回各个bin的区间范围
patches: 返回每个bin里面包含的数据,是一个list
from PIL import Image import numpy as np import matplotlib.pyplot as plt img=np.array(Image.open('d:/pic/lena.jpg').convert('L')) plt.figure("lena") arr=img.flatten() n, bins, patches = plt.hist(arr, bins=256, normed=1, facecolor='green', alpha=0.75) plt.show()
二、彩色图片直方图
实际上是和灰度直方图一样的,只是分别画出三通道的直方图,然后叠加在一起。
from PIL import Image import numpy as np import matplotlib.pyplot as plt src=Image.open('d:/ex.jpg') r,g,b=src.split() plt.figure("lena") ar=np.array(r).flatten() plt.hist(ar, bins=256, normed=1,facecolor='r',edgecolor='r',hold=1) ag=np.array(g).flatten() plt.hist(ag, bins=256, normed=1, facecolor='g',edgecolor='g',hold=1) ab=np.array(b).flatten() plt.hist(ab, bins=256, normed=1, facecolor='b',edgecolor='b') plt.show()
由此可见,matplotlib的画图功能是非常强大的,直方图只是其中非常小的一部分,更多的请参看官方文档:
http://matplotlib.org/api/pyplot_summary.html
python数字图像处理(4):图像数据类型及颜色空间转换
一、图像数据类型及转换
在skimage中,一张图片就是一个简单的numpy数组,数组的数据类型有很多种,相互之间也可以转换。这些数据类型及取值范围如下表所示:
Data type | Range |
---|---|
uint8 | 0 to 255 |
uint16 | 0 to 65535 |
uint32 | 0 to 232 |
float | -1 to 1 or 0 to 1 |
int8 | -128 to 127 |
int16 | -32768 to 32767 |
int32 | -231 to 231 - 1 |
一张图片的像素值范围是[0,255], 因此默认类型是unit8, 可用如下代码查看数据类型:
from skimage import io,data img=data.chelsea() print(img.dtype.name)
在上面的表中,特别注意的是float类型,它的范围是[-1,1]或[0,1]之间。一张彩色图片转换为灰度图后,它的类型就由unit8变成了float
1、unit8转float
from skimage import data,img_as_float img=data.chelsea() print(img.dtype.name) dst=img_as_float(img) print(dst.dtype.name)
输出:
uint8
float64
2、float转uint8
from skimage import img_as_ubyte import numpy as np img = np.array([0, 0.5, 1], dtype=float) print(img.dtype.name) dst=img_as_ubyte(img) print(dst.dtype.name)
输出:
float64
uint8
float转为unit8,有可能会造成数据的损失,因此会有警告提醒。
除了这两种最常用的转换以外,其实有一些其它的类型转换,如下表:
Function name | Description |
---|---|
img_as_float | Convert to 64-bit floating point. |
img_as_ubyte | Convert to 8-bit uint. |
img_as_uint | Convert to 16-bit uint. |
img_as_int | Convert to 16-bit int. |
二、颜色空间及其转换
如前所述,除了直接转换可以改变数据类型外,还可以通过图像的颜色空间转换来改变数据类型。
常用的颜色空间有灰度空间、rgb空间、hsv空间和cmyk空间。颜色空间转换以后,图片类型都变成了float型。
所有的颜色空间转换函数,都放在skimage的color模块内。
例:rgb转灰度图
from skimage import io,data,color img=data.lena() gray=color.rgb2gray(img) io.imshow(gray)
其它的转换,用法都是一样的,列举常用的如下:
skimage.color.rgb2grey(rgb)
skimage.color.rgb2hsv(rgb)
skimage.color.rgb2lab(rgb)
skimage.color.gray2rgb(image)
skimage.color.hsv2rgb(hsv)
skimage.color.lab2rgb(lab)
实际上,上面的所有转换函数,都可以用一个函数来代替
skimage.color.convert_colorspace(arr, fromspace, tospace)
表示将arr从fromspace颜色空间转换到tospace颜色空间。
例:rgb转hsv
from skimage import io,data,color img=data.lena() hsv=color.convert_colorspace(img,'RGB','HSV') io.imshow(hsv)
在color模块的颜色空间转换函数中,还有一个比较有用的函数是
skimage.color.label2rgb(arr), 可以根据标签值对图片进行着色。以后的图片分类后着色就可以用这个函数。
例:将lena图片分成三类,然后用默认颜色对三类进行着色
from skimage import io,data,color import numpy as np img=data.lena() gray=color.rgb2gray(img) rows,cols=gray.shape labels=np.zeros([rows,cols]) for i in range(rows): for j in range(cols): if(gray[i,j]<0.4): labels[i,j]=0 elif(gray[i,j]<0.75): labels[i,j]=1 else: labels[i,j]=2 dst=color.label2rgb(labels) io.imshow(dst)
python数字图像处理(5):图像的绘制
实际上前面我们就已经用到了图像的绘制,如:
io.imshow(img)
这一行代码的实质是利用matplotlib包对图片进行绘制,绘制成功后,返回一个matplotlib类型的数据。因此,我们也可以这样写:
import matplotlib.pyplot as plt plt.imshow(img)
imshow()函数格式为:
matplotlib.pyplot.
imshow
(X, cmap=None)
X: 要绘制的图像或数组。
cmap: 颜色图谱(colormap), 默认绘制为RGB(A)颜色空间。
其它可选的颜色图谱如下列表:
用的比较多的有gray,jet等,如:
plt.imshow(image,plt.cm.gray)
plt.imshow(img,cmap=plt.cm.jet)
在窗口上绘制完图片后,返回一个AxesImage对象。要在窗口上显示这个对象,我们可以调用show()函数来进行显示,但进行练习的时候(ipython环境中),一般我们可以省略show()函数,也能自动显示出来。
skimage = = (type(dst)) io.show()
显示为:
可以看到,类型是'matplotlib.image.AxesImage'。显示一张图片,我们通常更愿意这样写:
import matplotlib.pyplot as plt from skimage import io,data img=data.astronaut() plt.imshow(img) plt.show()
matplotlib是一个专业绘图的库,相当于matlab中的plot,可以设置多个figure窗口,设置figure的标题,隐藏坐标尺,甚至可以使用subplot在一个figure中显示多张图片。一般我们可以这样导入matplotlib库:
import matplotlib.pyplot as plt
也就是说,我们绘图实际上用的是matplotlib包的pyplot模块。
一、用figure函数和subplot函数分别创建主窗口与子图
例:分开并同时显示宇航员图片的三个通道
from skimage import data import matplotlib.pyplot as plt img=data.astronaut() plt.figure(num='astronaut',figsize=(8,8)) #创建一个名为astronaut的窗口,并设置大小 plt.subplot(2,2,1) #将窗口分为两行两列四个子图,则可显示四幅图片 plt.title('origin image') #第一幅图片标题 plt.imshow(img) #绘制第一幅图片 plt.subplot(2,2,2) #第二个子图 plt.title('R channel') #第二幅图片标题 plt.imshow(img[:,:,0],plt.cm.gray) #绘制第二幅图片,且为灰度图 plt.axis('off') #不显示坐标尺寸 plt.subplot(2,2,3) #第三个子图 plt.title('G channel') #第三幅图片标题 plt.imshow(img[:,:,1],plt.cm.gray) #绘制第三幅图片,且为灰度图 plt.axis('off') #不显示坐标尺寸 plt.subplot(2,2,4) #第四个子图 plt.title('B channel') #第四幅图片标题 plt.imshow(img[:,:,2],plt.cm.gray) #绘制第四幅图片,且为灰度图 plt.axis('off') #不显示坐标尺寸 plt.show() #显示窗口
在图片绘制过程中,我们用matplotlib.pyplot模块下的figure()函数来创建显示窗口,该函数的格式为:
matplotlib.pyplot.
figure
(num=None, figsize=None, dpi=None, facecolor=None, edgecolor=None)
所有参数都是可选的,都有默认值,因此调用该函数时可以不带任何参数,其中:
num: 整型或字符型都可以。如果设置为整型,则该整型数字表示窗口的序号。如果设置为字符型,则该字符串表示窗口的名称。用该参数来命名窗口,如果两个窗口序号或名相同,则后一个窗口会覆盖前一个窗口。
figsize: 设置窗口大小。是一个tuple型的整数,如figsize=(8,8)
dpi: 整形数字,表示窗口的分辨率。
facecolor: 窗口的背景颜色。
edgecolor: 窗口的边框颜色。
用figure()函数创建的窗口,只能显示一幅图片,如果想要显示多幅图片,则需要将这个窗口再划分为几个子图,在每个子图中显示不同的图片。我们可以使用subplot()函数来划分子图,函数格式为:
matplotlib.pyplot.subplot(nrows, ncols, plot_number)
nrows: 子图的行数。
ncols: 子图的列数。
plot_number: 当前子图的编号。
如:
plt.subplot(2,2,1)
则表示将figure窗口划分成了2行2列共4个子图,当前为第1个子图。我们有时也可以用这种写法:
plt.subplot(221)
两种写法效果是一样的。每个子图的标题可用title()函数来设置,是否使用坐标尺可用axis()函数来设置,如:
plt.subplot(221) plt.title("first subwindow") plt.axis('off')
二、用subplots来创建显示窗口与划分子图
除了上面那种方法创建显示窗口和划分子图,还有另外一种编写方法也可以,如下例:
import matplotlib.pyplot as plt from skimage import data,color img = data.immunohistochemistry() hsv = color.rgb2hsv(img) fig, axes = plt.subplots(2, 2, figsize=(7, 6)) ax0, ax1, ax2, ax3 = axes.ravel() ax0.imshow(img) ax0.set_title("Original image") ax1.imshow(hsv[:, :, 0], cmap=plt.cm.gray) ax1.set_title("H") ax2.imshow(hsv[:, :, 1], cmap=plt.cm.gray) ax2.set_title("S") ax3.imshow(hsv[:, :, 2], cmap=plt.cm.gray) ax3.set_title("V") for ax in axes.ravel(): ax.axis('off') fig.tight_layout() #自动调整subplot间的参数
直接用subplots()函数来创建并划分窗口。注意,比前面的subplot()函数多了一个s,该函数格式为:
matplotlib.pyplot.
subplots
(nrows=1, ncols=1)
nrows: 所有子图行数,默认为1。
ncols: 所有子图列数,默认为1。
返回一个窗口figure, 和一个tuple型的ax对象,该对象包含所有的子图,可结合ravel()函数列出所有子图,如:
fig, axes = plt.subplots(2, 2, figsize=(7, 6)) ax0, ax1, ax2, ax3 = axes.ravel()
创建了2行2列4个子图,分别取名为ax0,ax1,ax2和ax3, 每个子图的标题用set_title()函数来设置,如:
ax0.imshow(img) ax0.set_title("Original image")
如果有多个子图,我们还可以使用tight_layout()函数来调整显示的布局,该函数格式为:
matplotlib.pyplot.
tight_layout
(pad=1.08, h_pad=None, w_pad=None, rect=None)
所有的参数都是可选的,调用该函数时可省略所有的参数。
pad: 主窗口边缘和子图边缘间的间距,默认为1.08
h_pad, w_pad: 子图边缘之间的间距,默认为 pad_inches
rect: 一个矩形区域,如果设置这个值,则将所有的子图调整到这个矩形区域内。
一般调用为:
plt.tight_layout() #自动调整subplot间的参数
三、其它方法绘图并显示
除了使用matplotlib库来绘制图片,skimage还有另一个子模块viewer,也提供一个函数来显示图片。不同的是,它利用Qt工具来创建一块画布,从而在画布上绘制图像。
例:
from skimage import data from skimage.viewer import ImageViewer img = data.coins() viewer = ImageViewer(img) viewer.show()
最后总结一下,绘制和显示图片常用到的函数有:
函数名 | 功能 | 调用格式 |
figure | 创建一个显示窗口 | plt.figure(num=1,figsize=(8,8) |
imshow | 绘制图片 | plt.imshow(image) |
show | 显示窗口 | plt.show() |
subplot | 划分子图 | plt.subplot(2,2,1) |
title | 设置子图标题(与subplot结合使用) | plt.title('origin image') |
axis | 是否显示坐标尺 | plt.axis('off') |
subplots | 创建带有多个子图的窗口 | fig,axes=plt.subplots(2,2,figsize=(8,8)) |
ravel | 为每个子图设置变量 | ax0,ax1,ax2,ax3=axes.ravel() |
set_title | 设置子图标题(与axes结合使用) | ax0.set_title('first window') |
tight_layout | 自动调整子图显示布局 | plt.tight_layout() |
python数字图像处理(6):图像的批量处理
有些时候,我们不仅要对一张图片进行处理,可能还会对一批图片处理。这时候,我们可以通过循环来执行处理,也可以调用程序自带的图片集合来处理。
图片集合函数为:
skimage.io.
ImageCollection
(load_pattern,load_func=None)
这个函数是放在io模块内的,带两个参数,第一个参数load_pattern, 表示图片组的路径,可以是一个str字符串。第二个参数load_func是一个回调函数,我们对图片进行批量处理就可以通过这个回调函数实现。回调函数默认为imread(),即默认这个函数是批量读取图片。
先看一个例子:
import skimage.io as io from skimage import data_dir str=data_dir + '/*.png' coll = io.ImageCollection(str) print(len(coll))
显示结果为25, 说明系统自带了25张png的示例图片,这些图片都读取了出来,放在图片集合coll里。如果我们想显示其中一张图片,则可以在后加上一行代码:
io.imshow(coll[10])
显示为:
如果一个文件夹里,我们既存放了一些jpg格式的图片,又存放了一些png格式的图片,现在想把它们全部读取出来,该怎么做呢?
import skimage.io as io from skimage import data_dir str='d:/pic/*.jpg:d:/pic/*.png' coll = io.ImageCollection(str) print(len(coll))
注意这个地方'd:/pic/*.jpg:d:/pic/*.png' ,是两个字符串合在一起的,第一个是'd:/pic/*.jpg', 第二个是'd:/pic/*.png' ,合在一起后,中间用冒号来隔开,这样就可以把d:/pic/文件夹下的jpg和png格式的图片都读取出来。如果还想读取存放在其它地方的图片,也可以一并加进去,只是中间同样用冒号来隔开。
io.ImageCollection()这个函数省略第二个参数,就是批量读取。如果我们不是想批量读取,而是其它批量操作,如批量转换为灰度图,那又该怎么做呢?
那就需要先定义一个函数,然后将这个函数作为第二个参数,如:
from skimage import data_dir,io,color def convert_gray(f): rgb=io.imread(f) return color.rgb2gray(rgb) str=data_dir+'/*.png' coll = io.ImageCollection(str,load_func=convert_gray) io.imshow(coll[10])
这种批量操作对视频处理是极其有用的,因为视频就是一系列的图片组合
from skimage import data_dir,io,color class AVILoader: video_file = 'myvideo.avi' def __call__(self, frame): return video_read(self.video_file, frame) avi_load = AVILoader() frames = range(0, 1000, 10) # 0, 10, 20, ... ic =io.ImageCollection(frames, load_func=avi_load)
这段代码的意思,就是将myvideo.avi这个视频中每隔10帧的图片读取出来,放在图片集合中。
得到图片集合以后,我们还可以将这些图片连接起来,构成一个维度更高的数组,连接图片的函数为:
skimage.io.concatenate_images(ic)
带一个参数,就是以上的图片集合,如:
from skimage import data_dir,io,color coll = io.ImageCollection('d:/pic/*.jpg') mat=io.concatenate_images(coll)
使用concatenate_images(ic)函数的前提是读取的这些图片尺寸必须一致,否则会出错。我们看看图片连接前后的维度变化:
from skimage import data_dir,io,color coll = io.ImageCollection('d:/pic/*.jpg') print(len(coll)) #连接的图片数量 print(coll[0].shape) #连接前的图片尺寸,所有的都一样 mat=io.concatenate_images(coll) print(mat.shape) #连接后的数组尺寸
显示结果:
2
(870, 580, 3)
(2, 870, 580, 3)
可以看到,将2个3维数组,连接成了一个4维数组
如果我们对图片进行批量操作后,想把操作后的结果保存起来,也是可以办到的。
例:把系统自带的所有png示例图片,全部转换成256*256的jpg格式灰度图,保存在d:/data/文件夹下
改变图片的大小,我们可以使用tranform模块的resize()函数,后续会讲到这个模块。
from skimage import data_dir,io,transform,color import numpy as np def convert_gray(f): rgb=io.imread(f) #依次读取rgb图片 gray=color.rgb2gray(rgb) #将rgb图片转换成灰度图 dst=transform.resize(gray,(256,256)) #将灰度图片大小转换为256*256 return dst str=data_dir+'/*.png' coll = io.ImageCollection(str,load_func=convert_gray) for i in range(len(coll)): io.imsave('d:/data/'+np.str(i)+'.jpg',coll[i]) #循环保存图片
结果:
python数字图像处理(7):图像的形变与缩放
图像的形变与缩放,使用的是skimage的transform模块,函数比较多,功能齐全。
1、改变图片尺寸resize
函数格式为:
skimage.transform.resize(image, output_shape)
image: 需要改变尺寸的图片
output_shape: 新的图片尺寸
from skimage import transform,data import matplotlib.pyplot as plt img = data.camera() dst=transform.resize(img, (80, 60)) plt.figure('resize') plt.subplot(121) plt.title('before resize') plt.imshow(img,plt.cm.gray) plt.subplot(122) plt.title('before resize') plt.imshow(dst,plt.cm.gray) plt.show()
将camera图片由原来的512*512大小,变成了80*60大小。从下图中的坐标尺,我们能够看出来:
2、按比例缩放rescale
函数格式为:
skimage.transform.rescale(image, scale[, ...])
scale参数可以是单个float数,表示缩放的倍数,也可以是一个float型的tuple,如[0.2,0.5],表示将行列数分开进行缩放
from skimage import transform,data img = data.camera() print(img.shape) #图片原始大小 print(transform.rescale(img, 0.1).shape) #缩小为原来图片大小的0.1倍 print(transform.rescale(img, [0.5,0.25]).shape) #缩小为原来图片行数一半,列数四分之一 print(transform.rescale(img, 2).shape) #放大为原来图片大小的2倍
结果为:
(512, 512)
(51, 51)
(256, 128)
(1024, 1024)
3、旋转 rotate
skimage.transform.rotate(image, angle[, ...],resize=False)
angle参数是个float类型数,表示旋转的度数
resize用于控制在旋转时,是否改变大小 ,默认为False
from skimage import transform,data import matplotlib.pyplot as plt img = data.camera() print(img.shape) #图片原始大小 img1=transform.rotate(img, 60) #旋转90度,不改变大小 print(img1.shape) img2=transform.rotate(img, 30,resize=True) #旋转30度,同时改变大小 print(img2.shape) plt.figure('resize') plt.subplot(121) plt.title('rotate 60') plt.imshow(img1,plt.cm.gray) plt.subplot(122) plt.title('rotate 30') plt.imshow(img2,plt.cm.gray) plt.show()
显示结果:
4、图像金字塔
以多分辨率来解释图像的一种有效但概念简单的结构就是图像金字塔。图像金字塔最初用于机器视觉和图像压缩,一幅图像的金字塔是一系列以金字塔形状排列的分辨率逐步降低的图像集合。金字塔的底部是待处理图像的高分辨率表示,而顶部是低分辨率的近似。当向金字塔的上层移动时,尺寸和分辨率就降低。
在此,我们举一个高斯金字塔的应用实例,函数原型为:
skimage.transform.pyramid_gaussian(image, downscale=2)
downscale控制着金字塔的缩放比例
import numpy as np import matplotlib.pyplot as plt from skimage import data,transform image = data.astronaut() #载入宇航员图片 rows, cols, dim = image.shape #获取图片的行数,列数和通道数 pyramid = tuple(transform.pyramid_gaussian(image, downscale=2)) #产生高斯金字塔图像 #共生成了log(512)=9幅金字塔图像,加上原始图像共10幅,pyramid[0]-pyramid[1] composite_image = np.ones((rows, cols + cols / 2, 3), dtype=np.double) #生成背景 composite_image[:rows, :cols, :] = pyramid[0] #融合原始图像 i_row = 0 for p in pyramid[1:]: n_rows, n_cols = p.shape[:2] composite_image[i_row:i_row + n_rows, cols:cols + n_cols] = p #循环融合9幅金字塔图像 i_row += n_rows plt.imshow(composite_image) plt.show()
上右图,就是10张金字塔图像,下标为0的表示原始图像,后面每层的图像行和列变为上一层的一半,直至变为1
除了高斯金字塔外,还有其它的金字塔,如:
skimage.transform.pyramid_laplacian(image, downscale=2):