基于python脚本语言开发的数字图片处理包,比如PIL,Pillow, opencv, scikit-image等。PIL和Pillow只提供最基础的数字图像处理,功能有限;opencv实际上是一个c++库,只是提供了python接口,更新速度非常慢。scikit-image是基于scipy的一款图像处理包,它将图片作为numpy数组进行处理,正好与matlab一样。这里选择Skimage模块进行数字图像处理。
本文主要介绍了图像的读取,显示,保存,色彩转换,批量处理,缩放,对比度调,直方图均衡化等操作。
skimage包的全称是scikit-image SciKit (toolkit for SciPy) ,它对scipy.ndimage进行了扩展,提供了更多的图片处理功能。它是由python语言编写的,由scipy 社区开发和维护。skimage包由许多的子模块组成,各个子模块提供不同的功能。主要子模块列表如下:
子模块名称 | 主要实现功能 |
---|---|
io | 读取、保存和显示图片或视频 |
data | 提供一些测试图片和样本数据 |
color | 颜色空间变换 |
filters | 图像增强、边缘检测、排序滤波器、自动阈值等 |
draw | 操作于numpy数组上的基本图形绘制,包括线条、矩形、圆和文本等 |
transform | 几何变换或其它变换,如旋转、拉伸和拉东变换等 |
morphology | 形态学操作,如开闭运算、骨架提取等 |
exposure | 图片强度调整,如亮度调整、直方图均衡等 |
feature | 特征检测与提取等 |
measure | 图像属性的测量,如相似性或等高线等 |
segmentation | 图像分割 |
restoration | 图像恢复 |
util | 通用函数 |
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)
图像的读取可以使用imread
函数,返回的是浮点类型图像数组,代码如下
#常见的显示模块
import matplotlib.pyplot as plt
#使用skimage的io子模块中的imread,所以需要导入io模块
from skimage import io
# 图片文件的路径
filename = 'XXXXX'
# 使用imread读取图像
img = io.imread(filename)
图像的显示可以使用plt
子模块中的imshow
函数,代码如下:
#设置图像的大小
plt.figure(figsize = (10,10))
# 使用灰度方式显示图片
plt.imshow(image,'gray')
也可以使用io
子模块下的imshow
函数,代码如下:
from skimage import io,data
img = data.chelsea()
io.imshow(img)
图像的保存可以使用io
子模块下的imsave(fname,arr)
函数来实现,第一个参数表示保存的路径和名称,第二个参数表示需要保存的数组变量
from skimage import io,data
img = data.chelsea()
io.imshow(img)
io.imsave('cat.jpg',img)
可以获得图像中的类型,尺寸,高度,宽度,通道数,总像素个数,最大像素值,最小像素值,像素平均值等信息,代码如下:
from skimage import io, data
img = data.chelsea()
io.imshow(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()) #像素平均值
print(img[0][0]) #图像的像素值
使用了color模块的rgb2gray()函数,将色彩三通道图片转换成灰度图,转换结果为float64类型的数组,范围为[0,1]之间,将彩色三通道图片转换成灰度图,最后变成uint8,float64转换成uint8是有信息损失的。代码如下;
from skimage import io,color,img_as_ubyte,data
filename = 'XXXXX'
#读取图像,结果为M*N*3的矩阵,彩色形式
img = io.imread(filename)
# 彩色形式转成灰色形式,结果为M*N的矩阵,元素类型为float64,[0,1]
img_gray = color.rgb2grey(img)
# 将浮点类型转换成uint8型,[0,155],转换后有信息损失。
img_uint = img_as_ubyte(img)
在skimage中,一张图片就是一个简单的numpy数组,数组的数据类型有很多中,相互之间也可以转换。类型及取值范围如下:
数据类型 | 范围 | 数据类型 | 范围 | 数据类型 | 范围 |
---|---|---|---|---|---|
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],所以默认使用uint8,可以用如下代码查看数据类型:
from skimage import data
img=data.chelsea()
print(img.dtype.name)
常见的数据类型转换函数:
函数名称 | 描述 |
---|---|
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 |
类型转换还可以使用color模块下的convert_colorspace函数,代码如下:
from skimage import io,data,color
img=data.lena()
# 从RGB颜色空间转到gray颜色空间
img_gray=color.convert_colorspace(img,'RGB','Gray')
io.imshow(img_gray)
另外,label2rgb()函数可以根据标签纸对图片进行着色。
如果需要对一批图片进行处理,可以调用程序自带的图片集合ImageCollection
来处理。语法为:
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)
如果在一个文件夹里,既有jpg格式的图片,又有png的图片,想把它们都读出来,可用下面的代码:
import skimage.io as io
from skimage import data_dir
# 图片之间用冒号隔开
str='d:/pic1/*.jpg:d:/pic2/*.png'
coll = io.ImageCollection(str)
如果想对图片进行批量操作,比如转为灰度图,可以用下面的代码:
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])
图像的形变与缩放,可以使用skimage
的transform
模块,函数比较多,功能齐全。
改变图片尺寸可以使用resize
函数,语法为:skimage.transform.resize(image, output_shape)
其中,image
是需要改变尺寸的图片,output_shape
是新的图片的尺寸,代码如下:
from skimage import transform,data
img = data.camera()
dst=transform.resize(img, (80, 60))
缩放图片可以使用rescale
函数,语法为:skimage.transform.rescale(image, scale[, ...])
scale
参数可以是单个float
函数,表示缩放的倍数,也可以是一个float
型的tuple
,例子如下:
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)
图像旋转可以使用roate
函数,语法为:skimage.transform.rotate(image, angle[, ...],resize=False)
angle
参数是个float
类型数,表示旋转的度数resize
用于控制在旋转时,是否改变大小 ,默认为False代码如下:
from skimage import transform,data
img = data.camera()
img1=transform.rotate(img, 60) #旋转90度,不改变大小
img2=transform.rotate(img, 30,resize=True) #旋转30度,同时改变大小
图像亮度与对比度的调整,是放在skimage包里的exposure模块里面。
原理: O=Iγ O = I γ
对原图像的像素,进行幂运算,得到新的像素值,公式中的g
就是gamma
值。如果gamma
大于1,新图像比原图像暗,如果gamma
<1,新图像比原图像亮。语法为:skimage.exposure.adjust_gamma(image, gamma=1)
gamma
参数默认为1,原图像不发生变化。例子如下:
from skimage import data, exposure, img_as_float
image = img_as_float(data.moon())
gam1= exposure.adjust_gamma(image, 2) #调暗
gam2= exposure.adjust_gamma(image, 0.5) #调亮
这个刚好和gamma相反,原理 O=gain∗log(1+I) O = g a i n ∗ l o g ( 1 + I ) ,例子如下:
from skimage import data, exposure, img_as_float
image = img_as_float(data.moon())
gam1= exposure.adjust_log(image) #对数调整
函数:is_low_contrast(img)
,返回一个bool
型值。
from skimage import data, exposure
image =data.moon()
result=exposure.is_low_contrast(image)
print(result)
输出为False
函数为rescale_intensity
语法为skimage.exposure.rescale_intensity(image, in_range='image', out_range='dtype')
in_range
表示输入图片的强度范围,默认为’image’, 表示用图像的最大/最小像素值作为范围
out_range
表示输出图片的强度范围,默认为’dype’, 表示用图像的类型的最大/最小值作为范围
默认情况下,输入图片的[min,max]范围被拉伸到[dtype.min, dtype.max],如果dtype=uint8, 那么dtype.min=0, dtype.max=255
例子为:
import numpy as np
from skimage import exposure
image = np.array([51, 102, 153], dtype=np.uint8)
mat=exposure.rescale_intensity(image)
print(mat)
在图像处理中,直方图是非常重要的,也是非常有用的一个处理要素。在skimage库中,对直方图的处理,是放在exposure这个模块中。
语法为:skimage.exposure.histogram(image, nbins=256)
在numpy包中,也提供了一个计算直方图的函数histogram(),两者大同小义。
返回一个tuple(hist, bins_center), 前一个数组是直方图的统计量,后一个数组是每个bin的中间值
import numpy as np
from skimage import exposure,data
image =data.camera()*1.0
hist1=np.histogram(image, bins=2) #用numpy包计算直方图hist2=exposure.histogram(image, nbins=2) #用skimage计算直方图
print(hist1)
print(hist2)
如果一副图像的像素占有很多的灰度级而且分布均匀,那么这样的图像往往有高对比度和多变的灰度色调。直方图均衡化就是一种能仅靠输入图像直方图信息自动达到这种效果的变换函数。它的基本思想是对图像中像素个数多的灰度级进行展宽,而对图像中像素个数少的灰度进行压缩,从而扩展取值的动态范围,提高了对比度和灰度色调的变化,使图像更加清晰。例子如下:
from skimage import data,exposure
import matplotlib.pyplot as plt
img=data.moon()
plt.figure("hist",figsize=(8,8))
arr=img.flatten()
plt.subplot(221)
plt.imshow(img,plt.cm.gray) #原始图像
plt.subplot(222)
plt.hist(arr, bins=256, normed=1,edgecolor='None',facecolor='red') #原始图像直方图
img1=exposure.equalize_hist(img) #进行直方图均衡化
arr1=img1.flatten() #返回数组折叠成一维的副本
plt.subplot(223)
plt.imshow(img1,plt.cm.gray) #均衡化图像
plt.subplot(224)
plt.hist(arr1, bins=256, normed=1,edgecolor='None',facecolor='red') #均衡化直方图
plt.show()