134 lines
4 KiB
Markdown
134 lines
4 KiB
Markdown
# 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/`)
|