|
19 | 19 | logger = logging.getLogger("atlas_patch.extraction_service") |
20 | 20 |
|
21 | 21 |
|
| 22 | +def _global_lattice_start(start: int, *, step: int, patch_size: int) -> int: |
| 23 | + """Snap a contour bound onto the slide-global lattice anchored at (0, 0).""" |
| 24 | + return max(0, ((int(start) - int(patch_size)) // int(step)) * int(step)) |
| 25 | + |
| 26 | + |
22 | 27 | class PatchExtractionService(ExtractionService): |
23 | 28 | """Extracts patch coordinates (and optional images) from WSIs given a tissue mask.""" |
24 | 29 |
|
@@ -93,8 +98,10 @@ def _iter_patch_entries( |
93 | 98 | for contour, holes in zip(tissue_contours, holes_contours): |
94 | 99 | x0, y0, ww, hh = cv2.boundingRect(contour) |
95 | 100 | stop_x, stop_y = x0 + ww, y0 + hh |
96 | | - for y in range(y0, stop_y, step_src): |
97 | | - for x in range(x0, stop_x, step_src): |
| 101 | + start_x = _global_lattice_start(x0, step=step_src, patch_size=patch_size_src) |
| 102 | + start_y = _global_lattice_start(y0, step=step_src, patch_size=patch_size_src) |
| 103 | + for y in range(start_y, stop_y, step_src): |
| 104 | + for x in range(start_x, stop_x, step_src): |
98 | 105 | if not self._in_tissue((x, y), contour, holes, patch_size=patch_size_src): |
99 | 106 | continue |
100 | 107 |
|
|
0 commit comments