|
1 | 1 | import numpy as np |
| 2 | +from scipy.ndimage import convolve |
2 | 3 | from typing import Tuple |
3 | 4 | import warnings |
4 | 5 |
|
@@ -308,12 +309,58 @@ def mask_2d_via_pixel_coordinates_from( |
308 | 309 |
|
309 | 310 | if buffer == 0: |
310 | 311 | return mask_2d |
311 | | - else: |
312 | | - return buffed_mask_2d_from(mask_2d=mask_2d, buffer=buffer) |
| 312 | + return buffed_mask_2d_from(mask_2d=mask_2d, buffer=buffer) |
313 | 313 |
|
314 | 314 |
|
315 | | -from scipy.ndimage import convolve |
| 315 | +import numpy as np |
| 316 | + |
| 317 | + |
| 318 | +def min_false_distance_to_edge(mask: np.ndarray) -> Tuple[int, int]: |
| 319 | + """ |
| 320 | + Compute the minimum 1D distance in the y and x directions from any False value at the mask's extreme positions |
| 321 | + (leftmost, rightmost, topmost, bottommost) to its closest edge. |
316 | 322 |
|
| 323 | + Parameters |
| 324 | + ---------- |
| 325 | + mask |
| 326 | + A 2D boolean array where False represents the unmasked region. |
| 327 | +
|
| 328 | + Returns |
| 329 | + ------- |
| 330 | + The smallest distances of any extreme False value to the nearest edge in the vertical (y) and horizontal (x) |
| 331 | + directions. |
| 332 | +
|
| 333 | + Examples |
| 334 | + -------- |
| 335 | + >>> mask = np.array([ |
| 336 | + ... [ True, True, True, True], |
| 337 | + ... [ True, False, False, True], |
| 338 | + ... [ True, False, True, True], |
| 339 | + ... [ True, True, True, True] |
| 340 | + ... ]) |
| 341 | + >>> min_false_distance_to_edge(mask) |
| 342 | + (1, 1) |
| 343 | + """ |
| 344 | + false_indices = np.column_stack(np.where(mask == False)) |
| 345 | + |
| 346 | + if false_indices.size == 0: |
| 347 | + raise ValueError("No False values found in the mask.") |
| 348 | + |
| 349 | + leftmost = false_indices[np.argmin(false_indices[:, 1])] |
| 350 | + rightmost = false_indices[np.argmax(false_indices[:, 1])] |
| 351 | + topmost = false_indices[np.argmin(false_indices[:, 0])] |
| 352 | + bottommost = false_indices[np.argmax(false_indices[:, 0])] |
| 353 | + |
| 354 | + height, width = mask.shape |
| 355 | + |
| 356 | + # Compute distances to respective edges |
| 357 | + left_dist = leftmost[1] # Distance to left edge (column index) |
| 358 | + right_dist = width - 1 - rightmost[1] # Distance to right edge |
| 359 | + top_dist = topmost[0] # Distance to top edge (row index) |
| 360 | + bottom_dist = height - 1 - bottommost[0] # Distance to bottom edge |
| 361 | + |
| 362 | + # Return the minimum distance to an edge |
| 363 | + return min(top_dist, bottom_dist), min(left_dist, right_dist) |
317 | 364 |
|
318 | 365 | def blurring_mask_2d_from( |
319 | 366 | mask_2d: np.ndarray, kernel_shape_native: Tuple[int, int] |
@@ -350,19 +397,26 @@ def blurring_mask_2d_from( |
350 | 397 |
|
351 | 398 | """ |
352 | 399 |
|
353 | | - # Create a (3, 3) kernel of ones |
| 400 | + y_distance, x_distance = min_false_distance_to_edge(mask_2d) |
| 401 | + |
| 402 | + y_kernel_distance = (kernel_shape_native[0]) // 2 |
| 403 | + x_kernel_distance = (kernel_shape_native[1]) // 2 |
| 404 | + |
| 405 | + if (y_distance < y_kernel_distance) or (x_distance < x_kernel_distance): |
| 406 | + |
| 407 | + raise exc.MaskException( |
| 408 | + "The input mask is too small for the kernel shape. " |
| 409 | + "Please pad the mask before computing the blurring mask." |
| 410 | + ) |
| 411 | + |
354 | 412 | kernel = np.ones(kernel_shape_native, dtype=np.uint8) |
355 | 413 |
|
356 | | - # Convolve the mask with the kernel, applying logical AND to maintain 'True' regions |
357 | 414 | convolved_mask = convolve(mask_2d.astype(np.uint8), kernel, mode="reflect", cval=0) |
358 | 415 |
|
359 | | - # We want to return the mask where the convolved value is the full kernel size (i.e., 9 for a 3x3 kernel) |
360 | 416 | result_mask = convolved_mask == np.prod(kernel_shape_native) |
361 | 417 |
|
362 | 418 | blurring_mask = ~mask_2d + result_mask |
363 | 419 |
|
364 | | - print(blurring_mask * convolved_mask) |
365 | | - |
366 | 420 | return blurring_mask |
367 | 421 |
|
368 | 422 |
|
|
0 commit comments