Upload tumor_mask.py
Browse files- tumor_mask.py +84 -0
tumor_mask.py
ADDED
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
from scipy import ndimage
|
3 |
+
|
4 |
+
|
5 |
+
def extract_tumor_and_peritumoral(mask_volume, peritumoral_margin=2, patch_size=(16, 16, 16)):
|
6 |
+
"""
|
7 |
+
Extract tumor and peritumoral regions from a 3D annotation mask.
|
8 |
+
Flattens dilated mask into sequence of patches and creates position mask.
|
9 |
+
|
10 |
+
Parameters:
|
11 |
+
mask_volume: 3D numpy array (z, y, x) with tumor annotations (1 for tumor, 0 for background)
|
12 |
+
peritumoral_margin: Integer specifying the margin size (in voxels) for peritumoral region
|
13 |
+
patch_size: Tuple (z,y,x) specifying size of patches to use
|
14 |
+
|
15 |
+
Returns:
|
16 |
+
tumor_coords: List of coordinates (z, y, x) for tumor region
|
17 |
+
peritumoral_coords: List of coordinates (z, y, x) for peritumoral region
|
18 |
+
patch_mask: Binary mask indicating if patches contain tumor (1) or not (0)
|
19 |
+
"""
|
20 |
+
|
21 |
+
# Get tumor coordinates
|
22 |
+
tumor_coords = np.where(mask_volume == 1)
|
23 |
+
tumor_coords = list(zip(tumor_coords[0], tumor_coords[1], tumor_coords[2]))
|
24 |
+
|
25 |
+
# Create dilated mask for peritumoral region
|
26 |
+
dilated_mask = ndimage.binary_dilation(
|
27 |
+
mask_volume,
|
28 |
+
structure=np.ones((peritumoral_margin * 2 + 1, peritumoral_margin * 2 + 1, peritumoral_margin * 2 + 1)),
|
29 |
+
)
|
30 |
+
|
31 |
+
# Create patch position mask
|
32 |
+
z_steps = mask_volume.shape[0] // patch_size[0]
|
33 |
+
y_steps = mask_volume.shape[1] // patch_size[1]
|
34 |
+
x_steps = mask_volume.shape[2] // patch_size[2]
|
35 |
+
|
36 |
+
patch_mask = np.zeros((z_steps, y_steps, x_steps))
|
37 |
+
|
38 |
+
for z in range(z_steps):
|
39 |
+
for y in range(y_steps):
|
40 |
+
for x in range(x_steps):
|
41 |
+
patch = dilated_mask[
|
42 |
+
z * patch_size[0] : (z + 1) * patch_size[0],
|
43 |
+
y * patch_size[1] : (y + 1) * patch_size[1],
|
44 |
+
x * patch_size[2] : (x + 1) * patch_size[2],
|
45 |
+
]
|
46 |
+
if np.any(patch):
|
47 |
+
patch_mask[z, y, x] = 1
|
48 |
+
|
49 |
+
return tumor_coords, patch_mask.flatten()
|
50 |
+
|
51 |
+
|
52 |
+
# Example usage
|
53 |
+
def main():
|
54 |
+
# Create sample data for testing
|
55 |
+
volume_shape = (96, 96, 96)
|
56 |
+
mask_volume = np.zeros(volume_shape)
|
57 |
+
|
58 |
+
# Create a synthetic tumor mask in the middle
|
59 |
+
mask_volume[40:60, 40:60, 40:60] = 1
|
60 |
+
|
61 |
+
# Test parameters
|
62 |
+
patch_size = (16, 16, 16)
|
63 |
+
peritumoral_margin = 5
|
64 |
+
|
65 |
+
# Call function and get results
|
66 |
+
tumor_coords, patch_mask = extract_tumor_and_peritumoral(
|
67 |
+
mask_volume, peritumoral_margin=peritumoral_margin, patch_size=patch_size
|
68 |
+
)
|
69 |
+
|
70 |
+
# Print test results
|
71 |
+
print(f"Volume shape: {volume_shape}")
|
72 |
+
print(f"Tumor volume: {len(tumor_coords)}")
|
73 |
+
print(f"Number of total patches: {patch_mask.shape}")
|
74 |
+
print(f"Number of patches containing tumor/peritumoral region: {np.sum(patch_mask)}")
|
75 |
+
|
76 |
+
# Validate results
|
77 |
+
assert len(tumor_coords) > 0, "No tumor coordinates found"
|
78 |
+
assert len(patch_mask) == np.prod(np.array(volume_shape) // np.array(patch_size)), "Incorrect patch mask size"
|
79 |
+
|
80 |
+
return tumor_coords, patch_mask
|
81 |
+
|
82 |
+
|
83 |
+
if __name__ == "__main__":
|
84 |
+
tumor_coords, patch_mask = main()
|