Files
DeeJanuz--frametop/hands/track/pinch.h
T
DeeJanuzandClaude Opus 5.5 e2abaa06b6 Hands: fixes from the first headset test
- The runtime files move to /run/user/UID/frametop-hands/: the desktop
  session deletes /run/user/UID/frametop at every start.
- The cutout copy shader runs at highp: mediump (16-bit on Adreno)
  stepped 1.7 texels across a 3440-pixel screen.
- One hand no longer pinches both sides after its left/right call flips
  mid-pinch, and --pinch-palm-down (0.6) holds back pinches with the palm
  facing down (typing on a lap keyboard).
- ft-camd judges a colour frame fresh by its luma rows only, and logs
  per-buffer changes at stale colour frames with FT_CAMD_DEBUG=1.
- hands/run.sh caps skips the setcap when ft-camd already has them.
- The replay tool dumps poses (--poses), and its pinch events carry the
  hand id.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 14:00:54 -06:00

80 lines
3.4 KiB
C++

// Pinch detection for input: look at something and pinch to click, pinch and move to drag.
// Per side, from the tracker's hands after each step; published as fh_gestures.h.
#pragma once
#include "tracker.h"
#include <string>
#include <vector>
extern "C" {
#include "../include/fh_gestures.h"
}
struct PinchParams {
double begin_m = 0.020; // thumb and index tips closer than this: the pinch begins
double end_m = 0.035; // further apart than this: it ends (the gap keeps it from flickering)
int end_frames = 2; // processed frames in a row past end_m before it ends, so one
// noisy frame doesn't drop a drag
double grace_s = 0.25; // a pinching hand lost this long ends its pinch (FH_PINCH_LOST)
// Where the distance comes from: MediaPipe's world landmarks (the model's own 3D hand
// pose, averaged over the hand's views, at the user's hand size), or the tracker's
// triangulated tips. The model's pose should hold up better when the fingers hide each
// other; tomorrow's recordings will tell.
bool triangulated = false;
// No pinch begins while the palm faces down more than this (|palm normal . up| in the
// head frame; 1 turns it off). Typing curls the thumb onto the index: in the 2026-09-30
// lit recording, pinches that began while typing had 0.69-1.00, deliberate ones 0.00-0.50.
// Looking down tilts the head frame, which lowers the reading for a hand on a keyboard.
double palm_down_max = 0.6;
};
class Pinch {
public:
explicit Pinch(const PinchParams &p = {}) : p_(p) {}
const PinchParams &params() const { return p_; }
// After each processed set: the hands out of Tracker::step, the tracker's views (for
// the world landmarks) and the capture time.
void update(const std::vector<const Hand *> &hands, const std::vector<Seen> &views, int64_t t_ns);
// Ends any pinch that's down (as lost), e.g. when the tracker stops.
void release(int64_t t_ns);
const fh_pinch_t &side(int s) const { return side_[s]; } // 0 left, 1 right
// A pinch is down or closing: worth tracking at the full rate.
bool engaged() const;
// What changed in the last update, for logs.
struct Event {
int side;
const char *what; // "begin", "end", "lost"
int64_t t_ns;
double distance;
V3 point;
};
std::vector<Event> events;
// Both distance measures for the last update, per side (-1: no hand), for logs.
double world_d[2] = {-1, -1}, tri_d[2] = {-1, -1};
double palm_down[2] = {-1, -1}; // |palm normal . up| of each side's hand
int held_back[2] = {0, 0}; // pinches that didn't begin because the palm faced down
private:
void end(int s, int64_t t_ns, bool lost);
PinchParams p_;
fh_pinch_t side_[2]{};
int follow_[2] = {0, 0}; // the hand id a pinch follows while down
int open_frames_[2] = {0, 0};
int64_t seen_ns_[2] = {0, 0};
bool held_[2] = {false, false}; // a close held back (palm down) that hasn't opened yet
};
// Writes /run/user/UID/frametop-hands/gestures.
class GesturePublisher {
public:
bool open(const Pinch &pinch, std::string &err);
void write(const Pinch &pinch, uint64_t capture_ns);
private:
fh_gestures_t *out_ = nullptr;
uint64_t seq_ = 0;
uint32_t last_begins_[2] = {0, 0}, last_ends_[2] = {0, 0}; // Pinch's counters last written
};