如何自动处理尺寸不匹配时Numpy数组的图像复制边界问题?
问题:Numpy中如何自动处理小图像粘贴到大图像的边界情况
我尝试用常规Numpy语法将小图像数组粘贴到大图像数组中:
import numpy as np import matplotlib.pyplot as plt large_im = np.linspace(0,1,20)[:,None]*np.ones([1,20]) small_im = np.linspace(1,0,10)[None,:]*np.ones([10,1]) a0,b0 = 5,5 large_im[a0:a0+small_im.shape[0],b0:b0+small_im.shape[1]] = small_im plt.figure() plt.imshow(large_im)
(典型情况:小图像完整粘贴在大图像中央,显示正常渐变效果)
多数情况下该方法可行,但当粘贴位置导致小图像部分超出大图像范围时(如下列示例):
a0,b0 = 15,15 large_im[a0:a0+small_im.shape[0],b0:b0+small_im.shape[1]] = small_im
或:
a0,b0 = -5,-5 large_im[a0:a0+small_im.shape[0],b0:b0+small_im.shape[1]] = small_im
(边界情况:小图像部分超出大图像范围,此时直接赋值会因索引尺寸不匹配抛出ValueError)
目前我需手动编写大量代码检查并裁剪尺寸以适配,请问是否存在可自动完成此操作的Numpy函数?
解决方案
Numpy本身没有专门的“自动粘贴并处理边界”的函数,但可以通过计算有效重叠区域的方式,用几行代码实现自动适配,无需大量手动判断:
方法1:计算有效切片范围(推荐)
核心思路是分别计算大数组和小数组在两个轴上的有效索引范围,只对重叠区域进行赋值:
import numpy as np def paste_into_large(large_arr, small_arr, pos): a0, b0 = pos # 获取数组尺寸 large_h, large_w = large_arr.shape small_h, small_w = small_arr.shape # 计算大数组上的有效切片范围(限制在0到数组边界内) large_a_start = max(a0, 0) large_a_end = min(a0 + small_h, large_h) large_b_start = max(b0, 0) large_b_end = min(b0 + small_w, large_w) # 计算小数组上对应的有效切片范围 small_a_start = max(-a0, 0) small_a_end = small_h - max(a0 + small_h - large_h, 0) small_b_start = max(-b0, 0) small_b_end = small_w - max(b0 + small_w - large_w, 0) # 仅当存在重叠区域时赋值 if large_a_start < large_a_end and large_b_start < large_b_end: large_arr[large_a_start:large_a_end, large_b_start:large_b_end] = small_arr[small_a_start:small_a_end, small_b_start:small_b_end] return large_arr # 测试示例 large_im = np.linspace(0,1,20)[:,None]*np.ones([1,20]) small_im = np.linspace(1,0,10)[None,:]*np.ones([10,1]) # 测试边界位置 paste_into_large(large_im, small_im, (15,15)) paste_into_large(large_im, small_im, (-5,-5))
方法2:借助numpy.pad临时扩展大数组
如果希望超出部分被截断,也可以先将大数组用边缘值(或其他填充方式)扩展,粘贴后再裁剪回原尺寸,适合需要临时扩展场景:
def paste_with_pad(large_arr, small_arr, pos): a0, b0 = pos large_h, large_w = large_arr.shape small_h, small_w = small_arr.shape # 计算需要填充的上下左右尺寸 pad_top = max(-a0, 0) pad_bottom = max(a0 + small_h - large_h, 0) pad_left = max(-b0, 0) pad_right = max(b0 + small_w - large_w, 0) # 填充大数组(mode可选:'edge'、'constant'、'reflect'等) padded_large = np.pad(large_arr, ((pad_top, pad_bottom), (pad_left, pad_right)), mode='edge') # 计算填充后数组的粘贴位置 paste_a = a0 + pad_top paste_b = b0 + pad_left # 执行赋值 padded_large[paste_a:paste_a+small_h, paste_b:paste_b+small_w] = small_arr # 裁剪回原大数组尺寸 large_arr[:] = padded_large[pad_top:pad_top+large_h, pad_left:pad_left+large_w] return large_arr
补充:使用Scipy现成工具
如果可以引入Scipy库,scipy.ndimage模块中的相关函数(如结合shift与赋值)也能简化操作,但如果仅依赖Numpy,方法1是最直接高效的方案。
内容的提问来源于stack exchange,提问作者jadsq
相关产品推荐
相关产品推荐

