在特定位置提取图像中的球形区域(使用 skimage 等)
Extract spherical region in image at a certain position (with skimage et al.)
我有(一堆 3D)断层扫描数据堆栈,在这些数据中我已经推导出某个(3D)坐标,我需要围绕它切出一个球形区域。
我的代码生成了下图,概述了我所做的事情。
我根据白色虚线和绿色虚线区域计算橙色和绿色点。
在这些的中点附近,我想切出一个球形区域,它的表示现在在图像中用一个圆圈标记(也是我的代码绘制的)。
用 skimage.morphology.ball
构建一个球体并将其与原始图像相乘很容易,但是如何将球体的中心设置在图像中所需的 3D 位置?
大约 30 张 3D 图像堆栈的大小各不相同,区域也不同,但我已准备好所有必要的坐标以供进一步使用。
你有一些半径 r
和数据的索引 (i,j,k)
。
kernel = skimage.morphology.ball(r)
returns 一个 mask/kernel 每边 a = 2*r + 1
。这是 cube-shaped.
从断层扫描仪中取出一个 cube-shaped 切片,您的内核大小。起始索引取决于您需要的中心位置以及内核的半径。
piece = data[i-r:i-r+a, j-r:j-r+a, k-r:k-r+a]
将二进制“球”mask/kernel应用于切片。
piece *= kernel
这是我使用的两种方法,它们显示了数组中 sub-regions 的两种 'operating'(以某种方式计算值)的方法。两种不同的方法是:
假设您只想计算球形区域中值的平均值:
1 - 直接将区域坐标指定为'slice':
data[region_coordinates].mean()
2 - 使用数组的掩码版本,其中掩码用于指定区域:data_masked.mean()
哪个可能更好取决于您可能希望对该区域中的值执行的操作。两者都可以使用 inter-changebly,您可以只选择使您的代码 clearer/easier/faster.
在我的工作中,我使用这两种方法,但更常用的是第一种方法(您将区域指定为 'slice' 坐标)。
对我来说,坐标切片方法有以下优点:
1 - 发生的事情更加明显
2 - 如果需要,您可以更轻松地将几何运算应用于 'region'。 (例如旋转、平移、缩放...)
这是示例代码,以及您可以用于任一方法的方法:
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())
我有(一堆 3D)断层扫描数据堆栈,在这些数据中我已经推导出某个(3D)坐标,我需要围绕它切出一个球形区域。
我的代码生成了下图,概述了我所做的事情。 我根据白色虚线和绿色虚线区域计算橙色和绿色点。 在这些的中点附近,我想切出一个球形区域,它的表示现在在图像中用一个圆圈标记(也是我的代码绘制的)。
用 skimage.morphology.ball
构建一个球体并将其与原始图像相乘很容易,但是如何将球体的中心设置在图像中所需的 3D 位置?
大约 30 张 3D 图像堆栈的大小各不相同,区域也不同,但我已准备好所有必要的坐标以供进一步使用。
你有一些半径
r
和数据的索引(i,j,k)
。kernel = skimage.morphology.ball(r)
returns 一个 mask/kernel 每边a = 2*r + 1
。这是 cube-shaped.从断层扫描仪中取出一个 cube-shaped 切片,您的内核大小。起始索引取决于您需要的中心位置以及内核的半径。
piece = data[i-r:i-r+a, j-r:j-r+a, k-r:k-r+a]
将二进制“球”mask/kernel应用于切片。
piece *= kernel
这是我使用的两种方法,它们显示了数组中 sub-regions 的两种 'operating'(以某种方式计算值)的方法。两种不同的方法是:
假设您只想计算球形区域中值的平均值:
1 - 直接将区域坐标指定为'slice':
data[region_coordinates].mean()
2 - 使用数组的掩码版本,其中掩码用于指定区域:data_masked.mean()
哪个可能更好取决于您可能希望对该区域中的值执行的操作。两者都可以使用 inter-changebly,您可以只选择使您的代码 clearer/easier/faster.
在我的工作中,我使用这两种方法,但更常用的是第一种方法(您将区域指定为 'slice' 坐标)。
对我来说,坐标切片方法有以下优点:
1 - 发生的事情更加明显
2 - 如果需要,您可以更轻松地将几何运算应用于 'region'。 (例如旋转、平移、缩放...)
这是示例代码,以及您可以用于任一方法的方法:
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())