以下是我使用的两种方法,它们展示了对数组中的子区域进行“操作”(以某种方式计算值)的两种方法。两种不同的方法是:
假设您只想计算球形区域中的值的平均值:
1 - 将区域坐标直接指定为“切片”:
data[region_coordinates].mean()
2 - 使用掩码版本的数组,其中掩码用于指定区域:data_masked.mean()
哪个可能更好取决于您可能希望对该区域中的值做什么。两者都可以互换使用,您可以选择哪个使您的代码更清晰/更容易/更快。
在我的工作中,我使用了这两种方法,但更常见的是第一种方法(将区域指定为坐标的“切片”)。
对我来说,坐标切片方法有优势:
1 - 发生的事情更加明显
2 - 如果需要,您可以更轻松地将几何运算应用于您的“区域”。 (例如旋转、平移、缩放……)
以下是示例代码,以及可用于任一方法的方法:
mport numpy as np
import skimage.morphology as mo
from typing import Tuple
def get_ball_coords(radius: int, center: Tuple[int]) -> Tuple[np.ndarray]:
"""
Use radius and center to return the coordinates within that 3d region
as a 'slice'.
"""
coords = np.nonzero(mo.ball(radius))
# 'coords' is a tuple of 1d arrays - to move center using pure numpy,
# first convert to a 2d array
coords_array = np.array(coords)
center_array = np.array([center]).T
# transform coordinates to be centered at 'center'
coords_array = coords_array - radius + center_array
# convert coordinates back to tuple of 1d arrays, which can be used
# directly as a slice specification
coords_tuple = (
coords_array[0,:],
coords_array[1,:],
coords_array[2,:]
)
return coords_tuple
def get_masked_array(data: np.ndarray, radius: int, center: Tuple[int]) -> np.ndarray:
"""
Return a masked version of the data array, where all values are masked
except for the values within the sphere specified by radius and center.
"""
# get 'ball' as 2d array of booleans
ball = np.array(mo.ball(radius), dtype=bool)
# create full mask over entire data array
mask = np.full_like(data, True, dtype=bool)
# un-mask the 'ball' region, translated to the 'center'
mask[
center[0]-radius: center[0]+radius+1,
center[1]-radius: center[1]+radius+1,
center[2]-radius: center[2]+radius+1
] = ~ball
# mask is now True everywhere, except inside the 'ball'
# at 'center' - create masked array version of data using this.
masked_data = np.ma.array(data=data, mask=mask)
return masked_data
# make some 3D data
data_size = (100,100,100)
data = np.random.rand(*data_size)
# define some spherical region by radius and center
region_radius = 2
region_center = (23, 41, 53)
# get coordinates of this region
region_coords = get_ball_coords(region_radius, region_center)
# get masked version of the data, based on this region
data_masked = get_masked_array(data, region_radius, region_center)
# now you can use 'region_coords' as a single 'index' (slice)
# to specify only the points with those coordinates
print('\nUSING COORDINATES:')
print('here is mean value in the region:')
print(data[region_coords].mean())
print('here is the total data mean:')
print(data.mean())
# of you can use the masked array as-is:
print('\nUSING MASKED DATA:')
print('here is mean value in the region:')
print(data_masked.mean())
print('here is the total data mean:')
print(data.mean())