gliders 0.1.0__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.

Potentially problematic release.


This version of gliders might be problematic. Click here for more details.

gliders/__init__.py ADDED
@@ -0,0 +1,2 @@
1
+ from .pipeline import clean_image
2
+ # __all__ = ["get_clean_image_and_segment"]
gliders/artifacts.py ADDED
@@ -0,0 +1,349 @@
1
+ import numpy as np
2
+ from .utils import interpolate_image, grow_mask, add_noise_to_region, sigma_clipping, shrink_mask, get_profile_gradient, get_profile_from_border
3
+ from photutils.segmentation import SourceCatalog, detect_sources
4
+
5
+
6
+ def detect_and_clean_artifacts(image, config = None, img_bkg_lvl = None, pix_scale = 1, main_source_pos = None,
7
+ skip_flagged_artifacts = False, verbose = False, show_plots = False):
8
+ """
9
+ Detect and optionally remove overexposure artifacts from an image.
10
+
11
+ Artifact candidates are first identified using
12
+ :func:`detect_artifacts`, which searches for bright structures with
13
+ characteristic intensity profiles. Detected artifacts are then
14
+ classified as either safe or unsafe according to their size and
15
+ proximity to the target source through
16
+ :func:`get_artifact_flag`.
17
+
18
+ If artifacts are detected and cleaning is allowed, the affected
19
+ regions are replaced using :func:`clean_artifacts`, including an
20
+ additional mask to account for bleeding around the artifact.
21
+
22
+ Parameters
23
+ ----------
24
+ image : ndarray
25
+ Input image to be inspected and cleaned.
26
+
27
+ config : object, optional
28
+ Configuration object containing the artifact-detection and
29
+ cleaning parameters. If None, the default cleaning configuration
30
+ is loaded from ``cleaning_configs``.
31
+
32
+ img_bkg_lvl : float, optional
33
+ Background level of the image. If None, it is estimated using
34
+ sigma clipping.
35
+
36
+ pix_scale : float, optional
37
+ Pixel scale of the image. Used when cleaning artifacts. Default is 1.
38
+
39
+ main_source_pos : tuple(float, float) or None, optional
40
+ Pixel coordinates (x, y) of the primary target source. Used to
41
+ determine whether a detected artifact lies within the protected
42
+ central region of the image. If None, the image center is used.
43
+
44
+ skip_flagged_artifacts : bool, optional
45
+ If True, artifacts classified as unsafe are not cleaned and the
46
+ original image is returned unchanged. This can be useful to
47
+ preserve images where an artifact significantly affects the
48
+ target source. Default is False.
49
+
50
+ show_plots : bool, optional
51
+ If True, display diagnostic plots showing the original image,
52
+ cleaned image, detected artifact mask, and final cleaning mask.
53
+ Default is False.
54
+
55
+ Returns
56
+ -------
57
+ clean_image : ndarray
58
+ The cleaned image. If no artifacts are detected, or if cleaning
59
+ is skipped, this will be identical to the input image.
60
+
61
+ cleaning_mask : ndarray of bool
62
+ Boolean mask identifying pixels affected by the artifact
63
+ cleaning process. This includes both the detected artifact
64
+ pixels and any additional bleeding region considered during
65
+ cleaning.
66
+
67
+ unsafe_artifact_flag : bool
68
+ True if a detected artifact overlaps the protected central
69
+ region and exceeds the configured relative size threshold.
70
+ False otherwise.
71
+
72
+ Notes
73
+ -----
74
+ The behavior of the detector and cleaner is controlled by the
75
+ following configuration parameters:
76
+
77
+ - ``npixels_artifact``
78
+ - ``artifact_delta_slope_threshold``
79
+ - ``artifact_segment_slack``
80
+ - ``artifact_candidate_ratio``
81
+ - ``artifact_rel_size_thresh``
82
+ - ``artifact_safe_region_radius``
83
+ - ``artifact_bleeding_factor``
84
+
85
+ When ``skip_flagged_artifacts=True``, images containing unsafe
86
+ artifacts are not modified, although the artifact mask and flag are
87
+ still returned.
88
+ """
89
+
90
+ if config is None:
91
+ from .cleaning_configs import configs
92
+ config = configs["default"]
93
+ if img_bkg_lvl is None:
94
+ img_bkg_lvl, _ = sigma_clipping(image)
95
+
96
+ artifact_segmap = detect_artifacts(image, npixels_artifact=config.npixels_artifact,
97
+ delta_slope_threshold=config.artifact_delta_slope_threshold,
98
+ segment_slack=config.artifact_segment_slack,
99
+ hi_pass_threshold=img_bkg_lvl * config.artifact_candidate_ratio)
100
+
101
+ if artifact_segmap is None:
102
+ if verbose:
103
+ print("No overexposure artifacts were detected in the image.")
104
+ cleaning_mask = np.zeros_like(image, dtype=bool)
105
+ return image, cleaning_mask, False
106
+
107
+ artifact_mask = artifact_segmap.make_source_mask()
108
+ unsafe_artifact_flag = get_artifact_flag(artifact_mask, main_source_pos, config.artifact_rel_size_thresh, config.artifact_safe_region_radius, show_plots = show_plots)
109
+
110
+ if artifact_mask.any() and not (skip_flagged_artifacts and unsafe_artifact_flag):
111
+ clean_image, cleaning_mask = clean_artifacts(image, artifact_segmap, config.artifact_bleeding_factor,
112
+ config.artifact_interpolation_radius, pix_scale)
113
+ else:
114
+ clean_image = image
115
+ cleaning_mask = artifact_mask
116
+
117
+ if show_plots:
118
+ import matplotlib.pyplot as plt
119
+ fig, ax = plt.subplots(2,2)
120
+ ax[0,0].imshow(image, norm = "log", origin = "lower")
121
+ ax[0,0].set_title('Input image')
122
+ ax[0,1].imshow(clean_image, norm = "log", origin = "lower")
123
+ ax[0,1].set_title('Treated image')
124
+ ax[1,0].imshow(artifact_mask, origin = "lower")
125
+ ax[1,0].set_title('Detected artifacts')
126
+ ax[1,1].imshow(cleaning_mask, origin = "lower")
127
+ ax[1,1].set_title('Detected artifacts + bleeding')
128
+ plt.tight_layout()
129
+ plt.show()
130
+
131
+ return clean_image, cleaning_mask, unsafe_artifact_flag
132
+
133
+ def clean_artifacts(image, artifact_segmap = None, bleeding_factor = 1.0, interpolation_radius = 1, pix_scale = 1):
134
+
135
+ """Remove artifacts based on interpolation over segmented artifacts.
136
+
137
+ Parameters
138
+ ----------
139
+ image : np.ndarray
140
+ Input image.
141
+ artifact_segmap : segmentation map, optional
142
+ Artifact segmentation map. If None, the image is returned unchanged.
143
+ bleeding_factor : float
144
+ Multiplier controlling how far the artifact mask is expanded.
145
+ interpolation_radius : float
146
+ Radius of the circle containing the pixels to be considered in the interpolation.
147
+ pix_scale : float
148
+ Scale factor of the noise pixels added.
149
+
150
+ Returns
151
+ -------
152
+ image : np.ndarray
153
+ Cleaned image.
154
+ full_cleaning_mask : np.ndarray or None
155
+ Mask of pixels modified by the cleaning procedure.
156
+ """
157
+
158
+ if artifact_segmap is None or (len(artifact_segmap.segments) < 1):
159
+ return image, np.zeros(image.shape, dtype=bool)
160
+
161
+ if bleeding_factor < 0:
162
+ raise ValueError("bleeding_factor must be non-negative")
163
+
164
+ if interpolation_radius < 1:
165
+ raise ValueError("interpolation_radius must be equal or greater than 1")
166
+ all_artifacts_mask = artifact_segmap.make_source_mask()
167
+ full_cleaning_mask = all_artifacts_mask.copy()
168
+ for artifact in artifact_segmap.segments:
169
+ artifact_mask = artifact_segmap.data == artifact.label
170
+ artifact_area = artifact_mask.sum()
171
+ bleeding_decay = 2 * artifact_area**(1/3) # Rounded from empiric formula based on DESI Legacy images.
172
+ bleeding_radius = round(bleeding_factor * bleeding_decay)
173
+ # Expanding detection mask to cover artifact bleeding
174
+ cleaning_mask = grow_mask(artifact_mask, pixels=bleeding_radius)
175
+ full_cleaning_mask |= cleaning_mask
176
+
177
+ image = interpolate_image(image, full_cleaning_mask, interpolation_radius, method="inpaint")
178
+ _, img_bkg_lvl_std = sigma_clipping(image)
179
+ image = add_noise_to_region(image, full_cleaning_mask, noise_center=0, noise_std=img_bkg_lvl_std, scale=pix_scale)
180
+ return image, full_cleaning_mask
181
+
182
+ def detect_artifacts(image, npixels_artifact=100, delta_slope_threshold = 2.7, segment_slack = 5, hi_pass_threshold = 1):
183
+ """
184
+ Detect candidate overexposure artifacts based on their radial intensity profile.
185
+
186
+ The algorithm first identifies bright connected regions above a fixed
187
+ intensity threshold. For each candidate region, a series of concentric
188
+ layers is constructed around the detected segment and the mean pixel value
189
+ within each layer is measured. The resulting radial profile is analyzed
190
+ through its gradient and second-order variations (delta slopes).
191
+
192
+ Regions showing an abrupt change in profile slope are classified as
193
+ artifacts.
194
+
195
+ Parameters
196
+ ----------
197
+ image : ndarray
198
+ 2D image to analyze.
199
+
200
+ npixels_artifact : int, optional
201
+ Minimum number of connected pixels required for a region to be
202
+ considered as an artifact candidate.
203
+
204
+ delta_slope_threshold : float, optional
205
+ Minimum peak value in the profile delta-slope sequence required to
206
+ classify a candidate as an artifact. Larger values make the detection
207
+ more conservative.
208
+
209
+ segment_slack : int, optional
210
+ Number of pixels by which each candidate segment is expanded when
211
+ computing the surrounding radial profile. Also sets the number of
212
+ profile layers evaluated.
213
+
214
+ hi_pass_threshold : float, optional
215
+ Pixel intensity threshold used to generate the initial binary mask of
216
+ artifact candidates.
217
+
218
+ Returns
219
+ -------
220
+ ndarray of bool
221
+ Segmentation map of all detected artifacts.
222
+
223
+ Notes
224
+ -----
225
+ Artifact identification relies on the assumption that overexposed features
226
+ often exhibit sharp transitions in their radial intensity profile, unlike
227
+ typical astronomical sources whose profiles vary more smoothly.
228
+ """
229
+
230
+ hi_pass_mask = image > hi_pass_threshold
231
+ artifacts_segmap = detect_sources(hi_pass_mask, 0.5, npixels_artifact, connectivity=8)
232
+ if artifacts_segmap is None:
233
+ return artifacts_segmap
234
+
235
+ candidate_artifacts_mask = artifacts_segmap.data > 0
236
+
237
+ labels_to_remove = []
238
+ artifacts_cat = SourceCatalog(candidate_artifacts_mask, artifacts_segmap)
239
+
240
+ for artifact in artifacts_cat:
241
+ segment_mask = artifact.segment.astype(bool)
242
+
243
+ pad_top = min(segment_slack, artifact.bbox.iymin)
244
+ pad_bottom = min(segment_slack, image.shape[0] - artifact.bbox.iymax)
245
+ pad_left = min(segment_slack, artifact.bbox.ixmin)
246
+ pad_right = min(segment_slack, image.shape[1] - artifact.bbox.ixmax)
247
+ segment_mask_padded = np.pad(segment_mask, ((pad_top, pad_bottom), (pad_left, pad_right)),
248
+ mode="constant", constant_values=False)
249
+
250
+ segment_cutout = image[max(0, artifact.bbox.iymin - segment_slack):min(image.shape[0],
251
+ artifact.bbox.iymax + segment_slack),
252
+ max(0, artifact.bbox.ixmin - segment_slack):min(image.shape[1],
253
+ artifact.bbox.ixmax + segment_slack)]
254
+
255
+ mean_profile = get_profile_from_border(segment_cutout, segment_mask_padded, segment_slack)
256
+
257
+ if len(mean_profile) < 3:
258
+ labels_to_remove.append(artifact.label)
259
+ continue
260
+ _, profile_delta_slopes = get_profile_gradient(mean_profile)
261
+ max_delta_slope = np.max(profile_delta_slopes)
262
+ is_artifact = max_delta_slope >= delta_slope_threshold
263
+ if not is_artifact:
264
+ labels_to_remove.append(artifact.label)
265
+ artifacts_segmap.remove_labels(labels_to_remove)
266
+
267
+ return artifacts_segmap
268
+
269
+ def get_artifact_flag(artifact_mask, main_source_pos = None, relative_size_thresh = 0.005, safe_region_radius = 0.25, show_plots = False):
270
+ """
271
+ Determine whether a detected artifact should be considered critical.
272
+
273
+ An artifact is flagged when both of the following conditions are met:
274
+
275
+ 1. At least one artifact pixel lies inside a central circular region
276
+ of the image.
277
+ 2. The total artifact area exceeds a minimum fraction of the area
278
+ of that central region.
279
+
280
+ The central region is defined as a circle centered on
281
+ ``main_source_pos``. If no valid source position is provided, the
282
+ image center is used instead. The circle radius is computed as
283
+ ``safe_region_radius * min(image_shape)``.
284
+
285
+ Parameters
286
+ ----------
287
+ artifact_mask : ndarray of bool
288
+ Boolean mask containing the detected artifact pixels.
289
+ True values indicate artifact locations.
290
+
291
+ main_source_pos : tuple(float, float) or None, optional
292
+ Pixel coordinates (x, y) of the target source. If None or if
293
+ the coordinates are not finite, the geometric center of the
294
+ image is used.
295
+
296
+ relative_size_thresh : float, optional
297
+ Minimum ratio between the total artifact area and the area of
298
+ the central circular region required to trigger the flag.
299
+ Default is 0.005.
300
+
301
+ safe_region_radius : float, optional
302
+ Radius of the central circular region expressed as a fraction of
303
+ the smallest image dimension. Values are clipped to the interval
304
+ [0, 1]. Default is 0.25.
305
+
306
+ show_plots : bool, optional
307
+ If True and a critical artifact is detected, display a diagnostic
308
+ plot showing the artifact mask and the central region. Default is
309
+ False.
310
+
311
+ Returns
312
+ -------
313
+ bool
314
+ True if the artifact overlaps the central region and is larger
315
+ than the specified relative size threshold. False otherwise.
316
+
317
+ Notes
318
+ -----
319
+ The artifact size is computed using the total number of pixels in
320
+ ``artifact_mask`` and is not restricted to the portion lying within
321
+ the central region.
322
+ """
323
+ ny, nx = artifact_mask.shape
324
+ if (main_source_pos is None or not np.all(np.isfinite(main_source_pos))):
325
+ center = (nx // 2, ny // 2)
326
+ else:
327
+ center = main_source_pos
328
+ safe_reg_prop_radius = np.clip(safe_region_radius, 0, 1)
329
+ radius = int(round(min((ny, nx)) * safe_reg_prop_radius))
330
+ # Create a mask for the central circular region
331
+ y, x = np.ogrid[:ny, :nx]
332
+ circle_mask = ((x - center[0]) ** 2 + (y - center[1]) ** 2 <= radius ** 2)
333
+
334
+ artifact_size = np.sum(artifact_mask)
335
+ inner_region_size = np.sum(circle_mask)
336
+ if inner_region_size == 0:
337
+ return False
338
+ big_artifact = (artifact_size / inner_region_size >= relative_size_thresh)
339
+ artifact_inside_region = np.any(artifact_mask & circle_mask)
340
+ artifact_flag = artifact_inside_region and big_artifact
341
+
342
+ if show_plots and artifact_flag:
343
+ import matplotlib.pyplot as plt
344
+ plt.imshow(artifact_mask.astype(int) + circle_mask.astype(int), origin = "lower")
345
+ plt.title("Artifact not-safe region")
346
+ plt.show()
347
+
348
+ return artifact_flag
349
+
@@ -0,0 +1,268 @@
1
+ import matplotlib.pyplot as plt
2
+ import numpy as np
3
+ from scipy.stats import norm
4
+ from scipy.signal import convolve2d
5
+ from .utils import sigma_clipping, normalize_data
6
+ from astropy.convolution import Gaussian2DKernel
7
+
8
+ def suppress_background(image, method ="simple", kernel = None, logit_alpha = 1.0):
9
+ """
10
+ Suppress background-dominated pixels in an image using a noise-based
11
+ probability model.
12
+
13
+ The function assumes that image noise follows an approximately normal
14
+ distribution. A noise probability map is first computed from the image
15
+ intensity distribution and then refined using one of several methods.
16
+ The resulting probability map is applied as a weighting function,
17
+ enhancing statistically significant structures while attenuating pixels
18
+ consistent with the background noise.
19
+
20
+ Parameters
21
+ ----------
22
+ image : ndarray
23
+ Input image.
24
+
25
+ method : {'simple', 'logit', 'layers'}, optional
26
+ Method used to generate the probability map.
27
+
28
+ * ``'simple'``: spatial smoothing of the noise probability map.
29
+ * ``'logit'``: smoothing in logit space followed by a logistic
30
+ transformation.
31
+ * ``'layers'``: iterative probability refinement using an
32
+ additional intensity-weighted layer.
33
+
34
+ Default is ``'simple'``.
35
+
36
+ kernel : ndarray, optional
37
+ Convolution kernel used for local probability aggregation. If
38
+ ``None``, a ``Gaussian2DKernel(2.0)`` is used.
39
+
40
+ logit_alpha : float, optional
41
+ Scaling factor applied to the logistic transform when
42
+ ``method='logit'``. Larger values increase the contrast between
43
+ low- and high-probability regions.
44
+
45
+ Returns
46
+ -------
47
+ ndarray
48
+ Background-suppressed image rescaled to approximately match the
49
+ original image intensity range.
50
+
51
+ Notes
52
+ -----
53
+ For better performance it is recommended that the image background
54
+ is already flattened (background subtraction).
55
+
56
+ See Also
57
+ --------
58
+ get_p_simple
59
+ get_p_logit
60
+ get_p_layers
61
+ apply_p_map
62
+ """
63
+
64
+ if kernel is None:
65
+ kernel = Gaussian2DKernel(2.0) # Larger kernels yield higher noise level, but more symmetric noise distribution
66
+
67
+ image_noise_lvl, image_noise_std = sigma_clipping(image, robust=False)
68
+
69
+ # Probability of obtaining x or lower:
70
+ noise_p_map = norm.cdf(image, loc=image_noise_lvl, scale=image_noise_std) # sf = 1 - cdf = survival function
71
+
72
+ if method == "logit":
73
+ p_map = _get_p_logit(noise_p_map, kernel, alpha = logit_alpha)
74
+ elif method == "layers":
75
+ p_map = _get_p_layers(image, noise_p_map, kernel)
76
+ else: #simple
77
+ p_map = _get_p_simple(noise_p_map, kernel)
78
+
79
+ bkg_reduced_image_leveled = _apply_p_map(image, p_map)
80
+
81
+ return bkg_reduced_image_leveled
82
+
83
+ def _get_p_simple(p_map, kernel):
84
+ """
85
+ Convolve probability map (p_map) with the input kernel.
86
+ """
87
+
88
+ p_out = convolve2d(p_map, kernel, mode='same', boundary='symm')
89
+ return p_out
90
+
91
+ def _get_p_logit(p_map, kernel, alpha = 1.0):
92
+ """
93
+ Transform probability map (p_map) into logits, convolve with the supplied
94
+ kernel, and transform back into a probability map.
95
+
96
+ alpha is the scaling factor applied to the aggregated logits before converting
97
+ back to probabilities. Values greater than one amplify local contrast,
98
+ while values less than one reduce it.
99
+
100
+ Notes
101
+ -----
102
+ Pixels with probability equal to one are clipped slightly below one
103
+ before the logit transformation to avoid numerical singularities.
104
+ """
105
+
106
+ p_map[p_map >= 1] = 1-1e-9
107
+ logit = np.log(p_map / (1 - p_map))
108
+ L = convolve2d(logit, kernel, mode='same', boundary='symm') # weighted sum of logit
109
+ p_out = 1.0 / (1.0 + np.exp(-alpha * L))
110
+ return p_out
111
+
112
+ def _get_p_layers(image, p_map, kernel):
113
+ """
114
+ Generate a probability map using a two-layer probability refinement
115
+ scheme.
116
+
117
+ An initial probability map (p_map) is first convolved with the provided kernel.
118
+ The image is then weighted by this smoothed map, and a second probability map is
119
+ estimated from the resulting intensity distribution. The final output
120
+ is obtained by combining the two probability layers.
121
+ """
122
+
123
+ p_map_cnv = convolve2d(p_map, kernel, mode='same', boundary='symm')
124
+ image_p_map_cnv = image * p_map_cnv
125
+ image_p_map_cnv_noise = sigma_clipping(image_p_map_cnv, robust=False)
126
+ p_map_new_layer = norm.cdf(image_p_map_cnv, loc=image_p_map_cnv_noise[0], scale=image_p_map_cnv_noise[1])
127
+ p_map_new_layer_cnv = convolve2d(p_map_new_layer, kernel, mode='same', boundary='symm')
128
+ p_out = p_map_cnv * p_map_new_layer_cnv
129
+ return p_out
130
+
131
+ def _apply_p_map(image, p_map):
132
+ """
133
+ Apply a probability map (p_map) to an image and rescale according to their maxima.
134
+ """
135
+
136
+ image_p_map = image * p_map
137
+ image_p_map_leveled = image_p_map * image.max() / image_p_map.max()
138
+ return image_p_map_leveled
139
+
140
+ def show_all_methods(image, kernel = None, normalize = True, cmap = "plasma", display_norm = "log", image_bias = 0.001, show_distributions = False):
141
+ """
142
+ Visualization of the different background-suppression methods available in the
143
+ package.
144
+
145
+ This utility function computes the probability maps and background-reduced
146
+ images obtained with the ``simple``, ``logit``, and ``layers`` methods,
147
+ and displays the results either as images or as intensity distributions.
148
+ It is primarily intended for visual inspection, debugging, and parameter
149
+ tuning.
150
+
151
+ Parameters
152
+ ----------
153
+ image : ndarray
154
+ Input image.
155
+
156
+ kernel : ndarray, optional
157
+ Convolution kernel used to smooth the probability maps. If ``None``,
158
+ a ``Gaussian2DKernel(2.0)`` is used.
159
+
160
+ normalize : bool, optional
161
+ If ``True``, all displayed images are normalized using
162
+ ``normalize_data`` before visualization. Default is ``True``.
163
+
164
+ cmap : str, optional
165
+ Matplotlib colormap used for image display. Default is ``"plasma"``.
166
+
167
+ display_norm : str, optional
168
+ Normalization used for image visualization and histogram scaling.
169
+ Typical values are ``"log"`` and ``"linear"``. Default is ``"log"``.
170
+
171
+ image_bias : float, optional
172
+ Small positive value added to displayed images to avoid issues with
173
+ logarithmic visualization and zero-valued pixels. Default is
174
+ ``0.001``.
175
+
176
+ show_distributions : bool, optional
177
+ If ``True``, display intensity histograms of the original and
178
+ processed images instead of image panels. Default is ``False``.
179
+
180
+ Returns
181
+ -------
182
+ None
183
+ The function generates matplotlib figures but does not return any
184
+ value.
185
+
186
+ See Also
187
+ --------
188
+ suppress_background
189
+ get_p_simple
190
+ get_p_logit
191
+ get_p_layers
192
+ apply_p_map
193
+ normalize_data
194
+ sigma_clipping
195
+ """
196
+
197
+ if kernel is None:
198
+ kernel = Gaussian2DKernel(2.0)
199
+ image_noise_lvl, image_noise_std = sigma_clipping(image, robust=False)
200
+ p_map = norm.cdf(image, loc=image_noise_lvl, scale=image_noise_std) # sf = 1 - cdf = survival function
201
+
202
+ p_simple = _get_p_simple(p_map, kernel)
203
+ p_logit = _get_p_logit(p_map, kernel)
204
+ p_layers = _get_p_layers(image, p_map, kernel)
205
+
206
+ bkg_reduced_image_simple = _apply_p_map(image, p_simple)
207
+ bkg_reduced_image_logit = _apply_p_map(image, p_logit)
208
+ bkg_reduced_image_layers = _apply_p_map(image, p_layers)
209
+
210
+ images = {
211
+ 'im_original': image,
212
+ 'im_simple': bkg_reduced_image_simple,
213
+ 'im_logit': bkg_reduced_image_logit,
214
+ 'im_layers': bkg_reduced_image_layers,
215
+ }
216
+
217
+ if normalize:
218
+ for key in images:
219
+ images[key] = normalize_data(images[key]) + image_bias
220
+
221
+ if show_distributions:
222
+
223
+ image_hist = images['im_original'].flatten()
224
+ bins = np.logspace(np.log10(np.min(image_hist[image_hist>0])),np.log10(np.max(image_hist)),100)
225
+ for key in images:
226
+ log_y = False
227
+ if display_norm == "log":
228
+ log_y = True
229
+ plt.hist(images[key].flatten(), bins = bins, alpha = 0.8, log = log_y, histtype='step', label = key, linewidth = 3, density = False)
230
+ plt.xscale(display_norm)
231
+ plt.legend()
232
+ plt.show()
233
+
234
+ else:
235
+
236
+ if not normalize:
237
+ for key in images:
238
+ images[key] += image_bias
239
+
240
+ figs, ax = plt.subplots(2, 4, layout="tight")
241
+
242
+ ax[1, 0].imshow(p_map, origin="lower")
243
+ ax[1, 0].set_title("raw p_map")
244
+ ax[0, 0].imshow(images["im_original"], origin="lower", norm=display_norm, cmap=cmap)
245
+ ax[0, 0].set_title("original")
246
+
247
+ ax[1, 1].imshow(p_simple, origin="lower")
248
+ ax[1, 1].set_title("simple")
249
+ ax[0, 1].imshow(images["im_simple"], origin="lower", norm=display_norm, cmap=cmap)
250
+ ax[0, 1].set_title("simple")
251
+
252
+ ax[1, 2].imshow(p_logit, origin="lower")
253
+ ax[1, 2].set_title("logit")
254
+ ax[0, 2].imshow(images["im_logit"], origin="lower", norm=display_norm, cmap=cmap)
255
+ ax[0, 2].set_title("logit")
256
+
257
+ ax[1, 3].imshow(p_layers, origin="lower")
258
+ ax[1, 3].set_title("layers")
259
+ ax[0, 3].imshow(images["im_layers"], origin="lower", norm=display_norm, cmap=cmap)
260
+ ax[0, 3].set_title("layers")
261
+
262
+ plt.show()
263
+
264
+
265
+ if __name__ == "__main__":
266
+ quit()
267
+
268
+