Files
oko_public/bots_readme.md
T
2026-09-09 21:44:05 -05:00

7.2 KiB
Raw Blame History

Bots Readme — Motion Detection (mofin) Pipeline Addition

Overview

Added a motion detection stage (mofin) between runCam and terp in the video surveillance pipeline.

Old Pipeline

runCam ──TCP──▶ terp ──TCP──▶ coordinator

New Pipeline

runCam ──TCP──▶ mofin ──TCP──▶ terp ──TCP──▶ coordinator
                      └──TCP──▶ coordinator (no-motion clips)

mofin runs pixel-level motion detection on each clip. Clips with motion are forwarded to terp for classification (Haar cascade object detection). Clips without motion are sent directly to coordinator for storage, bypassing classification.


Files Created

frame/motion.go

Contains motion detection types and methods in the frame package.

Comparison struct:

type Comparison struct {
    Guid1, Guid2  []byte
    PixelsChanged int
    Threshold     uint8
}

Stores the result of comparing two adjacent frames in a clip — their GUIDs, how many pixels changed, and the pixel-value threshold used.

(*Frame).compareTo(next *Frame, threshold uint8) (int, error):

  • Converts both frames to gocv.Mat via ToMat()
  • Computes AbsDiff between the two Mats
  • Converts to grayscale if multi-channel (CvtColor)
  • Applies Threshold (pixel values above threshold count as changed)
  • Returns CountNonZero (number of changed pixels) or (0, error) on failure

(*Clip).CountChangedPixels(threshold uint8):

  • Iterates over adjacent frame pairs in c.PixelMats
  • For each pair, creates lightweight Frame objects from the clip's metadata and calls compareTo
  • Logs any error returned by compareTo (avoiding writing to ephemeral Frame copies)
  • Appends a Comparison entry to c.Comparisons

mofin/main.go

A new pipeline binary that:

Flag Default Purpose
-listen :8083 TCP address to receive clips from runCam
-terp localhost:8081 Forward address for clips with motion
-coordinator localhost:8082 Forward address for clips without motion
-threshold 5000 Minimum PixelsChanged to consider motion present
-passphrase "" Decryption/re-encryption passphrase (mirrors terp pattern)

Concurrency: Clips are processed in parallel — each incoming clip gets its own goroutine (tracked by procWg). On shutdown, the listener is closed, in-flight decode goroutines drain via acceptWg, clipChan is closed, and procWg.Wait() blocks until all processing finishes before exiting.

processClip flow:

  1. If passphrase is set, decrypt each frame's PixelBytes in-place via Sublimate + Decrypt
  2. Call clip.CountChangedPixels(30) — pixel-value sensitivity of 30
  3. Check if any Comparison.PixelsChanged >= threshold flag
  4. Re-encrypt if passphrase was set
  5. Forward to terp address (motion) or coordinator address (no motion)

mofin/go.mod

Standard module setup with replace frame => ../frame (same pattern as runCam, terp, coordinator).


Files Modified

frame/frame.go

  • Added Errors []string field to Frame — stores descriptive pipeline errors for backend review
  • Added Comparisons []Comparison field to Clip — stores pairwise motion comparison results
  • Removed a stale duplicate Detect method declaration at end of file

runCam/main.go

  • Renamed -terp flag to -mofin (default localhost:8083)
  • Updated all internal references from terpAddrmofinAddr in main(), rebalance(), and runCamera()

config.yaml

Added mofin1 node between cam1 and terp1:

- name: "mofin1"
  binary: "mofin"
  flags:
    listen: ":8083"
    terp: "localhost:8081"
    coordinator: "localhost:8082"
    threshold: 5000

Also updated cam1 to point mofin: "localhost:8083" instead of terp: "localhost:8081".


Tests

frame/frame_test.go — 19 tests

Test What it covers
TestToMat_Roundtrip ToMat() returns an identical Mat from Frame data
TestToMat_NonNilResult ToMat() succeeds with valid 2×2 grayscale data
TestToMat_EmptyBytes ToMat() errors on zero-size buffer
TestEncryptDecrypt_Roundtrip Encrypt then decrypt with same passphrase restores original bytes
TestEncryptDecrypt_WrongPassphrase Decrypt with wrong passphrase fails
TestEncryptDecrypt_EmptyBytes Encrypt/Decrypt on nil PixelBytes is a no-op
TestDecrypt_TooShort Decrypt on truncated data fails
TestEncrypt_UniqueSaltPerCall Two encryptions of same data produce different ciphertexts
TestSublimate_Basic Clip.Sublimate() produces correct Frame count, metadata, GUIDs, timestamps
TestSublimate_EmptyClip Empty clip produces zero frames
TestSublimate_DetectionsCarryOver Frame detections are correctly mapped from Clip
TestCheckLenCorrelations_Match Equal-length slices return true
TestCheckLenCorrelations_PixelMatsGuidsMismatch Mismatched PixelMats/Guids returns false
TestCheckLenCorrelations_TimestampsMismatch Mismatched Timestamps returns false
TestCheckLenCorrelations_Empty Empty clip returns true
TestClipSend Send/Receive roundtrip over TCP preserves Clip data
TestClipSend_InvalidAddress Send to unreachable address returns error
TestFrameFields_ZeroValues Zero-value Frame has nil Errors, nil Detections
TestClipFields_ZeroValues Zero-value Clip has nil Comparisons

frame/motion_test.go — 12 tests

Test What it covers
TestCompareTo_IdenticalFrames Two identical frames → 0 changed pixels
TestCompareTo_AllPixelsChanged 0→255 → all 16 pixels of 4×4 detected as changed
TestCompareTo_PartialChange 3 of 16 pixels differing → exactly 3 counted
TestCompareTo_ThresholdFiltersSmallDiffs Pixels with diff > threshold counted; diff ≤ threshold ignored
TestCompareTo_MultiChannel Multi-channel (BGR) → grayscale conversion works, changed pixels detected
TestCompareTo_DimensionMismatch Different sizes return error
TestCompareTo_ChannelMismatch Different channel counts return error
TestCompareTo_IdenticalPixelData Same pixel bytes → 0 changed (no crash with equal data)
TestCountChangedPixels_Basic 3 frames → 2 comparisons, correct pixel counts
TestCountChangedPixels_SingleFrame 1 frame → 0 comparisons
TestCountChangedPixels_EmptyClip 0 frames → 0 comparisons
TestCountChangedPixels_ResetsComparisons Pre-existing Comparisons are cleared before run
TestCountChangedPixels_ThresholdParameter Pixel-value threshold correctly filters small diffs
TestComparison_Fields Comparison struct fields store/retrieve correctly

frame/utils_test.go — 16 tests

Camera-dependent tests skip with -short flag. Pure-logic tests (empty range, negative index, struct fields, Sscanf) always run.

Running

go test -short ./...   # fast (skips camera hardware scans)
go test ./...          # full suite (attempts V4L device probes)

All 42+ tests pass. Pre-existing ScanCams tests preserved and corrected.

Build Verification

All five modules pass go build ./... and go vet ./...:

  • frame/
  • runCam/
  • mofin/
  • terp/
  • coordinator/