# nicholaskajoh/ivy architecture

> Architecture diagram of the GitHub repository nicholaskajoh/ivy, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-06-15). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/nicholaskajoh/ivy
- Repository: https://github.com/nicholaskajoh/ivy

## Overview

Ivy is a single-process Python video analytics pipeline for object counting. The architecture is centered on reading frames from a video source, detecting objects, tracking them across frames, and incrementing counts when tracked objects cross a configured region.

1. **Runtime entrypoint and orchestration**
   - `main.py` is the application entrypoint.
   - It likely wires together configuration, detector selection, video/job setup, the tracker, the counter, and the debug UI.
   - `ObjectCounter.py` appears to be the top-level counting workflow/class that coordinates per-frame processing.

2. **Core processing pipeline**
   - The main data flow is: **video/frame source → detector → detection post-processing → tracker → counter → logs/debug output**.
   - Each frame is analyzed independently, but object identity is preserved across frames by tracking.
   - The system is designed around continuous streaming rather than batch processing.

3. **Detector abstraction boundary**
   - `detectors/detector.py` defines the detector interface/contract.
   - The concrete detector implementations are:
     - `detectors/yolo.py`
     - `detectors/tfoda.py`
     - `detectors/detectron2.py`
     - `detectors/haarcascade.py`
   - This is the main pluggable boundary in the repo: detection backend can be swapped without changing downstream tracking/counting logic.

4. **Detection backends and external ML dependencies**
   - YOLO, TensorFlow Object Detection API, Detectron2, and Haar cascades are supported.
   - These are not just libraries; they materially change deployment/runtime requirements.
   - The README indicates optional framework installation depending on detector choice, so the repository supports multiple ML stacks under a common interface.

5. **Tracking subsystem**
   - `tracker.py` maintains object continuity across frames.
   - Its role is to transform per-frame detections into persistent tracked objects, which is necessary for stable counting and for avoiding double-counting.
   - Tracking is a separate concern from detection, which keeps detector output simple and lets the counting logic operate on identities rather than raw boxes.

6. **Counting and object state**
   - `counter.py` implements the counting rules.
   - It likely consumes tracked objects and decides when an object has entered/exited a region of interest or crossed a counting boundary.
   - `util/object_info.py` and `util/blob.py` likely carry object state, geometry, and per-object metadata used by the counter and tracker.

7. **Spatial and geometry utilities**
   - `util/bounding_box.py` handles box math and intersection/centroid logic.
   - `util/detection_roi.py` likely defines the count line or region-of-interest boundary.
   - `util/image.py` probably provides frame/image preprocessing and annotation helpers.
   - These utilities form the geometric layer between raw detector output and higher-level counting decisions.

8. **Debugging and visualization**
   - `util/debugger.py` and the README’s debug mode indicate an interactive visualization layer.
   - The app can display the live processing window, pause/play, capture screenshots, and log clicked coordinates.
   - This is an important operational boundary: it does not affect counting logic directly, but it is essential for tuning and validation.

9. **Configuration and job model**
   - `settings.py`, `.env.example`, and `util/job.py` suggest runtime configuration is driven by environment variables plus a job/config object.
   - The job layer probably encapsulates video source, detector choice, model paths, thresholds, and output options.
   - This keeps deployment settings separate from the processing code.

10. **Logging and observability**
   - `util/logger.py` centralizes logging behavior.
   - The README explicitly mentions analyzing logs, so logs are a first-class output of the application.
   - Logging likely captures counts, tracker events, detector selection, and debug/runtime issues.

11. **Input data and model assets**
   - The `data/` directory is the local asset boundary for sample videos, detector weights, and demo content.
   - The README’s demo package unpacks into `data`, so runtime assets are expected to live there rather than being fetched dynamically.

12. **Testing boundary**
   - `tests/` covers utility components such as blobs, bounding boxes, debugger, job, logger, and vehicle/object info.
   - The test suite is focused on deterministic logic rather than model accuracy, which makes sense for a pipeline that depends on external detector frameworks.
   - `pytest.ini` and coverage config show the repo is structured for unit testing of core geometry/state logic.

13. **Deployment and packaging**
   - `Dockerfile` provides containerized execution.
   - `.github/workflows/ivy.yml` indicates CI automation, likely for tests and linting.
   - `requirements.txt`, `.pylintrc`, and `.coveragerc` reinforce that the repo is packaged as a Python application with quality gates.

14. **Architectural summary**
   - Ivy’s main architectural split is between:
     - **perception**: detector backends,
     - **temporal continuity**: tracking,
     - **business logic**: counting,
     - **supporting concerns**: config, logging, debugging, and geometry utilities.
   - The most important diagram boundary is the interface between detector output and tracker/counter input, because that is where a raw CV model becomes a counted object stream.

Main entry points: [`ObjectCounter.py`](https://github.com/nicholaskajoh/ivy/blob/master/ObjectCounter.py) (Counter flow), [`detectors/detector.py`](https://github.com/nicholaskajoh/ivy/blob/master/detectors/detector.py) (Detector API), [`main.py`](https://github.com/nicholaskajoh/ivy/blob/master/main.py) (main.py), [`util/blob.py`](https://github.com/nicholaskajoh/ivy/blob/master/util/blob.py) (Blob)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_runtime["Runtime"]
  node_main["main.py<br/>entrypoint<br/>[main.py]"]
  node_object_counter["Counter flow<br/>workflow<br/>[ObjectCounter.py]"]
end

subgraph group_perception["Perception"]
  node_detector_iface["Detector API<br/>contract<br/>[detector.py]"]
  node_yolo["YOLO<br/>detector backend<br/>[yolo.py]"]
  node_tfoda["TF-ODA<br/>detector backend<br/>[tfoda.py]"]
  node_detectron2["Detectron2<br/>detector backend<br/>[detectron2.py]"]
  node_haarcascade["Haar cascade<br/>detector backend<br/>[haarcascade.py]"]
end

subgraph group_core["Core Flow"]
  node_blob["Blob<br/>object state<br/>[blob.py]"]
  node_object_info["Object info<br/>object state<br/>[object_info.py]"]
  node_tracker["Tracker<br/>temporal tracking<br/>[tracker.py]"]
  node_counter["Counter<br/>counting rules<br/>[counter.py]"]
end

subgraph group_support["Support"]
  node_settings["Settings<br/>config<br/>[settings.py]"]
  node_job["Job<br/>runtime config<br/>[job.py]"]
  node_logger["Logger<br/>observability<br/>[logger.py]"]
  node_debugger["Debugger<br/>ui overlay<br/>[debugger.py]"]
  node_image["Image utils<br/>image ops<br/>[image.py]"]
  node_roi{{"ROI<br/>geometry<br/>[detection_roi.py]"}}
  node_bbox{{"Boxes<br/>geometry<br/>[bounding_box.py]"}}
  node_data[("Data<br/>assets")]
end

node_main -->|"loads"| node_settings
node_main -->|"builds"| node_job
node_main -->|"starts"| node_object_counter
node_object_counter -->|"uses"| node_detector_iface
node_object_counter -->|"feeds"| node_tracker
node_object_counter -->|"drives"| node_counter
node_object_counter -->|"renders"| node_debugger
node_object_counter -->|"logs"| node_logger
node_object_counter -->|"annotates"| node_image
node_object_counter -->|"applies"| node_roi
node_object_counter -->|"reads"| node_data
node_tracker -->|"creates"| node_blob
node_tracker -->|"updates"| node_object_info
node_counter -->|"checks"| node_roi
node_counter -->|"compares"| node_bbox
node_blob -->|"contains"| node_bbox
node_blob -->|"shares"| node_object_info
node_detector_iface -.->|"implemented by"| node_yolo
node_detector_iface -.->|"implemented by"| node_tfoda
node_detector_iface -.->|"implemented by"| node_detectron2
node_detector_iface -.->|"implemented by"| node_haarcascade
node_debugger -->|"emits"| node_logger
node_settings -->|"configures"| node_job

click node_main "https://github.com/nicholaskajoh/ivy/blob/master/main.py"
click node_object_counter "https://github.com/nicholaskajoh/ivy/blob/master/ObjectCounter.py"
click node_settings "https://github.com/nicholaskajoh/ivy/blob/master/settings.py"
click node_job "https://github.com/nicholaskajoh/ivy/blob/master/util/job.py"
click node_logger "https://github.com/nicholaskajoh/ivy/blob/master/util/logger.py"
click node_debugger "https://github.com/nicholaskajoh/ivy/blob/master/util/debugger.py"
click node_image "https://github.com/nicholaskajoh/ivy/blob/master/util/image.py"
click node_roi "https://github.com/nicholaskajoh/ivy/blob/master/util/detection_roi.py"
click node_bbox "https://github.com/nicholaskajoh/ivy/blob/master/util/bounding_box.py"
click node_blob "https://github.com/nicholaskajoh/ivy/blob/master/util/blob.py"
click node_object_info "https://github.com/nicholaskajoh/ivy/blob/master/util/object_info.py"
click node_tracker "https://github.com/nicholaskajoh/ivy/blob/master/tracker.py"
click node_counter "https://github.com/nicholaskajoh/ivy/blob/master/counter.py"
click node_detector_iface "https://github.com/nicholaskajoh/ivy/blob/master/detectors/detector.py"
click node_yolo "https://github.com/nicholaskajoh/ivy/blob/master/detectors/yolo.py"
click node_tfoda "https://github.com/nicholaskajoh/ivy/blob/master/detectors/tfoda.py"
click node_detectron2 "https://github.com/nicholaskajoh/ivy/blob/master/detectors/detectron2.py"
click node_haarcascade "https://github.com/nicholaskajoh/ivy/blob/master/detectors/haarcascade.py"
click node_data "https://github.com/nicholaskajoh/ivy/tree/master/data"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_main,node_object_counter toneBlue
class node_detector_iface,node_yolo,node_tfoda,node_detectron2,node_haarcascade toneAmber
class node_blob,node_object_info,node_tracker,node_counter toneMint
class node_settings,node_job,node_logger,node_debugger,node_image,node_roi,node_bbox,node_data toneRose
```

## Components

### Runtime

Entrypoint and orchestration for the single-process pipeline

- [main.py](https://github.com/nicholaskajoh/ivy/blob/master/main.py): entrypoint · Application entrypoint · `main.py`
- [Counter flow](https://github.com/nicholaskajoh/ivy/blob/master/ObjectCounter.py): workflow · Top-level per-frame orchestration · `ObjectCounter.py`

### Perception

Detector backends and frame-to-detection boundary

- [Detector API](https://github.com/nicholaskajoh/ivy/blob/master/detectors/detector.py): contract · Common detector interface and abstraction boundary · `detectors/detector.py`
- [YOLO](https://github.com/nicholaskajoh/ivy/blob/master/detectors/yolo.py): detector backend · YOLO-based object detector · `detectors/yolo.py`
- [TF-ODA](https://github.com/nicholaskajoh/ivy/blob/master/detectors/tfoda.py): detector backend · TensorFlow Object Detection API backend · `detectors/tfoda.py`
- [Detectron2](https://github.com/nicholaskajoh/ivy/blob/master/detectors/detectron2.py): detector backend · Detectron2-based object detector · `detectors/detectron2.py`
- [Haar cascade](https://github.com/nicholaskajoh/ivy/blob/master/detectors/haarcascade.py): detector backend · Classic cascade-based detector · `detectors/haarcascade.py`

### Core Flow

Tracking, counting, and object state

- [Blob](https://github.com/nicholaskajoh/ivy/blob/master/util/blob.py): object state · Per-object geometry and metadata container · `util/blob.py`
- [Object info](https://github.com/nicholaskajoh/ivy/blob/master/util/object_info.py): object state · Persistent object attributes for counting · `util/object_info.py`
- [Tracker](https://github.com/nicholaskajoh/ivy/blob/master/tracker.py): temporal tracking · Maintains object identity across frames · `tracker.py`
- [Counter](https://github.com/nicholaskajoh/ivy/blob/master/counter.py): counting rules · Counts tracked objects crossing the configured region · `counter.py`

### Support

Configuration, logging, utilities, data, and packaging

- [Settings](https://github.com/nicholaskajoh/ivy/blob/master/settings.py): config · Runtime configuration defaults and env wiring · `settings.py`
- [Job](https://github.com/nicholaskajoh/ivy/blob/master/util/job.py): runtime config · Encapsulates run-specific inputs and options · `util/job.py`
- [Logger](https://github.com/nicholaskajoh/ivy/blob/master/util/logger.py): observability · Central logging setup and formatting · `util/logger.py`
- [Debugger](https://github.com/nicholaskajoh/ivy/blob/master/util/debugger.py): ui overlay · Interactive debug display and inspection · `util/debugger.py`
- [Image utils](https://github.com/nicholaskajoh/ivy/blob/master/util/image.py): image ops · Frame preprocessing and annotation helpers · `util/image.py`
- [ROI](https://github.com/nicholaskajoh/ivy/blob/master/util/detection_roi.py): geometry · Counting line or region definition · `util/detection_roi.py`
- [Boxes](https://github.com/nicholaskajoh/ivy/blob/master/util/bounding_box.py): geometry · Bounding box math and intersection logic · `util/bounding_box.py`
- [Data](https://github.com/nicholaskajoh/ivy/tree/master/data): assets · Local sample videos and model assets · `data`

## Connections

- main.py → Settings: loads · Reads runtime configuration
- main.py → Job: builds · Creates the run/job context
- main.py → Counter flow: starts · Launches the counting workflow
- Counter flow → Detector API: uses · Selects a detector through the common contract
- Counter flow → Tracker: feeds · Sends detections into tracking
- Counter flow → Counter: drives · Applies counting rules to tracked objects
- Counter flow → Debugger: renders · Optionally opens debug visualization
- Counter flow → Logger: logs · Emits processing and count events
- Counter flow → Image utils: annotates · Uses image helpers for frame display/output
- Counter flow → ROI: applies · Uses region or line geometry for counting
- Counter flow → Data: reads · Consumes local videos and model assets
- Tracker → Blob: creates · Represents detected objects as blobs
- Tracker → Object info: updates · Maintains per-object state over time
- Counter → ROI: checks · Evaluates crossings against the counting region
- Counter → Boxes: compares · Uses box geometry for movement and overlap
- Blob → Boxes: contains · Stores geometric extent
- Blob → Object info: shares · Carries object metadata across frames
- Detector API → YOLO: implemented by · One concrete detector backend
- Detector API → TF-ODA: implemented by · One concrete detector backend
- Detector API → Detectron2: implemented by · One concrete detector backend
- Detector API → Haar cascade: implemented by · One concrete detector backend
- Debugger → Logger: emits · Records interactive debug actions
- Settings → Job: configures · Job parameters are derived from settings
