# vision_palm_preview.py — hand detection on an in-flash model, watched live in
# the Tendrl dev UI (Contact / dev-mcp: Files -> Run).
#
# BlazePalm finds hands and gives you 7 joints per hand: the wrist, the four
# knuckles, and two thumb joints. That's enough to know a hand is there and
# roughly how it's oriented. For individual fingers and fingertips you need the
# 21-joint landmark model — see vision_hand_landmarks_preview.py.
#
# The model (`/rom/palm_detection_full_192.tflite`) ships in OpenMV flash.
#
# NOTE: at 192x192 this wants an NPU (OpenMV AE3 or N6) to run in real time. It
# still runs on an H7 / RT1062 — just poll it a few times a second rather than in
# a tight loop, and expect the preview to be choppy there.
#
# Adapted from OpenMV's MediaPipe palm detection example:
#   https://github.com/openmv/openmv/blob/master/scripts/examples/
#
# Requires: OpenMV cam with `ml`, the vision add-on (package-vision.json),
# and firmware that ships `ml.postprocessing.mediapipe`.
import time

from tendrl import preview
from tendrl.vision import PALM_LINES, Camera, draw_boxes, draw_skeleton, palm_boxes

# BlazePalm wants a SQUARE input — VGA windowed to 400x400.
cam = Camera(framesize="VGA", window=(400, 400))

detect = palm_boxes(min_conf=0.4)

while True:
    img = cam.snapshot()

    # [(x, y, w, h, score, keypoints), ...] — keypoints is a (7, 2) array:
    # 0 wrist, 1-4 index/middle/ring/pinky knuckles, 5 thumb base, 6 thumb joint.
    palms = detect(img)

    for x, y, w, h, score, kps in palms:
        draw_boxes(img, [(x, y, w, h)], label="palm %.2f" % score, color=(0, 0, 255))
        # PALM_LINES connects those 7 joints into a hand outline.
        draw_skeleton(img, kps, PALM_LINES, kp_color=(255, 0, 0), line_color=(0, 255, 0))

    if palms:
        print("%d hand(s), best %.2f" % (len(palms), max(p[4] for p in palms)))

    # Draw FIRST, preview second: this JPEG-compresses img in place.
    preview.frame(img)
    time.sleep_ms(50)


# --- To publish instead of preview -------------------------------------------
# palm() is the same model reduced to a state, for a Watch:
#
#     from tendrl import Client
#     from tendrl.vision import Watch, palm
#
#     watch = Watch(Client(mode="sync"), detect=palm(min_conf=0.4), debounce=2)
#     while True:
#         watch.update(cam.snapshot())     # publishes only when it changes
