spacr.qt.annotate_engine
Pure-Python backend for the Qt annotate screen.
The image-processing pipeline (normalize / channel-filter / outline / colored border) and the SQLite-backed page fetch + background save worker are all Tk-free. The Qt screen wraps this with a QWidget UI.
Semantics mirror spacr.gui_elements.AnnotateApp so annotations made in either GUI are read/written the same way from the same measurements/measurements.db.
Module Contents
- spacr.qt.annotate_engine.label_to_hex(val: int | None) str | None[source]
Map an annotation value to a hex border color.
None / 0 / non-int -> None (no border). 1 -> blue (#4A9EFF-ish), 2 -> red, 3+ -> golden-ratio hue rotation.
- spacr.qt.annotate_engine.normalize_pil(img: PIL.Image.Image, percentiles: Tuple[float, float] = (1.0, 99.0), normalize_channels: Iterable[str] | None = None) PIL.Image.Image[source]
Normalize the given PIL image per-channel using percentile stretch.
If normalize_channels is None or empty, the image is returned unchanged (aside from clipping to 8-bit range).
- spacr.qt.annotate_engine.filter_channels_pil(img: PIL.Image.Image, channels: Iterable[str] | None = None) PIL.Image.Image[source]
Zero out channels not present in channels (e.g. [‘r’,’g’]).
- spacr.qt.annotate_engine.outline_image(base_img: PIL.Image.Image, full_img: PIL.Image.Image, outline_channels: Iterable[str] | None = None, edge_sigma: float = 1.0, edge_thickness: float = 1.0, edge_transparency: float = 100.0, edge_image: bool = False, outline_threshold_factor: float = 1.0, object_size: Tuple[int, int] = (0, 0)) PIL.Image.Image[source]
Overlay per-channel object outlines on base_img.
Mirrors AnnotateApp.outline_image (Tk) semantics: for every channel in outline_channels, compute an Otsu-thresholded foreground mask on the corresponding channel of full_img, extract the boundary, optionally dilate it, then alpha-blend it over the channel in base_img with edge_transparency/100 opacity. Peak-normalized so thin edges stay visible.
- spacr.qt.annotate_engine.add_colored_border(img: PIL.Image.Image, width: int, color: str) PIL.Image.Image[source]
Return img with an inset colored border of width px.
- class spacr.qt.annotate_engine.AnnotateSettings[source]
Every knob the Annotate screen exposes, packed into one dataclass.
Sensible defaults let callers instantiate
AnnotateSettings()and override just the handful of fields they care about.
- spacr.qt.annotate_engine.ensure_annotation_column(db_path: str, column: str) None[source]
Add column INTEGER to png_list if missing and index png_path.
- spacr.qt.annotate_engine.count_rows(db_path: str, image_type: str | None = None) int[source]
Return the number of
png_listrows, optionally filtered byimage_type.- Parameters:
db_path – path to
measurements.db; missing files count as 0.image_type – optional substring to filter
png_pathon.
- spacr.qt.annotate_engine.fetch_page(db_path: str, annotation_column: str, offset: int, page_size: int, image_type: str | None = None) List[Tuple[str, int | None]][source]
Read one page of (png_path, annotation) rows in insertion order.
- spacr.qt.annotate_engine.fetch_filtered_paths(db_path: str, annotation_column: str, measurements: List[str], thresholds: List[float], directions: List[str], image_type: str | None = None) List[Tuple[str, int | None]][source]
Return ALL (png_path, annotation) rows matching every one of the measurement/threshold/direction triples.
Rows come from a merge of png_list with the measurement tables (via spacr.io._read_and_join_tables) — same code path as the Tk app — filtered on png_path substring when image_type is given. Callers paginate the returned list themselves.
- spacr.qt.annotate_engine.class_counts(db_path: str, annotation_column: str) List[Tuple[int, int]][source]
Return sorted list of (class_value, count) for annotated rows.
- spacr.qt.annotate_engine.clear_column(db_path: str, annotation_column: str) None[source]
Null every value in
annotation_columnofpng_list.- Parameters:
db_path – path to
measurements.db; missing files are ignored.annotation_column – column to reset.
- spacr.qt.annotate_engine.find_last_annotated_offset(db_path: str, annotation_column: str, page_size: int, image_type: str | None = None) int | None[source]
Return the page-aligned offset of the last annotated row, or None.