updates
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
"""Trial IMX708 full-body detection driving the two eyes over one Pi UART.
|
||||
|
||||
By default this only logs. Pass --drive-eyes for a timed hardware trial.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
from gaze_link import GazeLink, center_to_gaze, open_pi_uart
|
||||
from tracking_state import TrackingState
|
||||
|
||||
|
||||
PROJECT_ROOT = Path(__file__).resolve().parents[2]
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--duration", type=float, default=30.0)
|
||||
parser.add_argument("--rotation", type=int, choices=(0, 180), default=0)
|
||||
parser.add_argument("--drive-eyes", action="store_true")
|
||||
parser.add_argument("--device", default="/dev/serial0")
|
||||
parser.add_argument("--log", type=Path)
|
||||
args = parser.parse_args()
|
||||
if args.duration <= 0:
|
||||
parser.error("duration must be positive")
|
||||
|
||||
import cv2
|
||||
from libcamera import Transform
|
||||
from picamera2 import Picamera2
|
||||
|
||||
cv2.setNumThreads(2)
|
||||
hog = cv2.HOGDescriptor()
|
||||
hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector())
|
||||
camera = Picamera2()
|
||||
transform = Transform(hflip=1, vflip=1) if args.rotation == 180 else Transform()
|
||||
camera.configure(camera.create_video_configuration(
|
||||
main={"size": (320, 240), "format": "RGB888"},
|
||||
transform=transform,
|
||||
buffer_count=3,
|
||||
))
|
||||
# The first moving-person log had a 3.34 s detector gap despite a visible person.
|
||||
state = TrackingState(confirm_hits=2, hold_seconds=3.5)
|
||||
link = open_pi_uart(args.device) if args.drive_eyes else GazeLink(open(os.devnull, "wb"))
|
||||
stamp = datetime.now().strftime("%Y%m%d-%H%M%S")
|
||||
log_path = args.log or PROJECT_ROOT / "diagnostics" / f"pi_eye_trial_{stamp}.jsonl"
|
||||
log_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
started = False
|
||||
frames = 0
|
||||
tracked = 0
|
||||
try:
|
||||
camera.start()
|
||||
started = True
|
||||
time.sleep(1.0)
|
||||
deadline = time.monotonic() + args.duration
|
||||
with log_path.open("w", encoding="utf-8") as log:
|
||||
while time.monotonic() < deadline:
|
||||
frame = camera.capture_array("main")
|
||||
detect_start = time.monotonic()
|
||||
boxes, weights = hog.detectMultiScale(
|
||||
frame, hitThreshold=0.0, winStride=(8, 8),
|
||||
padding=(8, 8), scale=1.05, groupThreshold=1,
|
||||
)
|
||||
detect_ms = round((time.monotonic() - detect_start) * 1000, 1)
|
||||
target = None
|
||||
candidate = None
|
||||
if len(boxes):
|
||||
index = max(range(len(boxes)), key=lambda i: float(weights[i]))
|
||||
box_x, box_y, width, height = (int(v) for v in boxes[index])
|
||||
left = max(0, box_x)
|
||||
top = max(0, box_y)
|
||||
right = min(box_x + width - 1, frame.shape[1] - 1)
|
||||
bottom = min(box_y + height - 1, frame.shape[0] - 1)
|
||||
if left <= right and top <= bottom:
|
||||
candidate = center_to_gaze(
|
||||
(left, top, right, bottom), frame.shape[1], frame.shape[0]
|
||||
)
|
||||
target = {"x": box_x, "y": box_y, "width": width,
|
||||
"height": height, "score": float(weights[index])}
|
||||
x, y, valid = state.update(candidate, time.monotonic())
|
||||
seq = link.send(x, y, valid)
|
||||
frames += 1
|
||||
tracked += valid
|
||||
log.write(json.dumps({
|
||||
"time": datetime.now().astimezone().isoformat(),
|
||||
"frame": frames,
|
||||
"detect_ms": detect_ms,
|
||||
"target": target,
|
||||
"gaze": {"x": x, "y": y, "valid": valid, "sequence": seq},
|
||||
}) + "\n")
|
||||
if frames % 10 == 0:
|
||||
print(f"frames={frames} tracked={tracked} "
|
||||
f"last_gaze={x},{y},{int(valid)}", flush=True)
|
||||
finally:
|
||||
# The eyes should return to blue whether the trial ends normally or fails.
|
||||
try:
|
||||
if args.drive_eyes:
|
||||
for _ in range(3):
|
||||
link.send(500, 500, False)
|
||||
time.sleep(0.1)
|
||||
finally:
|
||||
link.stream.close()
|
||||
if started:
|
||||
camera.stop()
|
||||
camera.close()
|
||||
|
||||
print(json.dumps({"frames": frames, "tracked_frames": tracked,
|
||||
"log": str(log_path), "eyes_driven": args.drive_eyes}, indent=2))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user