Skip to content

bennybeg/AxonVision

Repository files navigation

Axon Vision - Motion Detection Demo

This project implements a simple multi‑process motion detector over a video file using OpenCV.
It is structured into three processes:

  • Streamer - reads frames from a video file and sends them downstream with presentation timestamps.
  • Detector - applies the provided motion‑detection algorithm and outputs bounding boxes.
  • Displayer - renders frames with bounding boxes and plays them back at (approximately) real‑time speed.

Setup

1. Python version

Use Python 3.11 (or another version supported by opencv-python):

python3.11 --version

2. Install dependencies

You can use either Poetry (recommended) or a plain virtual environment with requirements.txt.

Using Poetry

cd /path/to/axon-vision
poetry install

Then run the app with:

poetry run python main.py

Using pip / requirements

Create and activate a virtual environment, then install dependencies:

python3.11 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

Run the app with:

python main.py

3. Configure the input video

The input video path is defined in constants.py:

VIDEO_PATH = "People - 6387.mp4"

Update this constant to point to any local video file you want to process, for example:

VIDEO_PATH = "/absolute/path/to/your_video.mp4"

How it works

Processes and data flow

  • Streamer (in streamer.py)

    • Opens VIDEO_PATH with OpenCV.
    • For each frame, reads both the image and its presentation timestamp in milliseconds (pts_ms) using cv2.CAP_PROP_POS_MSEC.
    • Wraps them in a FramePacket dataclass and pushes it onto a frames_queue.
  • Detector (in detector.py)

    • Runs the provided motion‑detection algorithm:
      • Convert frame to grayscale.
      • Compute absolute difference (absdiff) between the current and previous grayscale frame.
      • Apply a binary threshold.
      • Dilate the thresholded image to connect regions.
      • Find contours and convert them into bounding boxes.
    • Bounding boxes are represented as BoundingBox dataclasses.
    • Produces a DetectionResult (frame, list of bounding boxes, original pts_ms) and puts it onto a results_queue.
  • Displayer (in displayer.py)

    • Reads DetectionResult objects from results_queue.
    • Draws bounding boxes and a timestamp overlay on each frame.
    • Displays the frames in an OpenCV window while trying to match the original video timing.

Inter‑process communication uses multiprocessing.Queue, and a shared stop_event plus SENTINEL values to signal a clean shutdown.

Real‑time playback logic

The key to “real‑time” playback is the pts_ms (presentation timestamp in milliseconds) that comes from OpenCV:

  1. Streamer reads pts_ms for each frame using:

    pts_ms = cap.get(cv2.CAP_PROP_POS_MSEC)

    and passes it along unchanged.

  2. Detector preserves this timestamp and attaches it to each DetectionResult so the display process knows when the frame should appear.

  3. Displayer anchors video time to wall‑clock time on the first frame:

    • When the first DetectionResult arrives, it stores:
      • first_pts_ms – the first frame’s pts_ms.
      • start_wall – the current wall‑clock time from time.perf_counter().
  4. For every subsequent frame with timestamp pts_ms, it computes a target wall‑clock time:

    target = start_wall + (float(pts_ms) - first_pts_ms) / 1000.0
    • (pts_ms - first_pts_ms) / 1000.0 is “how many seconds into the video this frame is, relative to the first frame”.
    • Adding that to start_wall gives “the exact wall‑clock time when this frame should be shown”.
  5. If the display is behind schedule (current time is already past target), the displayer may drop older frames in the queue and use newer ones to catch up, keeping playback closer to real‑time rather than slowly drifting behind.

  6. Otherwise, it sleeps in small increments until time.perf_counter() reaches target, then it renders and shows the frame.

This combination of timestamps and scheduling makes the playback speed match the original video’s timing as closely as possible, even though processing happens across multiple processes.

Controls and exit behavior

  • Press q in the video window to stop the display and signal all processes to shut down.
  • Closing the window also triggers a graceful shutdown.
  • The main process waits on the Displayer process first, then signals the others and joins them with a timeout to ensure a clean exit.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages