spacr 0.2.32__py3-none-any.whl → 0.2.45__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- spacr/core.py +46 -59
- spacr/gui.py +20 -38
- spacr/gui_core.py +389 -474
- spacr/gui_elements.py +198 -56
- spacr/gui_utils.py +315 -57
- spacr/io.py +29 -38
- spacr/measure.py +6 -9
- spacr/plot.py +106 -0
- spacr/resources/icons/logo.pdf +2786 -6
- spacr/resources/icons/logo_spacr.png +0 -0
- spacr/resources/icons/logo_spacr_1.png +0 -0
- spacr/settings.py +1 -1
- spacr/utils.py +4 -24
- {spacr-0.2.32.dist-info → spacr-0.2.45.dist-info}/METADATA +4 -1
- {spacr-0.2.32.dist-info → spacr-0.2.45.dist-info}/RECORD +19 -17
- {spacr-0.2.32.dist-info → spacr-0.2.45.dist-info}/LICENSE +0 -0
- {spacr-0.2.32.dist-info → spacr-0.2.45.dist-info}/WHEEL +0 -0
- {spacr-0.2.32.dist-info → spacr-0.2.45.dist-info}/entry_points.txt +0 -0
- {spacr-0.2.32.dist-info → spacr-0.2.45.dist-info}/top_level.txt +0 -0
spacr/plot.py
CHANGED
@@ -19,6 +19,112 @@ from IPython.display import Image as ipyimage
|
|
19
19
|
|
20
20
|
from .logger import log_function_call
|
21
21
|
|
22
|
+
def plot_image_mask_overlay(file, channels, cell_channel, nucleus_channel, pathogen_channel, figuresize=10, normalize=True, thickness=3, save_pdf=True):
|
23
|
+
"""Plot image and mask overlays."""
|
24
|
+
|
25
|
+
def _plot_merged_plot(image, outlines, outline_colors, figuresize, thickness):
|
26
|
+
"""Plot the merged plot with overlay, image channels, and masks."""
|
27
|
+
|
28
|
+
def _normalize_image(image, percentiles=(2, 98)):
|
29
|
+
"""Normalize the image to the given percentiles."""
|
30
|
+
v_min, v_max = np.percentile(image, percentiles)
|
31
|
+
image_normalized = np.clip((image - v_min) / (v_max - v_min), 0, 1)
|
32
|
+
return image_normalized
|
33
|
+
|
34
|
+
def _generate_contours(mask):
|
35
|
+
"""Generate contours for the given mask using OpenCV."""
|
36
|
+
contours, _ = cv2.findContours(mask.astype(np.uint8), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
37
|
+
return contours
|
38
|
+
|
39
|
+
def _apply_contours(image, mask, color, thickness):
|
40
|
+
"""Apply the contours to the RGB image for each unique label."""
|
41
|
+
unique_labels = np.unique(mask)
|
42
|
+
for label in unique_labels:
|
43
|
+
if label == 0:
|
44
|
+
continue # Skip background
|
45
|
+
label_mask = np.where(mask == label, 1, 0).astype(np.uint8)
|
46
|
+
contours = _generate_contours(label_mask)
|
47
|
+
for contour in contours:
|
48
|
+
cv2.drawContours(image, [contour], -1, mpl.colors.to_rgb(color), thickness)
|
49
|
+
return image
|
50
|
+
|
51
|
+
num_channels = image.shape[-1]
|
52
|
+
fig, ax = plt.subplots(1, num_channels + 1, figsize=(4 * figuresize, figuresize))
|
53
|
+
|
54
|
+
# Plot each channel with its corresponding outlines
|
55
|
+
for v in range(num_channels):
|
56
|
+
channel_image = image[..., v]
|
57
|
+
channel_image_normalized = _normalize_image(channel_image)
|
58
|
+
channel_image_rgb = np.dstack((channel_image_normalized, channel_image_normalized, channel_image_normalized))
|
59
|
+
|
60
|
+
for outline, color in zip(outlines, outline_colors):
|
61
|
+
channel_image_rgb = _apply_contours(channel_image_rgb, outline, color, thickness)
|
62
|
+
|
63
|
+
ax[v].imshow(channel_image_rgb)
|
64
|
+
ax[v].set_title(f'Image - Channel {v}')
|
65
|
+
|
66
|
+
# Plot the combined RGB image with all outlines
|
67
|
+
rgb_image = np.zeros((*image.shape[:2], 3), dtype=float)
|
68
|
+
rgb_channels = min(3, num_channels)
|
69
|
+
for i in range(rgb_channels):
|
70
|
+
channel_image = image[..., i]
|
71
|
+
channel_image_normalized = _normalize_image(channel_image)
|
72
|
+
rgb_image[..., i] = channel_image_normalized
|
73
|
+
|
74
|
+
for outline, color in zip(outlines, outline_colors):
|
75
|
+
rgb_image = _apply_contours(rgb_image, outline, color, thickness)
|
76
|
+
|
77
|
+
ax[-1].imshow(rgb_image)
|
78
|
+
ax[-1].set_title('Combined RGB Image')
|
79
|
+
|
80
|
+
plt.tight_layout()
|
81
|
+
|
82
|
+
# Save the figure as a PDF
|
83
|
+
if save_pdf:
|
84
|
+
pdf_dir = os.path.join(os.path.dirname(os.path.dirname(file)), 'results', 'overlay')
|
85
|
+
os.makedirs(pdf_dir, exist_ok=True)
|
86
|
+
pdf_path = os.path.join(pdf_dir, os.path.basename(file).replace('.npy', '.pdf'))
|
87
|
+
fig.savefig(pdf_path, format='pdf')
|
88
|
+
|
89
|
+
plt.show()
|
90
|
+
return fig
|
91
|
+
|
92
|
+
stack = np.load(file)
|
93
|
+
|
94
|
+
# Convert to float for normalization and ensure correct handling of both 8-bit and 16-bit arrays
|
95
|
+
if stack.dtype == np.uint16:
|
96
|
+
stack = stack.astype(np.float32)
|
97
|
+
elif stack.dtype == np.uint8:
|
98
|
+
stack = stack.astype(np.float32)
|
99
|
+
|
100
|
+
image = stack[..., channels]
|
101
|
+
outlines = []
|
102
|
+
outline_colors = []
|
103
|
+
|
104
|
+
if pathogen_channel is not None:
|
105
|
+
pathogen_mask_dim = -1 # last dimension
|
106
|
+
outlines.append(np.take(stack, pathogen_mask_dim, axis=2))
|
107
|
+
outline_colors.append('blue')
|
108
|
+
|
109
|
+
if nucleus_channel is not None:
|
110
|
+
nucleus_mask_dim = -2 if pathogen_channel is not None else -1
|
111
|
+
outlines.append(np.take(stack, nucleus_mask_dim, axis=2))
|
112
|
+
outline_colors.append('green')
|
113
|
+
|
114
|
+
if cell_channel is not None:
|
115
|
+
if nucleus_channel is not None and pathogen_channel is not None:
|
116
|
+
cell_mask_dim = -3
|
117
|
+
elif nucleus_channel is not None or pathogen_channel is not None:
|
118
|
+
cell_mask_dim = -2
|
119
|
+
else:
|
120
|
+
cell_mask_dim = -1
|
121
|
+
outlines.append(np.take(stack, cell_mask_dim, axis=2))
|
122
|
+
outline_colors.append('red')
|
123
|
+
|
124
|
+
fig = _plot_merged_plot(image=image, outlines=outlines, outline_colors=outline_colors, figuresize=figuresize, thickness=thickness)
|
125
|
+
|
126
|
+
return
|
127
|
+
|
22
128
|
def plot_masks(batch, masks, flows, cmap='inferno', figuresize=20, nr=1, file_type='.npz', print_object_number=True):
|
23
129
|
"""
|
24
130
|
Plot the masks and flows for a given batch of images.
|