如何从numpy二维数组的嵌套视图中提取对应原数组的坐标范围?
解答
首先明确两个前提结论:
- 你示例中的
median_filter返回的是全新数组,并非原数组A的视图,二者没有内存继承关系,所以无法直接从subview反推它在A中的坐标,这个是scipy滤波接口的特性导致的,和numpy本身的视图机制无关。 - 如果你是处理纯切片生成、步长全为1的numpy视图,完全可以通过numpy内置属性计算出它在原始数组中的坐标,不需要额外传递矩形参数。
实现原理
numpy所有数组都内置了几个底层属性,可直接访问:
.base:如果当前数组是视图,该属性指向生成该视图的父数组;如果是原始数组,该属性为None.ctypes.data:当前数组首元素的内存地址.itemsize:单个数组元素占用的字节数
通过视图和原始数组的内存地址差,就能算出偏移量,再结合数组形状就能换算出切片坐标。
示例代码
import numpy as np def get_rect(view, base_arr): # 先校验当前视图是否属于base_arr的后代视图 cur_base = view while cur_base.base is not None: cur_base = cur_base.base if cur_base is not base_arr: raise ValueError("输入视图并非指定原始数组的后代视图") # 计算元素级偏移量 byte_offset = view.ctypes.data - base_arr.ctypes.data elem_offset = byte_offset // base_arr.itemsize # 二维数组步长为1的场景坐标换算,可扩展到更高维度 h, w = base_arr.shape start_y = elem_offset // w start_x = elem_offset % w end_y = start_y + view.shape[0] end_x = start_x + view.shape[1] return (slice(start_y, end_y), slice(start_x, end_x))
测试用例
A = np.zeros((100,100)) # 直接从A切片生成的都是视图 view = A[30:40, 30:40] subview = view[0:5, 0:5] coords = get_rect(subview, A) # 输出坐标为 (slice(30, 35, None), slice(30, 35, None)) print(np.array_equal(A[coords], subview)) # 验证为True
关于视图跟踪类的补充
如果你需要对滤波后的数据也跟踪和原数组的对应关系,不用非要继承numpy.ndarray,可以封装一个轻量数据类:
from dataclasses import dataclass import numpy as np from scipy.ndimage import median_filter @dataclass class ArrayWithOrigin: data: np.ndarray origin_arr: np.ndarray # 如果有缩放/偏移可以额外加参数,滤波后坐标没有偏移就不用加 # 生成带原始数组关联的实例 filt = ArrayWithOrigin( data=median_filter(A, size=5), origin_arr=A )
如果确实需要所有切片视图都自动携带原始数组坐标,用numpy的__array_finalize__钩子实现自定义数组类的成本也很低,不需要处理复杂的内部逻辑。
内容的提问来源于stack exchange,提问作者P i
相关产品推荐
相关产品推荐

