OpenRoadCode Computer Vision

Source: controllers/computer_vision/README.md

The computer-vision layer consumes CameraFrame objects and publishes presentation-neutral object detections. Camera ownership remains in hardware_io.camera; perception does not open video devices directly.

Debian/Ubuntu setup

Use the project setup script rather than installing dependencies by hand:

./development/debian/setup_camera_perception.sh

The script installs the Linux camera tooling (v4l-utils, OpenCV, Python venv support), finds the active OpenRoadCode virtual environment or the repository venv, creates venv if needed, and installs Ultralytics there. It finishes with import checks and reports whether /dev/video0 is present.

Activate the environment when needed:

source venv/bin/activate

VM perception preview

Run the live preview with the default USB camera:

python -m controllers.computer_vision.component_test.perception_preview

The default configuration uses /dev/video0, 1920x1080 MJPEG capture at 30 FPS, the small yolo11n.pt model, 640-pixel inference input, and a confidence threshold of 0.35. Ultralytics may download the model weights on the first run.

The preview displays detections for road-relevant COCO classes: person, bicycle, motorcycle, car, bus, and truck. It also displays camera FPS, AI FPS, inference latency, and the current object count. Press q or Escape to exit.

Useful overrides:

python -m controllers.computer_vision.component_test.perception_preview \
  --device /dev/video0 \
  --model yolo11n.pt \
  --confidence 0.40 \
  --imgsz 640

Concurrency model

PerceptionWorker runs inference on a background thread. Camera capture and preview remain on the caller’s thread. Submitting a newer frame replaces any older pending frame that inference has not started processing, so the detector prefers fresh road-scene data over building latency in a frame queue.

Bounding boxes are normalized to [0, 1], allowing inference resolution and preview resolution to differ without coupling the UI to model input geometry.

orcUi VISION evaluation screen

The integrated orcUi shell exposes an isolated VISION navigation destination for camera/perception evaluation. It intentionally does not feed HOME, NAVIGATION, VEHICLE, or other screens while the feature is being developed.

Start orcUi normally:

python -m apps.orcUi

Select VISION from the side navigation. Entering the screen sends a semantic activation request to VisionController. The controller opens /dev/video0, starts YOLO inference, and publishes immutable VisionUiState snapshots with RGB image data and normalized object overlays. Leaving the screen sends a deactivation request; the controller invalidates queued callbacks, stops inference, restores daytime camera defaults, and releases the camera.

The Tk screen depends only on contracts under ui/vision. It renders complete state snapshots and emits explicit target-state requests for camera mode and AI enablement. Camera, V4L2, OpenCV, YOLO, ByteTrack, worker, and lifecycle ownership remain outside the widget. State uses seconds, hertz, normalized luminance, and normalized image coordinates; the frontend owns display labels and conversions such as seconds to milliseconds.

The screen provides three processing profiles:

  • AUTO: select low-light enhancement when mean scene luminance is low.
  • DAY: show and analyze the unmodified camera frame.
  • LOW LIGHT: apply CLAHE to the LAB lightness channel before preview and inference.

The VISION screen now combines software and hardware profiles. DAY restores the camera’s conservative auto-exposure profile. LOW LIGHT keeps the camera in its supported auto-exposure mode, applies modest gain/gamma/backlight adjustment, and then applies CLAHE. The validated camera advertises absolute exposure but reports that control inactive and rejects writes while streaming, so ORC does not force it. AUTO uses scene luminance with hysteresis: it enters low-light below a mean luma of 65 and returns to day above 85, avoiding rapid mode flapping near the threshold.

The VISION status panel reports the measured scene luminance and the active hardware profile so profile transitions can be evaluated directly on the VM before road testing.

Persistent object tracking

VISION passes YOLO detections through an ObjectTrackerIf abstraction backed initially by ByteTrack. Detection remains independent of tracking: YOLO reports frame-local observations while the tracker assigns persistent identities over time.

The VISION overlay renders tracked objects as LABEL #ID confidence age, and the status panel reports active track count and oldest-track age. YOLO uses a lower candidate threshold in VISION so ByteTrack can use weaker detections to maintain an existing identity through brief confidence drops.

Tracking state is owned by the perception worker and reset whenever VISION is started, so IDs are session-local rather than permanent object identities. Session generations prevent a frame or inference completion queued by a hidden or closed session from updating the current screen.

Supervision 0.28 deprecated its bundled ByteTrack class in favor of ByteTrackTracker from the separate trackers distribution. ORC narrowly suppresses that specific warning while retaining the current tested adapter. Moving to the replacement requires an explicit dependency and adapter migration before Supervision 0.31 removes the bundled class.