Skip to main content

TouchLabel AI - Tactile Data Annotation Toolkit

Project description

TouchLabel AI ๐Ÿฆž

Sensor-Agnostic Tactile Data Annotation Toolkit

load โ†’ review โ†’ export ยท Three steps to close the loop

PyPI Python License GitHub Stars Downloads ไธญๆ–‡ๆ–‡ๆกฃ


๐Ÿ”ฅ What's New in v0.2.0b1

Major improvements for downstream compatibility and user experience:

  • โœจ Enhanced metadata: Added sensor_id, calibration_params, feature_names, and episode boundary markers (is_first/is_last)
  • ๐Ÿ”„ LeRobot integration: Bidirectional converters for seamless data exchange with Hugging Face LeRobot framework
  • ๐Ÿ’พ HDF5 export: Scientific computing standard format for research workflows
  • ๐Ÿ“š Comprehensive tutorials: Step-by-step guides for GelSight, PaXini, and Daimon sensors
  • ๐ŸŽฏ Better error messages: Clear guidance with exact pip install commands and format descriptions
  • ๐Ÿ“– Improved docs: 5-Minute Quick Start, sensor-specific loading instructions, troubleshooting table

See CHANGELOG.md for full details.


๐ŸŽฏ Got tactile data from different sensors that refuse to talk to each other? TLabel makes them speak the same language โ€” load any format, annotate in a visual panel, export a unified schema.


๐ŸŽฏ 5-Minute Quick Start

New to TLabel? Start here. This tutorial gets you from zero to annotated data in 5 minutes โ€” no sensor data needed.

Step 1: Install (30 seconds)

pip install tlabel

That's it. The core package installs in seconds with just numpy as a dependency.

Step 2: Try the Built-in Demo (1 minute)

Open a Python terminal or Jupyter notebook:

import tlabel

# Load built-in GelSight demo data (no files needed!)
data = tlabel.demo()

# Open the interactive annotation panel
data.review()

A colorful panel pops up right in your notebook:

  • Timeline at the top shows contact (green), slip (red), and idle (gray) frames
  • Radar chart displays all 22 dimensions for the current frame
  • Detail panel lets you inspect and edit individual values

TLabel Panel with Export Buttons

Try this: Click on different frames in the timeline. Notice how the radar chart updates. Spot any frames that look wrong (e.g., contact=0 but force_magnitude > 0).

Step 3: Make Your First Correction (2 minutes)

Found a mislabeled frame? Fix it:

# In the panel, use the batch correction tool:
# 1. Select a range of frames (drag on timeline)
# 2. Set contact=0 in the correction panel
# 3. Click "Apply" โ€” cascade rules auto-zero 7 related fields

# Or do it programmatically:
data.batch_patch(10, 20, "contact", 0)  # Frames 10-20: no contact

The cascade system ensures physical consistency: setting contact=0 automatically zeroes force_magnitude, slip_event, and resets manipulation_phase to "idle".

Step 4: Export Your Annotations (30 seconds)

# Export to JSON (full TLabel Format v2 schema)
data.export("my_annotations.json")

# Or export to CSV for quick analysis in Excel/pandas
data.export("my_annotations.csv")

Done! You've just completed the full annotation loop: load โ†’ review โ†’ correct โ†’ export.

What's Next?


๐Ÿ“ฅ Loading Your Own Data

Once you're comfortable with the demo, load your real sensor data:

GelSight / DIGIT (vision-based tactile sensors)

# Install extra dependencies
pip install tlabel[gelsight]

# Load your .pkl file (from gelsight-force-estimation or similar)
data = tlabel.load("my_gelsight_episode.pkl")
data.review()

What happens: The adapter extracts 22 dimensions from background-subtracted tactile images, including force magnitude, slip detection, optical flow, and manipulation phase inference.

PaXini PXCap (distributed force array)

pip install tlabel[paxini]

# Load your .h5 or .hdf5 file
data = tlabel.load("my_paxini_episode.h5")
data.review()

What happens: The adapter reads 6D force/torque vectors from each taxel region, detects contact and slip events, and maps them to 20 TLabel dimensions (no optical flow for force-only sensors).

Daimon DM-TacClaw (multimodal robot arm + tactile)

pip install tlabel[daimon]

# Load from LeRobot-style directory structure
data = tlabel.load("path/to/daimon_episode/")
data.review()

Requirements: The directory should contain:

  • meta/info.json โ€” episode metadata
  • data/chunk-*.parquet โ€” observation data (114-dim state vector)
  • videos/ โ€” FFV1-encoded tactile video files (optional, degrades gracefully if missing)

What happens: The adapter decodes FFV1 video frames, extracts tactile features (deformation, contact area, texture), and fuses them with robot state data.

Troubleshooting Common Issues

Error Solution
ImportError: No module named 'cv2' Run pip install tlabel[gelsight] or pip install opencv-python
ImportError: No module named 'h5py' Run pip install tlabel[paxini] or pip install h5py
ImportError: No module named 'pyarrow' Run pip install tlabel[daimon] or pip install pyarrow
ValueError: Unknown format Check file extension (.pkl, .h5, .hdf5, .parquet) or pass format="gelsight" explicitly
FileNotFoundError Double-check the path; use absolute paths if unsure

โšก 30-Second Demo

๐Ÿ‘‰ Try it live in your browser โ€” no install needed, see the panel in action right now.

Or fire it up in Jupyter:

import tlabel
data = tlabel.demo()    # โ† built-in GelSight demo
data.review()           # โ† interactive panel pops up

Or try other sensors:

tlabel.demo('digit').review()    # DIGIT sensor
tlabel.demo('paxini').review()   # PaXini force sensor
tlabel.demo('daimon').review()   # Daimon DM-TacClaw

What you'll see: a color-coded timeline (๐ŸŸข contact / ๐Ÿ”ด slip / โฌœ idle), 22-dim radar chart, frame detail editor, and batch patching โ€” all in one panel.

TLabel Panel Demo


๐Ÿš€ Quick Start

pip install tlabel
import tlabel

# Load โ€” auto-detect sensor format, no config needed
data = tlabel.load("gelsight_force.pkl")     # GelSight / DIGIT
data = tlabel.load("paxini_episode.h5")      # PaXini
data = tlabel.load("daimon_data/")           # Daimon (directory or .parquet)

# Annotate โ€” interactive Jupyter panel
data.review()          # Chinese UI
data.review(lang="en") # English UI

# Export โ€” unified TLabel Format
data.export("output.json")   # TLabel Format v2 JSON
data.export("output.csv")    # flat CSV

Pre-annotate โ€” AI-assisted, review & correct

from tlabel.predict import PredictEngine engine = PredictEngine() results = engine.predict(data) # predict contact, slip, phase... engine.apply(data, results, min_confidence=0.7) # apply only high-confidence data.review() # review & correct in panel


That's it. Full loop. ๐Ÿ”

---

## ๐Ÿค” Why TLabel?

| Pain | TLabel's Answer |
|------|-----------------|
| Every sensor spits out a different format | **One `load()` call, auto-detected** |
| Raw tactile data is unreadable numbers | **Visual panel: timeline + radar + details** |
| Fixing labels frame-by-frame is soul-crushing | **Batch patch + cascade rules, fix ranges in one click** |
| Your lab mate exported... something... | **Unified TLabel Format v2, 22 dimensions, no ambiguity** |
| "But we use DIGIT and they use PaXini" | **Sensor-agnostic. Load both, same schema, same tool.** |
| "Manually labeling thousands of frames is tedious" | **AI pre-annotation: predict contact, slip, phase โ€” review & correct** |

---

## ๐Ÿ“ก Supported Sensors

| Sensor | Format | Dimensions | Optical Flow | Status |
|--------|--------|:----------:|:------------:|:------:|
| **GelSight Mini** | `.pkl` | 22 | โœ… | โœ… Stable |
| **DIGIT** | `.pkl` | 22 | โœ… | โœ… Stable |
| **Daimon DM-TacClaw** | `.parquet` / dir | 22 (video) / 20 (no video) | โœ… / โ€” | โœ… Stable |
| **PaXini PXCap** | `.h5` / `.hdf5` | 20 | โ€” | โœ… Stable |

> Force-type sensors (PaXini) lack optical images โ†’ 20 dims. Image-type โ†’ full 22. Daimon gracefully degrades when no video is present. No errors, no surprises.

---

## ๐Ÿ“ฆ Installation

```bash
# Just the core (numpy only, ~2s install)
pip install tlabel

# Per-sensor extras
pip install tlabel[gelsight]   # GelSight / DIGIT โ†’ opencv-python
pip install tlabel[paxini]     # PaXini โ†’ h5py
pip install tlabel[daimon]     # Daimon โ†’ pyarrow + opencv-python

# I want it all
pip install tlabel[all]

๐ŸŽจ Panel Features

  • ๐ŸŽจ Color-coded timeline: green = contact ยท red = slip ยท gray = idle โ€” patterns jump out instantly
  • ๐Ÿ•ธ 22-dim radar chart: see the full feature vector at a glance, bilingual labels
  • โœ๏ธ Frame & batch patching: fix one frame or a range, your call
  • ๐Ÿ”— Cascade rules: set contact=0 โ†’ 7 related fields auto-zero + phase resets to idle
  • ๐ŸŒ Bilingual toggle: ไธญๆ–‡ / English, one click top-right
  • ๐Ÿ“ค Export: JSON / CSV, auto-detected by file extension

TLabel Format v2 โ€” 22 Dimensions

Static Features (18-dim)

# Key Description
1 contact Binary contact flag
2 deformation_magnitude Surface deformation intensity
3 force_magnitude Normal force magnitude
4 force_peak Peak force in episode window
5 force_direction Force vector angle (ยฐ)
6 slip_entropy Uncertainty of slip detection
7 slip_event Binary slip event flag
8 texture_energy Surface texture frequency energy
9 edge_density Contact edge pixel ratio
10 contact_area Contact region area ratio
11 centroid_x Contact centroid x-position
12 normal_field_magnitude Normal pressure field magnitude
13 normal_field_variance Normal field spatial variance
14 shear_field_magnitude Shear stress magnitude
15 shear_field_direction Shear direction angle (ยฐ)
16 delta_force_normal Frame-to-frame ฮ”F_normal
17 delta_force_shear Frame-to-frame ฮ”F_shear
18 friction_cone_ratio Tangential/normal force ratio

Temporal Features (4-dim, v0.2.0)

# Key Image-type Force-type Description
19 optical_flow_magnitude โœ… โ€” Inter-frame motion magnitude (Farneback)
20 optical_flow_direction โœ… โ€” Optical flow angle (ยฐ)
21 temporal_deformation_rate โœ… โœ… Rate of deformation change
22 contact_transition โœ… โœ… Contact state transition probability

๐Ÿ“– API Quick Reference

import tlabel

# โ”€โ”€ Loading โ”€โ”€
data = tlabel.load(path)                     # Auto-detect sensor format
data = tlabel.load(path, format="gelsight")  # Force specific adapter

# โ”€โ”€ Demo โ”€โ”€
data = tlabel.demo()                         # Built-in demo data
tlabel.list_demos()                          # See available sensors

# โ”€โ”€ Properties โ”€โ”€
data.num_frames        # int โ€” total frame count
data.duration_s        # float โ€” episode duration
data.sensor_type       # str โ€” sensor identifier
data.dimension_keys    # list โ€” all dimension keys
data.modified_count    # int โ€” frames with manual patches

# โ”€โ”€ Frame Access โ”€โ”€
frame = data[0]                          # Index access
frame = data.get_frame(42)               # By frame_idx
frame.contact                            # Contact value
frame.slip_event                         # Slip event value
frame.is_modified                        # Has patches?

# โ”€โ”€ Patching โ”€โ”€
frame.patch("contact", 0)                         # Single frame (cascade=True)
frame.patch("contact", 0, cascade=False)           # No cascade
data.batch_patch(10, 50, "contact", 0)             # Range patch

# โ”€โ”€ Review & Export โ”€โ”€
data.review()                    # Jupyter panel (Chinese)
data.review(lang="en")           # English
data.export("output.json")       # JSON (TLabel Format v2)
data.export("output.csv")        # CSV

Cascade Rules (contact โ†’ 0)

When contact is set to 0, these fields are automatically zeroed:

Auto-zeroed Field Condition
force_magnitude always
force_peak always
slip_event always
delta_force_normal always
delta_force_shear always
contact_area always
contact_transition only if value > 0.5
manipulation_phase โ†’ "idle" (if not already)

๐Ÿค– AI-Assisted Pre-Annotation

Let the engine suggest labels, then you review and correct โ€” human-in-the-loop, not black-box.

from tlabel.predict import PredictEngine

engine = PredictEngine()

# Option 1: cold start โ€” no prior labels
results = engine.predict(data)

# Option 2: warm start โ€” learn from partially labeled data first
engine.fit(data)        # extract statistics from existing annotations
results = engine.predict(data)

# Apply only high-confidence predictions (โ‰ฅ0.7)
applied = engine.apply(data, results, min_confidence=0.7)
print(f"Auto-filled {applied} fields")

# Review the summary
stats = engine.summary(results)
print(stats)
# โ†’ {total_frames, predicted_fields, avg_confidence, method_distribution, ...}

data.review()  # check predictions in the panel, correct as needed

What it predicts:

Dimension Method Confidence Range
contact Rule (force + deformation + area) 0.4 โ€“ 0.9
slip_event Rule (shear + delta + entropy) 0.55 โ€“ 0.8
manipulation_phase Rule (contact + slip + force cascade) 0.55 โ€“ 0.65
Missing dims (with fit()) Statistics (mean from labeled frames) ~0.4

๐Ÿ’ก Tip: Use fit() on partially labeled data first โ€” even 10โ€“20% labeled frames significantly improve statistical predictions. Predictions below your confidence threshold are simply skipped, so you stay in control.


๐Ÿ—‚ Project Structure

tlabel/
โ”œโ”€โ”€ core/
โ”‚   โ”œโ”€โ”€ types.py          # TLabelFrame / TLabelData containers
โ”‚   โ”œโ”€โ”€ loader.py         # Auto-detect & dispatch loading
โ”‚   โ””โ”€โ”€ registry.py       # Adapter registry
โ”œโ”€โ”€ adapters/
โ”‚   โ”œโ”€โ”€ base.py           # BaseAdapter interface
โ”‚   โ”œโ”€โ”€ gelsight.py       # GelSight Mini / DIGIT
โ”‚   โ”œโ”€โ”€ paxini.py         # PaXini PXCap
โ”‚   โ””โ”€โ”€ daimon.py         # Daimon DM-TacClaw (+ video decoding)
โ”œโ”€โ”€ viewer/
โ”‚   โ”œโ”€โ”€ panel.py          # Jupyter _repr_html_ renderer
โ”‚   โ””โ”€โ”€ templates.py      # HTML + JS + CSS template engine
โ”œโ”€โ”€ predict/
โ”‚   โ””โ”€โ”€ engine.py         # AI-assisted pre-annotation engine
โ”œโ”€โ”€ demo.py               # Built-in demo data loader
โ””โ”€โ”€ export/
    โ””โ”€โ”€ writer.py         # JSON / CSV export + NumpyEncoder

๐Ÿ’ฌ Feedback

Found a bug? Have an idea? Just want to say hi?

  • ๐Ÿ› Bug report โ†’ Open an Issue
  • ๐Ÿ’ก Feature request โ†’ GitHub Discussions
  • ๐ŸŒŸ Using tlabel in your research? โ†’ We'd love to hear about it! Drop us a star โญ

๐Ÿค Contributing

We welcome contributions! See CONTRIBUTING.md for guidelines.

Good first issues:

  • ๐Ÿ”Œ Add a new sensor adapter (SynTouch? XELA? Your call.)
  • ๐Ÿ“Š Improve radar chart UI (dark mode, interactive hover)
  • ๐ŸŒ Add more language support (ๆ—ฅๆœฌ่ชž, ํ•œ๊ตญ์–ด)
  • ๐Ÿงช Add integration tests for edge cases

๐Ÿ“„ License

MIT ยฉ Niuzu Tech


If this saved you from manually labeling tactile data, a โญ would make our day!

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tlabel-0.3.0.tar.gz (100.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tlabel-0.3.0-py3-none-any.whl (100.4 kB view details)

Uploaded Python 3

File details

Details for the file tlabel-0.3.0.tar.gz.

File metadata

  • Download URL: tlabel-0.3.0.tar.gz
  • Upload date:
  • Size: 100.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.12

File hashes

Hashes for tlabel-0.3.0.tar.gz
Algorithm Hash digest
SHA256 89351556361fdd90e2a43d888b49660892d14aa2c6731403e8d543c006cc047b
MD5 fb1f891541fb95bee20710da7e263c79
BLAKE2b-256 0fc2d926d4241571aa6385912d030d1877ce7d723e9b7f081f1ac4a456fa2fec

See more details on using hashes here.

File details

Details for the file tlabel-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: tlabel-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 100.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.12

File hashes

Hashes for tlabel-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b3a9c43ca4cf157865ed694639d013d94ea20d794e92a2af1ad108d23ee7855c
MD5 63179b2110783c59d87d26ec9923f991
BLAKE2b-256 31eb51631113bb1bd7cdbb52db51e1035fb6e1e66633f6b32123f03e4b06a0e4

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page