如何用skimage在Python中无损调整3D CT二进制分割掩码至(128,128,128)?
3D二进制分割掩码的无损尺寸调整问题
我正在处理3D CT图像,需要将尺寸为(564,359,359)的二进制分割掩码调整为(128,128,128)。
最初尝试的代码:
from skimage.transform import resize mask_resized= resize(binary_mask, (128, 128, 128), order=0)
调整前的掩码是标准二进制图像,调整后输出值介于0和1之间且存在失真。尝试用np.rint(image_resized_seg)处理后,部分含掩码的切片变为全黑。
之后又尝试了以下代码,结果仍存在失真且部分掩码切片丢失:
from scipy import ndimage def resize_volume_mask(img): """Resize across z-axis""" # Set the desired depth desired_depth = 128 desired_width = 128 desired_height = 128 # Get current depth current_depth = img.shape[0] current_width = img.shape[1] current_height = img.shape[2] # Compute depth factor depth = current_depth / desired_depth width = current_width / desired_width height = current_height / desired_height depth_factor = 1 / depth width_factor = 1 / width height_factor = 1 / height # Resize across z-axis img = ndimage.zoom(img, (depth_factor, width_factor, height_factor), order=0) return img
请问如何在不丢失信息的前提下调整分割掩码尺寸并保持其二进制属性?
解决方案
二进制掩码的resize核心要保证类别边界准确性和无信息丢失,以下是三种可靠的实现方式:
方法1:修正skimage.resize的二值化逻辑
skimage的resize默认会将输出归一化到[0,1],即使使用order=0(最近邻插值),也可能因浮点精度出现非0/1值。正确做法是插值后直接阈值化,而非依赖np.rint:
from skimage.transform import resize import numpy as np # 最近邻插值,保留原始值范围避免归一化 mask_resized = resize( binary_mask, (128, 128, 128), order=0, preserve_range=True, # 关键参数:不改变原始值范围 anti_aliasing=False # 二进制图像无需抗锯齿 ) # 强制二值化:大于0.5的像素设为1,否则为0 mask_resized_binary = (mask_resized > 0.5).astype(binary_mask.dtype)
方法2:优化scipy.ndimage.zoom的处理流程
之前的代码问题在于缩放因子非整数倍时,最近邻插值可能丢失稀疏掩码区域。通过插值后强制二值化解决浮点误差问题:
from scipy import ndimage import numpy as np def resize_binary_mask(img, target_shape=(128,128,128)): current_shape = img.shape # 计算各维度缩放因子 zoom_factors = [t/c for t,c in zip(target_shape, current_shape)] # 最近邻插值缩放,保留原始值范围 resized = ndimage.zoom(img, zoom_factors, order=0, mode='nearest') # 强制二值化修正浮点误差 resized_binary = (resized > 0.5).astype(img.dtype) return resized_binary # 使用示例 mask_resized = resize_binary_mask(binary_mask)
方法3:基于坐标映射的精确重采样(最可靠)
若上述方法仍有信息丢失,可手动生成目标网格坐标,映射回原始掩码取最近邻值,完全避免插值算法的局限性:
import numpy as np def resize_mask_coordinate_based(mask, target_shape=(128,128,128)): # 生成目标空间的网格坐标 z_target, y_target, x_target = np.meshgrid( np.linspace(0, mask.shape[0]-1, target_shape[0]), np.linspace(0, mask.shape[1]-1, target_shape[1]), np.linspace(0, mask.shape[2]-1, target_shape[2]), indexing='ij' ) # 取原始掩码的最近邻坐标 z_original = np.round(z_target).astype(int) y_original = np.round(y_target).astype(int) x_original = np.round(x_target).astype(int) # 从原始掩码取值生成新掩码 resized_mask = mask[z_original, y_original, x_original] return resized_mask
关键注意事项
- 必须开启
preserve_range=True(skimage)或避免归一化操作,防止原始二进制值被修改 - 直接用
>0.5阈值二值化,避免np.rint因浮点误差导致的全黑切片 - 针对稀疏3D掩码,优先选择坐标映射法,确保小区域不丢失
内容的提问来源于stack exchange,提问作者Dushi Fdz
相关产品推荐
相关产品推荐

