From d93c8d97b34c9c668fd5c59bab036fdaa976e55c Mon Sep 17 00:00:00 2001 From: dev Date: Sat, 28 Feb 2026 10:06:15 +0000 Subject: [PATCH] docs: add architecture reference --- docs/architecture.md | 134 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 docs/architecture.md diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..1233bda --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,134 @@ +# Architecture + +## Overview + +ScanSlicer is a Qt desktop app split into UI mixins, controller mixins, canvas subsystems, and image-processing/autotune engines. + +Top-level startup path: + +1. `scanslicer.entry:main` +2. Backend/environment resolution and validation +3. `scanslicer.main:run_app` +4. `QtScanSlicer` window composition + +## Module Map + +- `scanslicer/entry.py` + - CLI parsing + - Wayland/X11 backend selection + - Qt platform environment configuration +- `scanslicer/main.py` + - `QtScanSlicer` main window lifecycle + - Theme handling and app icon resolution + - App bootstrap (`run_app`) +- `scanslicer/controller*.py` + - UI action handlers split by responsibility +- `scanslicer/ui_builders*.py` + - Widget construction for control panel, preview panel, and shared UI helpers +- `scanslicer/canvas*.py` + - Interactive image canvas for box display/editing +- `scanslicer/autoslicer.py` + - Detection/export engine wrapper +- `scanslicer/autoslicer_detection.py` + - Detection pipelines and contour-to-box extraction +- `scanslicer/autoslicer_feedback.py` + - Auto-tune profiles, candidate scoring, and feedback persistence +- `scanslicer/params.py` + - Parameter model, defaults, and user presets +- `scanslicer/slices.py` + - Box geometry model and polygon IoU helper + +## UI Composition + +`QtScanSlicer` inherits: + +- `ScanSlicerUiBuilderMixin` (UI construction) +- `ScanSlicerControllerMixin` (behavior) + +Controller mixin composition: + +- `ScanSlicerStatusMixin` (status/logging/busy state) +- `ScanSlicerCanvasActionsMixin` (box operations and preview toggles) +- `ScanSlicerDetectionMixin` (worker orchestration) +- `ScanSlicerImageIOMixin` (directory/image loading and save/export) +- `ScanSlicerParamsMixin` (parameter/default/preset/autotune interactions) + +## Detection Execution Flow + +1. User action triggers `update_preview()`. +2. Detection starts in `DetectionTask` (`QRunnable`) on `QThreadPool` (single worker). +3. Worker runs `Autoslicer.autodetect_slices(...)`. +4. On completion: + - Cache normal preview image + - Cache filter preview image + - Update canvas image + - Merge/update boxes +5. Toolbar status and box state are refreshed. + +Key properties: + +- One detection worker at a time. +- Busy state disables controls during processing. +- Task IDs prevent stale callbacks from old tasks mutating UI. + +## Auto-Tune Execution Flow + +1. User clicks `Auto-tune`. +2. `AutotuneTask` runs in the same single-thread pool. +3. `autotune_for_current_image()`: + - Builds candidate parameter sets + - Ranks by current-image + prior feedback similarity + - Coarse pass on downscaled image (`fast_mode=True`) + - Fine pass on top finalists + - Applies best candidate to parameter model +4. UI controls sync from model and detection re-runs. + +## Canvas System + +- `QtSlicingCanvas` = interaction + rendering + state mixins +- Stores: + - image and zoom/pan state + - list of `PhotoSlice` objects + - active slice index + - drag modes (corner, side, rotation, box drag, panning) +- Emits `active_slice_changed` signal to keep toolbar state synchronized. + +## Geometry Model + +`PhotoSlice` stores 4-point quadrilateral and flags: + +- `locked` +- `side_handles_enabled` + +It supports: + +- top-left normalization and winding correction +- rectangle detection (`is_perfect_rectangle`) +- squarize while preserving tilt +- reset to axis-aligned orientation + +## Persistence Model + +Paths are runtime-dependent (host vs container), with environment overrides: + +- Defaults JSON +- Presets JSON +- Auto-tune feedback JSON +- Session status log + +Persistence writes are performed through explicit actions (save defaults/preset, save slices with feedback, status updates). + +## Export Pipeline + +For each locked box: + +1. Compute output width/height from opposing edge lengths. +2. Build perspective transform from box quad to rectangle. +3. Warp source image with `cv2.warpPerspective`. +4. Save with format-specific encoding params. + +## Packaging Surfaces + +- Python package/CLI (`pyproject.toml`, script `scanslicer`) +- Docker runtime (`Dockerfile`, `docker-compose.yml`) +- AppImage (`packaging/appimage/`)