如何在Python中从3D图像中提取补丁?

6
我有一个3D图像,大小为:Deep x Weight x Height(例如:10x20x30,表示有10个图像,每个图像的大小为20x30)。
给定一个补丁大小为pd x pw x ph(如pd < Deep, pw<Weight, ph<Height),例如补丁大小为4x4x4。路径中心点的位置将是:pd/2 x pw/2 x ph/2。让我们称时间t和时间t+1之间中心点的距离为stride,例如stride=2
我想将原始3D图像提取成所给大小和步长的补丁。我该如何在Python中实现?谢谢。

.

enter image description here


你是否想要在大图像中跟踪一些细节,以(time,x,y)空间的形式?你是否想要为已知值(x0,y0,t0)生成微小空间([t0-dt, t0+dt] , [x0-dx, x0+dx],[y0-dy, y0+dy])? - B. M.
实际上,我不关心时间。我只想从给定的图像和补丁大小中提取图像补丁。该补丁将从左到右进行扫描,并深入扫描。该过程类似于卷积,但我提取补丁而不是计算值。 - user3051460
2个回答

8
使用 np.lib.stride_tricks.as_strided。这个解决方案不需要步幅来划分输入堆栈的相应维度。它甚至允许重叠的补丁(在这种情况下,不要写入结果,或者进行复制)。因此,它比其他方法更灵活。
import numpy as np
from numpy.lib import stride_tricks

def cutup(data, blck, strd):
    sh = np.array(data.shape)
    blck = np.asanyarray(blck)
    strd = np.asanyarray(strd)
    nbl = (sh - blck) // strd + 1
    strides = np.r_[data.strides * strd, data.strides]
    dims = np.r_[nbl, blck]
    data6 = stride_tricks.as_strided(data, strides=strides, shape=dims)
    return data6#.reshape(-1, *blck)

#demo
x = np.zeros((5, 6, 12), int)
y = cutup(x, (2, 2, 3), (3, 3, 5))

y[...] = 1
print(x[..., 0], '\n')
print(x[:, 0, :], '\n')
print(x[0, ...], '\n')

输出:

[[1 1 0 1 1 0]
 [1 1 0 1 1 0]
 [0 0 0 0 0 0]
 [1 1 0 1 1 0]
 [1 1 0 1 1 0]] 

[[1 1 1 0 0 1 1 1 0 0 0 0]
 [1 1 1 0 0 1 1 1 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0]
 [1 1 1 0 0 1 1 1 0 0 0 0]
 [1 1 1 0 0 1 1 1 0 0 0 0]] 

[[1 1 1 0 0 1 1 1 0 0 0 0]
 [1 1 1 0 0 1 1 1 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0]
 [1 1 1 0 0 1 1 1 0 0 0 0]
 [1 1 1 0 0 1 1 1 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0]] 

解释。Numpy数组按照步幅(stride)组织,每个维度都有一个步幅,数据点[x,y,z]在内存中的地址为base + stridex * x + stridey * y + stridez * z。
stride_tricks.as_strided工厂允许直接操作新数组的步幅和形状,并与给定数组共享其内存。只有在您知道自己在做什么时才尝试使用此选项,因为不执行任何检查,这意味着您可以通过寻址越界内存来损坏自己的代码。
该代码使用此函数将三个现有维度分成两个新维度,一个用于相应的块内坐标(这将具有原始维度的相同步幅,因为块中相邻点对应于整个堆栈中的相邻点),另一个维度用于沿此轴的块索引;这将具有步幅=原始步幅x块步幅。
代码所做的就是计算正确的步幅和维度(=块维度和沿三个轴的块计数)。
由于数据与原始数组共享,当我们将所有6d数组的点设置为1时,它们也在原始数组中设置,从而在演示中暴露了块结构。请注意,函数最后一行中注释掉的reshape会打破此链接,因为它强制进行复制。

谢谢你的解决方案。你可以解释一下它的实现思路吗? - user3051460
@user3051460 我已经尝试过(请参见帖子);同时我还简化了代码。 - Paul Panzer

2

skimage模块提供了一个集成的解决方案,其中包括view_as_blocks。源代码在线上。

请注意选择Deep,Weight,Heightpd, pw, ph的倍数,因为as_strided不会检查边界。


使用as_strided的整个目的是为了适应不将输入维度划分为块维度的情况。只有基于reshape的解决方案才有此限制。 - Paul Panzer
嗯,我不太确定 OP 的目标。看起来是在 (t,x,y) 空间中进行跟踪任务。在这种情况下,步幅不需要重新定义... 我会问他的。 - B. M.
@B.M. 这是一个非常好的库。但是如果两个补丁重叠会发生什么呢?这意味着步幅小于Weight/2或Height/2。 - user3051460
也许 view_as_windows 可以在这种情况下帮助你? - B. M.
@B.M:你说得对。as_strided不会检查边界。我正在尝试使用view_as_windows。你认为view_as_windows支持随机选择补丁吗? - user3051460

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接