2026-04-10 05:25:27 +00:00
|
|
|
|
import numpy as np
|
|
|
|
|
|
import SimpleITK as sitk
|
|
|
|
|
|
from config.constant import LABEL_MAP
|
|
|
|
|
|
|
2026-09-04 20:30:10 +00:00
|
|
|
|
def resample_img(sitk_image, out_spacing=[0.5, 0.5, 0.5], is_label=False,
|
|
|
|
|
|
interpolator=None, cval=None):
|
|
|
|
|
|
"""重採樣到 out_spacing,完整保留物理範圍(邊界 margin 不裁剪):
|
|
|
|
|
|
- CT(is_label=False):线性插值。本流程是上採樣(~0.75-1mm -> 0.5mm),
|
|
|
|
|
|
线性即無漣波的理想重建;B-spline 會在身體 margin 等強邊界產生
|
|
|
|
|
|
非物理的 undershoot/overshoot(量測:~0.5% 體素低於 air floor
|
|
|
|
|
|
-1024 HU,最低 -1274,沿體輪廓形成黑暈)。
|
|
|
|
|
|
- 預設填充值 = 影像最小值(air),而非 GetPixelIDValue()
|
|
|
|
|
|
(對 int16 CT 回傳佔位值 2 ≈ 軟組織,會把 margin 填成軟組織)。
|
|
|
|
|
|
- 輸出尺寸用 ceil 覆蓋原物理尺寸(round 會讓遠端端點被裁 ≤0.25mm)。
|
|
|
|
|
|
label(is_label=True):最近邻、填充 0。
|
|
|
|
|
|
interpolator:明確指定插值器(None = 依 is_label 取 Linear / NearestNeighbor;
|
|
|
|
|
|
例如 SMD 等 piecewise-linear 場用 sitk.sitkBSpline,三阶 B 样条对分段
|
|
|
|
|
|
线性场为精确重建、無漣波)。
|
|
|
|
|
|
cval:明確指定填充值(None = 上述預設)。
|
|
|
|
|
|
"""
|
|
|
|
|
|
original_spacing = np.array(sitk_image.GetSpacing(), dtype=float)
|
|
|
|
|
|
original_size = np.array(sitk_image.GetSize())
|
|
|
|
|
|
out_spacing = np.array(out_spacing, dtype=float)
|
|
|
|
|
|
physical = original_size * original_spacing
|
|
|
|
|
|
out_size = [max(1, int(np.ceil(physical[i] / out_spacing[i] - 1e-6)))
|
|
|
|
|
|
for i in range(3)]
|
2026-04-10 05:25:27 +00:00
|
|
|
|
|
|
|
|
|
|
resample = sitk.ResampleImageFilter()
|
2026-09-04 20:30:10 +00:00
|
|
|
|
resample.SetOutputSpacing(out_spacing.tolist())
|
2026-04-10 05:25:27 +00:00
|
|
|
|
resample.SetSize(out_size)
|
|
|
|
|
|
resample.SetOutputDirection(sitk_image.GetDirection())
|
|
|
|
|
|
resample.SetOutputOrigin(sitk_image.GetOrigin())
|
|
|
|
|
|
resample.SetTransform(sitk.Transform())
|
|
|
|
|
|
|
|
|
|
|
|
if is_label:
|
2026-09-04 20:30:10 +00:00
|
|
|
|
resample.SetInterpolator(interpolator or sitk.sitkNearestNeighbor)
|
|
|
|
|
|
resample.SetDefaultPixelValue(cval if cval is not None else 0)
|
|
|
|
|
|
elif interpolator is not None:
|
|
|
|
|
|
resample.SetInterpolator(interpolator)
|
|
|
|
|
|
# SMD 等 signed 場的填充:預設 0 = 表面層值(比影像 min/max 安全,
|
|
|
|
|
|
# 不會製造假的零穿越環);可用品值可用 cval 覆蓋
|
|
|
|
|
|
resample.SetDefaultPixelValue(float(cval) if cval is not None else 0.0)
|
2026-04-10 05:25:27 +00:00
|
|
|
|
else:
|
2026-09-04 20:30:10 +00:00
|
|
|
|
resample.SetInterpolator(sitk.sitkLinear)
|
|
|
|
|
|
# air 值 = 影像最小 HU(statistics 濾波器 streaming 計算,不載入整張 array)
|
|
|
|
|
|
stats = sitk.StatisticsImageFilter()
|
|
|
|
|
|
stats.Execute(sitk_image)
|
|
|
|
|
|
resample.SetDefaultPixelValue(float(stats.GetMinimum()))
|
2026-04-10 05:25:27 +00:00
|
|
|
|
|
|
|
|
|
|
return resample.Execute(sitk_image)
|