mirror of
https://github.com/DeeJanuz/frametop.git
synced 2026-10-06 05:00:08 +02:00
Hands: pick the cameras by the light, and detect grips
ft-hands tracks with the mono IR cameras in dim light and with every camera (or the colour pair, HANDS_BRIGHT) in bright light, going by the colour frames' mean brightness with hysteresis and a 2 s hold (HANDS_CAMERAS=auto, the default; mono, color and all fix it). Colour frames are placed on the mono cameras' clock by their dequeue time, and a view in a camera a step lacks waits for that camera's next frame. A grip (a closed hand) is a second gesture next to the pinch, in version 2 of the gestures file: every fingertip curled toward the wrist, beginning only on a hand seen open within a second and held up in front. On the 2026-09-30 lit recording that leaves 6 false grips of 14, all with the hands on the desk; pinch counts are unchanged. ft-handreplay logs grips and finger curl, watch_gestures.py shows them, and tools/cut_sets.py copies a few sets out of a recording. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
40a2f39b2a
commit
50c14545ed
11 files changed
+746
-185
No files matched your search
@@ -0,0 +1,51 @@
|
||||
"""Copy a few frame sets out of a recording (ft-hands --record) into a small one, to look at
|
||||
or check elsewhere without moving gigabytes. Plain Python, so it runs on the Frame's host.
|
||||
|
||||
usage: python3 tools/cut_sets.py REC_DIR OUT_DIR [--sets N] (8, spread evenly) | [--at I,J,...]
|
||||
"""
|
||||
import argparse
|
||||
import os
|
||||
import struct
|
||||
|
||||
HDR = struct.Struct('<8sII')
|
||||
|
||||
|
||||
def offsets(path):
|
||||
offs, size = [], os.path.getsize(path)
|
||||
with open(path, 'rb') as f:
|
||||
off = 0
|
||||
while off + HDR.size <= size:
|
||||
f.seek(off)
|
||||
magic, _, nbytes = HDR.unpack(f.read(HDR.size))
|
||||
if magic[:7] != b'FHSET01' or off + nbytes > size:
|
||||
break
|
||||
offs.append((off, nbytes))
|
||||
off += nbytes
|
||||
return offs
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument('rec')
|
||||
ap.add_argument('out')
|
||||
ap.add_argument('--sets', type=int, default=8)
|
||||
ap.add_argument('--at', default='')
|
||||
a = ap.parse_args()
|
||||
src = os.path.join(a.rec, 'sets.bin')
|
||||
offs = offsets(src)
|
||||
if a.at:
|
||||
pick = [int(i) for i in a.at.split(',')]
|
||||
else:
|
||||
n = max(1, min(a.sets, len(offs)))
|
||||
pick = [round(i * (len(offs) - 1) / max(n - 1, 1)) for i in range(n)]
|
||||
os.makedirs(a.out, exist_ok=True)
|
||||
with open(src, 'rb') as f, open(os.path.join(a.out, 'sets.bin'), 'wb') as out:
|
||||
for i in pick:
|
||||
off, nbytes = offs[i]
|
||||
f.seek(off)
|
||||
out.write(f.read(nbytes))
|
||||
print('%d of %d sets (%s) -> %s' % (len(pick), len(offs), ','.join(map(str, pick)), a.out))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in new issue
Block a user