# AICAM Intrusion Module (Picamera2 + YOLOv5 ONNX)

## Table of Contents
1. Overview
2. What This Module Does
3. What This Module Explicitly Does *Not* Do
4. Architectural Fit Within AICAM
5. Capture Stack (Why Picamera2)
6. Model Runtime (YOLOv5 ONNX)
7. Boundary Logic
8. Evidence Produced
9. Failure Semantics (The Fog)
10. Why This File Is Hard-Coded
11. Run Commands
12. Boundary Examples (LINE_A / LINE_B)
13. Canonical Use Case
14. Summary

## Overview

The **AICAM Intrusion module** is a **boundary-crossing evidence recorder** designed for Raspberry Pi OS using a CSI camera.

Its purpose is **not** to decide intent, issue alerts, or interpret behavior.

Its purpose is to:

> **Record verifiable evidence when a human crosses a defined boundary.**

This module follows the core AICAM project principle:

> *All you can truly protect is the few feet around you.*

## What This Module Does

- Captures video from a **Raspberry Pi CSI camera** using **Picamera2 / libcamera**
- Runs **YOLOv5 (ONNX)** inference using **onnxruntime (CPU)**
- Detects **persons only** (YOLO class `0`)
- Monitors a **single, explicitly defined boundary line**
- When a person’s **bounding-box center crosses the line**:
  - Saves **preroll + postroll video**
  - Writes **JSONL event records**
  - Preserves model provenance

## What This Module Explicitly Does *Not* Do

No tracking, no alerts, no networking, no cloud calls, no Ultralytics, no `/dev/video*`.

## Run Command

```bash
python3 -u INTRUSIONCAM_PICAMERA2_HARDENED.py
```

---

## Boundary Examples (LINE_A / LINE_B) — Expanded

The intrusion boundary is a **single line segment** defined by two pixel coordinates:

```python
LINE_A = (x1, y1)
LINE_B = (x2, y2)
```

The module triggers when the **center point of a detected person bounding box** crosses from one side of the line to the other.

### Quick coordinate refresher (pixel space)

- `(0, 0)` is the **top-left** of the frame
- `x` increases to the **right**
- `y` increases **down**
- Valid ranges are typically:
  - `0 <= x <= CAM_WIDTH`
  - `0 <= y <= CAM_HEIGHT`

### Example 1: Horizontal “do not cross” line (hallway midline)

Use when the camera is facing a hallway and you want to record when someone passes the midpoint depth.

```python
LINE_A = (0, CAM_HEIGHT // 2)
LINE_B = (CAM_WIDTH, CAM_HEIGHT // 2)
```

ASCII sketch:

```
(0,0) +-----------------------------+ (W,0)
      |                             |
      |                             |
      |-----------  LINE  ----------|  y = H/2
      |                             |
      |                             |
(0,H) +-----------------------------+ (W,H)
```

### Example 2: Doorway threshold (horizontal line near bottom)

Use when the camera is inside a room looking toward a doorway and you want to record when someone **steps into the room**.
Place the line near the bottom third of the frame where feet/legs cross reliably.

```python
y = int(CAM_HEIGHT * 0.72)
LINE_A = (0, y)
LINE_B = (CAM_WIDTH, y)
```

Rule of thumb:
- Put the line where **a person’s center** crosses shortly after the threshold.
- If the camera is high and angled down, the “center” crosses earlier than feet.

### Example 3: Doorway at an angle (diagonal threshold line)

Use when the doorway appears diagonal due to camera placement or perspective.
Align the line with the visible door sill or a floor tile seam that matches the threshold.

```python
LINE_A = (int(CAM_WIDTH * 0.20), int(CAM_HEIGHT * 0.78))
LINE_B = (int(CAM_WIDTH * 0.70), int(CAM_HEIGHT * 0.55))
```

ASCII sketch (diagonal line):

```
+-----------------------------+
|                             |
|                             |
|                  B *        |
|               /             |
|            /                |
|       A *                   |
+-----------------------------+
```

### Example 4: Vertical “do not cross” line (left-side entry)

Use when the camera looks across a space and the “entry plane” is left-to-right.

```python
x = int(CAM_WIDTH * 0.30)
LINE_A = (x, 0)
LINE_B = (x, CAM_HEIGHT)
```

### Example 5: Corner cut / stair landing (diagonal guard line)

Use when people round a corner and you want to capture as they enter a new area.

```python
LINE_A = (int(CAM_WIDTH * 0.10), int(CAM_HEIGHT * 0.40))
LINE_B = (int(CAM_WIDTH * 0.90), int(CAM_HEIGHT * 0.90))
```

### Example 6: “Restricted zone” approximation using one line

This module intentionally uses **one boundary** (line) for verifiable semantics.
If you need a “keep out” polygon, approximate it with the most defensible **entry plane**:

- Choose the choke point a person must cross to enter the zone
- Place the line there
- Record evidence on crossing

### How to choose a boundary that behaves well

Use boundaries that satisfy these constraints:

1. **Crossing is unambiguous**  
   Avoid lines that people can walk parallel to for long distances; you want a clean “before/after.”

2. **Crossing happens in a stable part of the image**  
   Prefer floor/threshold areas with less motion blur than upper frame regions.

3. **Avoid edges of frame**  
   If detections partially enter the frame, the center can “jump,” causing noisy crossings.
   Keep the line away from the extreme top/left/right edges when possible.

4. **Keep the line away from the horizon / vanishing point**  
   Far depth regions compress movement; the center point can oscillate with small detection jitter.

### Calibration workflow (practical, fast)

1. Run the module and record a short clip (or use an existing saved clip).
2. Identify two visible, fixed reference points in the scene that represent the desired boundary:
   - door sill endpoints
   - tile seam endpoints
   - edge of rug
3. Measure their pixel coordinates:
   - Use a frame grab + click-to-read coordinates (recommended), or
   - Temporarily print center points and draw overlays in the code (debug mode)

If you do not yet have a coordinate picker, use this simple “guess then refine” method:
- Start with the nearest obvious line (like `y = 0.70 * H` or `x = 0.30 * W`)
- Walk through the boundary once
- Adjust until crossing triggers exactly where you want

### Boundary sanity checks

- If you get **false triggers** when people are near the boundary:
  - move the line away from the area where people linger
  - prefer a choke point (doorway) over an “open space” midline
- If you miss triggers when people cross quickly:
  - ensure FPS is adequate
  - move the line to a region with larger pixel displacement per step (usually lower in frame)
- If the camera is angled downward sharply:
  - consider using a line aligned to a **floor seam** rather than a generic horizontal line

### Template: pick one boundary style and fill in numbers

Horizontal threshold:
```python
y = 410  # set explicitly after calibration
LINE_A = (0, y)
LINE_B = (CAM_WIDTH, y)
```

Vertical threshold:
```python
x = 240  # set explicitly after calibration
LINE_A = (x, 0)
LINE_B = (x, CAM_HEIGHT)
```

Diagonal threshold:
```python
LINE_A = (120, 520)
LINE_B = (540, 360)
```

---

## Optional: Draw the boundary on the output (debug-only)

If you add a debug overlay, it becomes much easier to validate your boundary placement.
Example (OpenCV draw on a frame):

```python
import cv2

cv2.line(frame, LINE_A, LINE_B, (255, 255, 255), 2)
cv2.circle(frame, LINE_A, 6, (255, 255, 255), -1)
cv2.circle(frame, LINE_B, 6, (255, 255, 255), -1)
```

Keep this **debug-only** to preserve the “hard-coded truth recorder” principle.

## Summary

Preserve truth inside a boundary.
