有办法吗?是的。复杂吗?不是特别。
import numpy as np
def fill_crop(img, pos, crop):
'''
Fills `crop` with values from `img` at `pos`,
while accounting for the crop being off the edge of `img`.
*Note:* negative values in `pos` are interpreted as-is, not as "from the end".
'''
img_shape, pos, crop_shape = np.array(img.shape), np.array(pos), np.array(crop.shape),
end = pos+crop_shape
# Calculate crop slice positions
crop_low = np.clip(0 - pos, a_min=0, a_max=crop_shape)
crop_high = crop_shape - np.clip(end-img_shape, a_min=0, a_max=crop_shape)
crop_slices = (slice(low, high) for low, high in zip(crop_low, crop_high))
# Calculate img slice positions
pos = np.clip(pos, a_min=0, a_max=img_shape)
end = np.clip(end, a_min=0, a_max=img_shape)
img_slices = (slice(low, high) for low, high in zip(pos, end))
crop[tuple(crop_slices)] = img[tuple(img_slices)]
为什么要使用这个?
如果内存是一个问题,那么将图像复制到填充版本可能并不好。这也适用于更高维度的输入,并且很清楚如何在需要时返回索引/切片。
为什么crop是个参数?
为了表示填充值,我们可以使用np.zeros/np.full提前为裁剪创建内存,然后填写我们需要的部分。困难不在于从哪里复制,而是从哪里粘贴到作物内部。
理论
让我们看一个一维案例:
如果你稍微考虑一下,你会发现:
-
crop_low 远高于0,而pos 低于0,但如果pos >= 0,则crop_low == 0
-
crop_high 远低于crop.shape 就像end 高于img.shape,但如果end <= img.shape,则crop_high == crop.shape
如果我们把它放到普通的python代码中,它会是这样的:
crop_low = max(-pos, 0)
crop_high = crop.shape - max(end-img.shape, 0)
上面的其余代码仅用于索引。
测试
# Examples in 1 dimension
img = np.arange(10, 20)
# Normal
pos = np.array([1,])
crop = np.full([5,], 0)
fill_crop(img, pos, crop)
assert crop.tolist() == [11, 12, 13, 14, 15]
# Off end
pos = np.array([8,])
crop = np.full([5,], 0)
fill_crop(img, pos, crop)
assert crop.tolist() == [18, 19, 0, 0, 0]
# Off start
pos = np.array([-2,])
crop = np.full([5,], 0)
fill_crop(img, pos, crop)
assert crop.tolist() == [ 0, 0, 10, 11, 12]
# Example in 2 dimensions (y,x)
img = np.arange(10, 10+10*10)\
.reshape([10, 10])
# Off Top right
pos = np.array([-2, 8])
crop = np.full([5, 5], 0)
fill_crop(img, pos, crop)
assert np.all(crop[:2] == 0) # That is, the top two rows are 0s
assert np.all(crop[:, 3:] == 0) # That is, the right 3 rows are 0s
assert np.all(crop[2:, :2] == img[:3, 8:])
# That is, the rows 2-5 and columns 0-1 in the crop
# are the same as the top 3 rows and columns 8 and 9 (the last two columns)
我们有它。对原始问题的过度设计的答案。