图像在scikit-images
中用Numpy矩阵表示。因此,可以使用标准的NumPy方法来实现许多常见的操作:
from skimage import data
camera = data.camera()
type(camera)
查看图像的形状和像素数量:
camera.shape
(512, 512)
camera.size
262144
查看图像像素值的统计信息:
camera.min(), camera.max()
(0, 255)
118.31400299072266
表示图像的Numpy数组可以是不同的整数或浮点数类型。查看图像数据类型及其含义获得详细信息和scikit-images
如何处理不同数据类型。
Numpy索引可用于查看像素值或修改它们:
camera[10, 20] # 获取第10行第20列的像素值
153
camera[3, 10] = 0 #将第3行第20列的像素值设为0
注意,在Numpy索引中,第一个维度(camera.shape[0]
)对应行,第二个维度(camera .shape[1]
)对应列,原点(camera[0,0]
)位于左上角。它匹配矩阵/线性代数表示法,但与笛卡尔坐标(x, y)相反。详细信息,参阅坐标约定。
除了单个像素外,还可以使用Numpy的切片功能访问/修改整个像素集的值:
camera[:10] = 0 #将头10行设为黑色0
掩码(布尔值掩码索引,可理解为PS中的蒙版):
mask = camera < 87
camera[mask] = 255 # 当掩码为真时设置该像素为白色255
花式索引(索引集索引):
import numpy as np
inds_r = np.arange(len(camera)) # 0到511的矩阵
inds_c = 4 * inds_r % len(camera) # 0到511,间距为4的矩阵
camera[inds_r, inds_c] = 0
当您需要选择一组像素执行操作时,掩码非常有用。掩码可以是与图像形状相同的布尔数组,或可向图像形状传递的形状。
例如,定义一个感兴趣的区域,一个圆:
nrows, ncols = camera.shape
row, col = np.ogrid[:nrows, :ncols] #快速产生二维行向量和列向量
cnt_row, cnt_col = nrows / 2, ncols / 2 #取半径
outer_disk_mask = ((row - cnt_row)**2 + (col - cnt_col)**2 > (nrows / 2)**2) # 蒙版为当前坐标位置大于半径范围
camera[outer_disk_mask] = 0 # 当掩码为真时设置该像素为黑色255
查看图像
from skimage import io
%matplotlib inline
io.imshow(camera)
lower_half = row > cnt_row
lower_half_disk = np.logical_and(lower_half, outer_disk_mask)
camera = data.camera()
camera[lower_half_disk] = 0
io.imshow(camera)
上述所有内容对彩色图像同样适用。彩色图像是再多一个维度的Numpy数组:
cat = data.chelsea()
io.imshow(cat)
type(cat)
numpy.ndarray
cat.shape
(300, 451, 3)
这表明变量cat
是一个300×451像素的图像,有三个通道(红、绿、蓝)。如前所述,我们可以获取并设置像素值:
cat[10, 20]
array([151, 129, 115], dtype=uint8)
cat[50, 60] = 0 #将第50行,第60列的像素设为黑色
cat[50, 61] = [0, 255, 0] # 将第50行,第60列的像素设为绿色[red, green, blue]
同样地,可以对2D多通道图像使用2D布尔蒙版:
cat = data.chelsea()
reddish = cat[:, :, 0] > 160 # 红色的值大于160(0red 1green 2blue)
cat[reddish] = [0, 255, 0] #设为绿色
io.imshow(cat)
因为scikit-image
使用Numpy数组表示图像,所以坐标约定必须匹配。二维灰度图(如上图camera)通过行、列,缩写为(row, col)
或(r, c)
进行索引,左上角像素的索引为(0,0)
。
在库的各个部分,你还将看到用rr
和cc
引用行和列坐标。我们将这个约定与(x, y)
区别开来,(x, y)
通常表示标准的笛卡尔坐标,其中x
是横坐标,y
是纵坐标,原点在左下角。例如,Matplotlib轴使用这种坐标。
对于多通道图像,最后一个维用于彩色通道,用channel
或ch
表示。
最后,对于立体3D图像,如视频、磁共振成像(MRI)扫描、共聚焦显微镜等,我们将第一个维度称为plane
,缩写为pln
或p
。
约定总结如下:
图片类型 | 约定 |
---|---|
二维灰度图 | (row, col) |
二维多通道(如RGB) | (row, col, ch) |
三维灰度 | (pln, row, col) |
三维多通道 | (pln, row, col, ch) |
scikit-image
中的许多函数可以直接对3D图像进行操作(以下代码执行时间略久):
im3d = np.random.rand(100, 1000, 1000) # 生成随机矩阵
from skimage import morphology
from scipy import ndimage as ndi
seeds = ndi.label(im3d < 0.1)[0] # 标记小于0.1的值
ws = morphology.watershed(im3d, seeds) # 分水岭算法
然而,多数情况下,第三个空间维度的分辨率低于其他两个维度。一些scikit-image
函数提供了一个间距关键字spacing
参数来帮助处理这类数据:
from skimage import segmentation
slics = segmentation.slic(im3d, spacing=[5, 1, 1], multichannel=False) #k-means聚类分割图像
其他情况,处理必须在plane
维度上完成。当第一个维度为plane
(与约定一致),可以使用以下语法:
from skimage import filters
edges = np.empty_like(im3d)
for pln, image in enumerate(im3d):
# 迭代第一个维度
edges[pln] = filters.sobel(image) #Sobel变换
尽管坐标轴的标记可能看起来很随意,但是它对操作的速度有很大的影响。这是因为现代处理器不会从内存中仅检索一项,而是检索整个相邻块(称为预取的操作)。因此,处理内存中相邻的元素比处理分散的元素要快,即使操作的数量相同:
def in_order_multiply(arr, scalar):
for plane in list(range(arr.shape[0])):
arr[plane, :, :] *= scalar
def out_of_order_multiply(arr, scalar):
for plane in list(range(arr.shape[2])):
arr[:, :, plane] *= scalar
import time
im3d = np.random.rand(100, 1024, 1024)
t0 = time.time(); x = in_order_multiply(im3d, 5); t1 = time.time()
print("%.2f seconds" % (t1 - t0))
0.08 seconds
s0 = time.time(); x = out_of_order_multiply(im3d, 5); s1 = time.time()
print("%.2f seconds" % (s1 - s0))
1.65 seconds
print("Speedup: %.1fx" % ((s1 - s0) / (t1 - t0)))
Speedup: 21.3x
当最后/最右边的维度变得更大时,加速效果更显著。在开发算法时考虑数据局部性是值得的。特别地,scikit-image
默认使用C-连续数组。当使用嵌套循环时,数组的最后/最右边的维度应该位于计算的最内层循环中。在上面的例子中,*=
numpy操作符遍历所有剩余的维度。
虽然scikit-image
目前还没有提供专门处理时变3D数据的函数,但它与Numpy数组的兼容性使我们能够很自然地处理形如(t, pln, row, col, ch)的5D数组:
# 伪代码
for timepoint in image5d:
# Each timepoint is a 3D multichannel image
do_something_with(timepoint)
对上表进行补充如下:
数据类型类型 | 约定 |
---|---|
二维灰度图 | (row, col) |
二维多通道(如RGB) | (row, col, ch) |
三维灰度 | (pln, row, col) |
三维多通道 | (pln, row, col, ch) |
二维彩色视频 | (t, row, col, ch) |
三维多通道视频 | (t, pln, row, col, ch) |