spacr.ops_compose¶
The canonical nuclear map, composed one window at a time.
ops_stitch solves where every tile sits and
deliberately does not hold the pixels – well A1 is 26,855 x 26,865, which is
1.4 GB as uint16 for ONE channel, and every later phase would read through it.
This module composes the same well WINDOW BY WINDOW instead, which is what
segmentation wants anyway: segment once, on the composite, a window at a
time.
THE MEMORY PROBLEM AND THE SEGMENTATION PLAN HAVE THE SAME ANSWER. A window that a segmenter can hold is also a window a composer can build, so nothing ever materialises the whole canvas. The join key the object numbering needs – a plate-level object number in the WELL frame – survives because every window carries its own offset into that frame.
WHY AVERAGE THE OVERLAPS AT ALL. PART 15 measured it: the gain is about 1.15x on the exact channel segmentation runs on, not the 3.3x an earlier draft claimed from averaging across cycles. There is only one DAPI acquisition, so the eleven-sample argument does not apply – what is left is the raster’s own 14% overlap, where two tiles saw the same nuclei twice. 1.15x is worth having and is not worth overstating, which is why the number is here rather than the adjective.
Exceptions¶
Raised when a window cannot be composed, with the reason. |
Classes¶
A rectangle of the well frame, and where it sits in it. |
Functions¶
|
Average every tile that overlaps |
|
The noise gain averaging bought, over pixels a tile actually reached. |
|
Tile a canvas into overlapping windows, in raster order. |
Module Contents¶
- exception spacr.ops_compose.ComposeError[source]¶
Bases:
ValueErrorRaised when a window cannot be composed, with the reason.
Initialize self. See help(type(self)) for accurate signature.
- class spacr.ops_compose.Window[source]¶
A rectangle of the well frame, and where it sits in it.
- Parameters:
top – first row in well pixels.
left – first column in well pixels.
height – rows.
width – columns.
- spacr.ops_compose.compose_window(window: Window, placements: Mapping[int, Tuple[float, float]], read_tile: Callable[[int], numpy.ndarray], *, tile_shape: Tuple[int, int] | None = None, dtype: type = np.float32) Tuple[numpy.ndarray, numpy.ndarray][source]¶
Average every tile that overlaps
windowinto one image.AVERAGED, NOT LAST-WRITER-WINS. A tile pasted over its neighbour keeps a seam exactly where two tiles disagree, and a seam is a gradient a segmenter will happily find an edge in. Averaging removes the seam AND is where the 1.15x comes from; they are the same operation.
- Parameters:
window – the rectangle of the well frame to build.
placements –
site -> (y, x)from the solve, in well pixels.read_tile – called with a site number, returns that tile. Called ONLY for tiles that actually touch the window, so a well of 333 tiles costs a handful of reads per window rather than 333.
tile_shape –
(height, width); read from the first tile when omitted.
- Returns:
(image, coverage)– the averaged window and how many tiles contributed to each pixel. COVERAGE IS RETURNED RATHER THAN DISCARDED because a pixel no tile reached is not a black pixel, and only the count tells them apart.
- spacr.ops_compose.overlap_gain(count: numpy.ndarray) float[source]¶
The noise gain averaging bought, over pixels a tile actually reached.
sqrt of the mean coverage: averaging n independent samples of one signal divides the noise by sqrt(n). Reported over COVERED pixels only, because a well’s corners are reached by one tile and including the uncovered background would report a gain for pixels nothing measured.
PART 15 measured 1.15x for well A1 at a 14% raster overlap. A composer that reports much more than that on the same geometry is averaging something twice.
- Parameters:
count – the coverage array from
compose_window().
- spacr.ops_compose.windows_over(canvas: Tuple[int, int], size: int = 4096, overlap: int = 256) Iterator[Window][source]¶
Tile a canvas into overlapping windows, in raster order.
THE WINDOWS OVERLAP ON PURPOSE, and sewing is the reason: an object straddling a window boundary is one object, and it can only be matched across the seam if both windows saw all of it. The overlap has to exceed the largest object, not merely touch.
- Parameters:
canvas –
(height, width)of the well frame.size – window edge in pixels.
overlap – how much neighbouring windows share.
- Raises:
ComposeError – when the overlap is not smaller than the window, which would make the stride zero and the iteration infinite.