🦞 TouchLabel AI

June 30, 2026 Β· View on GitHub

🦞 TouchLabel AI

The World's First Sensor-Agnostic Tactile Data Annotation Toolkit

Load any tactile sensor β†’ Annotate visually β†’ Export a unified schema

PyPI Python License Downloads GitHub Stars Last Commit δΈ­ζ–‡ζ–‡ζ‘£

TLabel Panel Demo

GelSight Β· DIGIT Β· PaXini Β· Daimon Β· YCB-Slide β€” one tool, one format, all sensors

πŸš€ Quick Start Β· πŸ€– AI Pre-Annotation Β· πŸ“Š Benchmark Β· πŸ“– Docs Β· 🀝 Contributing


πŸ†• What's New

v0.10.1 β€” YCB-Slide Sim Data Fix

  • πŸ”§ Auto-detect nested directories: Handle Google Drive download quirk where sim data has extra nesting level (e.g., 004_sugar_box/004_sugar_box/00/)
  • βœ… Verified PKL structure: gelposes_meas, gelposes, camposes, mNoise fields

v0.10.0 β€” YCB-Slide Adapter (MidasTouch)

Convert CMU RPL's YCB-Slide tactile manipulation dataset to the unified TLabel format.

  • πŸ“‚ Auto-detect YCB-Slide real & sim data from directory structure
  • πŸ– DIGIT sensor support with image-based 22-dim feature extraction
  • πŸ“ 6-DoF pose tracking for both DIGIT sensor and manipulated objects
  • πŸ”„ Real + Sim data in a single adapter (split='real' / 'sim' / 'all')
  • πŸ“¦ Validated on the full YCB-Slide dataset (10 objects Γ— 5 sequences = 182,983 frames)

Usage Example

from tlabel import load

# Load real data
data = load('/path/to/ycb_slide/real', format='ycb_slide', split='real')

# Load sim data (supports Google Drive nested directory structure)
data = load('/path/to/ycb_slide/sim', format='ycb_slide', split='sim')

# Load both
data = load('/path/to/ycb_slide', format='ycb_slide', split='all')

Supported directory structures:

# Real data:
<object>/dataset_X/synced_data.npy
<object>/dataset_X/digit/*.jpg

# Sim data (standard):
<object>/XX/tactile_data.pkl
<object>/XX/tactile_images/*.jpg

# Sim data (Google Drive download, auto-detected):
<object>/<object>/XX/tactile_data.pkl
<object>/<object>/XX/tactile_images/*.jpg

v0.9.0 β€” Interactive Panel Phase 1 + Exporter Plugin Registry

Professional tactile annotation experience with rich visualization and extensible export pipeline.

  • 🎨 Pseudo GelSight Visualization: Real-time tactile contact heatmap with radial gradient and force rings
  • ⌨️ Keyboard Shortcuts: Space (toggle annotation), ←→ (frame navigation), ↑↓ (label adjust)
  • πŸ“Š Timeline Range Selection: Click-to-jump + drag-to-select frame ranges for batch editing
  • πŸ€– AI Pre-Annotation: One-click auto-label with confidence threshold control
  • πŸ“¦ Unified Export Center: Single tab for all formats β€” JSON, CSV, HDF5, FTP-1, LeRobot, RLDS(stub), ROS2(stub)
  • πŸ”Œ Exporter Plugin Registry: ExporterBase + dynamic register()/unregister() β€” add new formats as subclasses

v0.8.0 β€” FTP-1 / MTTS Export

Export labeled data directly to FTP-1's MTTS Zarr format for foundation model fine-tuning.

  • πŸš€ FTP-1 Converter: tlabel_to_ftp1() / `batch_to_ftp1()$ β€” \text{one}-\text{click} \text{export} \text{to} \text{Zarr}
  • πŸ– 21 \text{Functional} \text{Areas}: \text{MTTS} \text{morphology}-\text{aware} \text{tactile} \text{token} \text{space} (15 \text{hand} \text{zones} + 6 \text{wrist} \text{torque} \text{channels})
  • πŸ“‘ 7 \text{Sensor} \text{Registry}: \text{GelSight}, \text{GelSightMini}, \text{FreeTacMan}, \text{ViTaMIn}, 3\text{DViTac}, \text{Contactile}, \text{BinaryContact}
  • 🎨 \text{New} \text{Export} \text{Tab} \text{in} \text{Panel}: \text{sensor} \text{selection}, \text{functional} \text{area} \text{picker} \text{with} \text{presets}, \text{export} \text{preview}
  • πŸ“¦ \text{Zarr} \text{backend}: \text{append} \text{mode} \text{for} \text{multi}-\text{episode} \text{datasets}, \text{auto} \text{image} \text{resize} \text{to} 224 \times 224 + \text{normalization}

$``python from tlabel import demo data = demo('gelsight') data.export_ftp1("output.zarr", sensor_name="GelSightMini", functional_areas=[0, 1]) # thumb tip + index fingertip


### v0.5.0 β€” AI-Assisted Pre-Annotation
**Let the engine suggest labels, then you review and correct β€” human-in-the-loop, not black-box.**
- πŸ€– **PredictEngine**: predict contact, slip, and manipulation phase automatically
- πŸ“ˆ **Warm start with `fit()`**: learn from your partially labeled data β€” even 10% labels significantly boost accuracy
- 🎯 **Confidence threshold**: only apply predictions above your threshold, you stay in control
- πŸ”¬ **HMM Phase Detection**: Hidden Markov Model for manipulation phase inference with Viterbi decoding
- 🧹 **Removed black-box pkl models**: no opaque pretrained weights β€” every prediction is interpretable

<details>
<summary><b>Previous releases</b></summary>

- **v0.4.2** β€” Full i18n: bilingual Panel UI (δΈ­ζ–‡/English), localized error messages, docs in both languages
- **v0.4.1** β€” Panel UI integration: Tab navigation, batch correction tool, export buttons directly in panel
- **v0.4.0** β€” Interactive Panel: color-coded timeline, 22-dim radar chart, frame detail editor
- **v0.2.0b1** β€” LeRobot integration, HDF5 export, enhanced metadata, comprehensive tutorials

</details>

---

## 🎯 Why TLabel?

> **Every tactile sensor spits out a different format. There's no universal annotation tool β€” until now.**

| The Problem | TLabel's Answer |
|:------------|:----------------|
| 4 different sensors β†’ 4 different pipelines | **One `tlabel.load()` call, auto-detected** |
| Raw tactile data = unreadable numbers | **Visual Panel: timeline + radar chart + frame editor** |
| Fixing labels frame-by-frame is soul-crushing | **AI pre-annotation + batch patch + cascade rules** |
| "We use DIGIT, they use PaXini" β€” data doesn't mix | **Sensor-agnostic 22-dim schema, one format for all** |
| No standardized tactile labels exist | **TLabel Format v2 β€” the first unified specification** |
| Annotation tools assume vision, not touch | **Built for tactile from day one** |

**TLabel is the only tool that:**
- βœ… Supports 5+ tactile sensor families out of the box
- βœ… Provides a unified 22-dimension annotation schema
- βœ… Offers AI-assisted pre-annotation with human-in-the-loop
- βœ… Ships an interactive visual Panel for Jupyter
- βœ… Includes a cross-sensor benchmark ([TLabel-Bench](https://github.com/liesliy/tlabel-bench))

---

## πŸš€ Quick Start

### Install

```bash
pip install tlabel

That's it. Core installs in seconds with just numpy as a dependency.

Try the Demo (30 seconds)

import tlabel

data = tlabel.demo()     # Built-in GelSight demo β€” no files needed
data.review()            # Interactive Panel pops up in Jupyter

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.

Other sensors:

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

πŸ‘‰ Try it live in your browser β€” no install needed.

Load Your Own Data

import tlabel

# 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 & Export

# Interactive Jupyter panel (bilingual: δΈ­ζ–‡ / English)
data.review()           # Chinese UI
data.review(lang="en")  # English UI

# Export β€” unified TLabel Format v2
data.export("output.json")   # Full schema JSON
data.export("output.csv")    # Flat CSV for pandas/Excel

Full loop: load β†’ review β†’ correct β†’ export πŸ”

Export to FTP-1 (Foundation Model Ready)

pip install tlabel[ftp1]   # installs zarr
# Export labeled data β†’ FTP-1 Zarr format
data.export_ftp1("output.zarr",
    sensor_name="GelSightMini",
    functional_areas=[0, 1])

# Batch export multiple episodes
from tlabel.converters import batch_to_ftp1
batch_to_ftp1(["ep1.json", "ep2.json"], "dataset.zarr",
    sensor_name="GelSightMini",
    functional_areas=[0, 1])

# Preset configurations
from tlabel.converters import DEFAULT_AREA_MAPPINGS
# "parallel_gripper": [0, 1]
# "three_finger": [0, 1, 2]
# "five_finger": [0, 1, 2, 3, 4]
# "dexterous_hand": list(range(15))

The exported Zarr files are directly compatible with FTP-1 for fine-tuning the world's first general-purpose tactile foundation model.


πŸ€– AI Pre-Annotation

New in v0.5.0 β€” Let the engine suggest labels, then you review and correct.

from tlabel.predict import PredictEngine

engine = PredictEngine()

# Option 1: Cold start β€” no prior labels needed
results = engine.predict(data)

# Option 2: Warm start β€” learn from your partial annotations first
engine.fit(data)          # Extract statistics from labeled frames
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 in Panel β€” correct any mistakes
data.review()

What it predicts:

DimensionMethodConfidence Range
contactRule-based (force + deformation + area)0.4 – 0.9
slip_eventRule-based (shear + delta + entropy)0.55 – 0.8
manipulation_phaseHMM + Viterbi decoding0.55 – 0.65
Missing dims (with fit())Statistical (mean from labeled frames)~0.4

πŸ’‘ Tip: Use fit() on partially labeled data first β€” even 10–20% labeled frames significantly improve predictions. Predictions below your confidence threshold are simply skipped.


πŸ“‘ Supported Sensors

SensorTypeFormatDimsOptical FlowStatus
GelSight MiniVision-based.pkl22βœ…βœ… Stable
DIGITVision-based.pkl22βœ…βœ… Stable
Daimon DM-TacClawMultimodal.parquet / dir22 (video) / 20 (no video)βœ… / β€”βœ… Stable
PaXini PXCapForce array.h5 / .hdf520β€”βœ… 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.

FTP-1 Compatible Sensors

All sensors below can export directly to FTP-1 MTTS Zarr format via export_ftp1():

SensorTypeDefault Shape
GelSight / GelSightMiniimage(224, 224, 3)
FreeTacManimage(224, 224, 3)
ViTaMInimage(224, 224, 3)
3DViTacmatrix(12, 32)
Contactilematrix(12, 32)
BinaryContactbinary(1,)

Per-Sensor Installation

pip install tlabel[gelsight]   # GelSight / DIGIT β†’ opencv-python
pip install tlabel[paxini]     # PaXini β†’ h5py
pip install tlabel[daimon]     # Daimon β†’ pyarrow + opencv-python
pip install tlabel[ftp1]       # FTP-1/MTTS export β†’ zarr
pip install tlabel[all]        # Everything

Sensor Tutorials


🎨 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
  • πŸ€– Pre-annotation integration: apply AI predictions, then review in the same panel
  • 🌐 Bilingual toggle: δΈ­ζ–‡ / English, one click top-right
  • πŸ“€ In-panel export: JSON / CSV / FTP-1 Zarr with one click

πŸ“ TLabel Format v2 β€” 22 Dimensions

The first unified tactile annotation schema. Every frame, every sensor, same 22 dimensions.

Static Features (18-dim)

#KeyDescription
1contactBinary contact flag
2deformation_magnitudeSurface deformation intensity
3force_magnitudeNormal force magnitude
4force_peakPeak force in episode window
5force_directionForce vector angle (Β°)
6slip_entropyUncertainty of slip detection
7slip_eventBinary slip event flag
8texture_energySurface texture frequency energy
9edge_densityContact edge pixel ratio
10contact_areaContact region area ratio
11centroid_xContact centroid x-position
12normal_field_magnitudeNormal pressure field magnitude
13normal_field_varianceNormal field spatial variance
14shear_field_magnitudeShear stress magnitude
15shear_field_directionShear direction angle (Β°)
16delta_force_normalFrame-to-frame Ξ”F_normal
17delta_force_shearFrame-to-frame Ξ”F_shear
18friction_cone_ratioTangential/normal force ratio

Temporal Features (4-dim)

#KeyImage-typeForce-typeDescription
19optical_flow_magnitudeβœ…β€”Inter-frame motion magnitude (Farneback)
20optical_flow_directionβœ…β€”Optical flow angle (Β°)
21temporal_deformation_rateβœ…βœ…Rate of deformation change
22contact_transitionβœ…βœ…Contact state transition probability

πŸ“– Full specification: annotation-spec.md | tlabel-format.md


πŸ“– 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

# ── Pre-Annotation ──
from tlabel.predict import PredictEngine
engine = PredictEngine()
engine.fit(data)                                   # Warm start from partial labels
results = engine.predict(data)                     # Predict contact, slip, phase
engine.apply(data, results, min_confidence=0.7)    # Apply high-confidence only

# ── 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
data.export_ftp1("out.zarr")     # FTP-1 Zarr format

Cascade Rules (contact β†’ 0)

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

Auto-zeroed FieldCondition
force_magnitudealways
force_peakalways
slip_eventalways
delta_force_normalalways
delta_force_shearalways
contact_areaalways
contact_transitiononly if value > 0.5
manipulation_phase→ "idle" (if not already)

πŸ† Benchmark

TLabel-Bench β€” The first cross-sensor unified tactile annotation benchmark.

Same objects, different sensors, one format. TLabel-Bench provides cross-sensor annotations (material labels, episode segmentation, quality scores) for objects annotated with GelSight Mini, DIGIT, DMA, and more β€” all in the unified TLabel format.

git clone https://github.com/liesliy/tlabel-bench.git
cd tlabel-bench
bash scripts/download_data.sh
python evaluation/material_classification.py

If you're using TLabel in research, citing the benchmark helps demonstrate sensor-agnostic value πŸ‘‡


πŸ—‚ 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)
β”œβ”€β”€ converters/
β”‚   β”œβ”€β”€ lerobot.py        # LeRobot format converter
β”‚   └── ftp1.py           # FTP-1/MTTS Zarr format converter
β”œβ”€β”€ 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

πŸ“ Citing TLabel

If you use TLabel in your research, please cite:

@software{tlabel2026,
  title = {TLabel: A Sensor-Agnostic Tactile Data Annotation Toolkit},
  author = {NiuZhu Tech},
  year = {2026},
  url = {https://github.com/liesliy/tlabel}
}

🀝 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
  • πŸ€– Improve pre-annotation models (replace rules with lightweight ML?)

πŸ’¬ Feedback

  • πŸ› 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 ⭐

πŸ“„ License

MIT Β© NiuZhu Tech


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

⭐ Star on GitHub Β· πŸ“¦ Install from PyPI Β· πŸ† Try the Benchmark