Last Updated: 2025-10-22 Purpose: Quick orientation for AI assistants to minimize token usage and expedite inquiries
Project Name: DemBA (DeepLabCut Multi-animal Behavioral Analysis with Improved re-ID) Primary Use Case: Cichlid fish behavioral video analysis (Streelman & McGrath labs, Georgia Tech) Core Technology: Python pipeline built on top of DeepLabCut for multi-animal pose tracking
Key Innovation: CNN-based per-video identity correction using triplet loss, combined with hard-partition tracklet stitching to maintain consistent identity assignment across long videos (tested on 3.5-hour videos).
demba/
├── __init__.py # Package exports and version (v0.1.0)
├── config.py # All pipeline configuration constants
├── file_manager.py # TrialManager & ProjectManager classes for file path management
├── pose_estimation.py # Stage 1: DeepLabCut pose estimation wrapper
├── identity_correction.py # Stage 2: CNN triplet-loss ID correction (CORE MODULE)
├── tracklet_stitching.py # Stage 3: Hard-partition stitching by identity
├── filtering.py # Stage 4: Temporal filtering wrapper
├── feature_extraction.py # Stage 5: Behavioral feature detection (cichlid-specific)
├── visualization.py # Stage 6: Labeled video creation
├── analysis.py # Stage 7: Statistical plots and analysis
└── utils/
├── dlc.py # DeepLabCut file loading utilities
├── roi.py # ROI estimation and video cropping
├── metrics.py # Evaluation metrics (phi, jaccard)
└── gen_utils.py # Batch mode utilities (metadata save/load)
main.py: CLI entry point with argparse for all pipeline stagessetup.py: Package installation configuration
DeepLabCut/: External library (EXCLUDE from analysis, treat as black box).claude/: AI assistant configuration (not committed)
Purpose: Manages all file paths and completion status for a single trial/video.
Key Responsibilities:
- Constructs exact file paths using DeepLabCut scorer naming conventions
- Tracks pipeline completion status via
.demba_registry.json - Provides methods to check which stages are complete
Important Attributes:
trial_dir: Path to trial directory (e.g.,Videos/trial1/)video_stem: Video filename without extensionscorer_name: DLC scorer string (e.g.,DLC_Resnet50_..._shuffle1_..._el)config_path: Path to DeepLabCut config.yaml
Key Methods:
tm.video_path() # Videos/trial1/trial1.mp4
tm.el_pickle_path() # trial1<scorer>_el.pickle (tracklets)
tm.h5_path() # trial1<scorer>.h5 (pose data)
tm.stitched_h5_path() # trial1<scorer>_el.h5 (stitched tracks)
tm.filtered_h5_path() # trial1<scorer>_el_filtered.h5
tm.id_correction_dir() # trial1/id_correction/
tm.is_stage_complete('stage_name') # Check completion status
tm.mark_stage_complete('stage_name') # Mark stage as doneValid Pipeline Stages:
pose_estimationidentity_correctiontracklet_stitchingfilteringfeature_extractionvisualization
Purpose: Manages project-level operations across multiple trials.
Key Responsibilities:
- Discovers all trial directories in
Videos/ - Provides batch access to TrialManager instances
- Filters trials by completion status
- Auto-detects quivering annotations
Expected Project Structure:
MyProject/
├── config.yaml # DeepLabCut project config
└── Analysis_<date>/ # Analysis directory
├── Videos/ # Required: Trial video directories
│ ├── trial1/ # Each trial in its own directory
│ │ ├── trial1.mp4 # Video file (name matches directory)
│ │ ├── trial1_roi.png # ROI image (optional)
│ │ └── ... # Pipeline outputs created here
│ ├── trial2/
│ └── ...
└── Annotations/ # Optional: Manual annotations
└── quivering_annotations.xlsx # Auto-detected by batch mode
Key Methods:
pm.list_trial_dirs() # List all trial directories
pm.get_trial_manager('trial1') # Get TrialManager for specific trial
pm.get_all_trial_managers() # Get all TrialManagers
pm.get_incomplete_trials('stage') # Filter by completion status
pm.find_quivering_annotations() # Auto-detect annotations file- What: Runs DeepLabCut multi-animal pose estimation
- Input: Video file, config.yaml
- Output:
*_full.pickle: Raw detections*_el.pickle: SORT-style tracklets (identity-unaware)
- Functions:
estimate_pose(trial_manager, n_fish, force_rerun)
- What: Trains CNN with triplet loss to assign consistent identities
- Input:
*_el.pickle(tracklets from pose estimation) - Output:
id_correction/encoder_model.pth: Trained CNNid_correction/patch_cache.pkl: Pre-extracted image patchesid_correction/embeddings.pkl: Per-detection embeddingsid_correction/cluster_comparison.mp4: Interactive mapping video*_el.pickle(updated with corrected IDs)
Two-Phase Approach:
-
Preparation Phase (non-interactive):
train_id_model(): Train CNN, extract embeddings, cluster- Saves metadata to
batch_metadata.json
-
Interactive Phase:
map_clusters_to_sex(): User maps clusters to identities- Saves mapping to
cluster_mapping.json
-
Finalization Phase (non-interactive):
assign_corrected_ids(): Apply mapping to tracklets
Key Classes:
PatchExtractor: Extract RGB patches from video based on keypointsCoOccupancyDetector: Find frames where both animals are visibleTripletDataset: Generate triplets for contrastive learningSimpleCNN: 4-layer CNN encoder (outputs 128-dim embeddings)TripletLoss: Contrastive loss with margin
Architecture Details:
- Input: 128×128 RGB patches
- CNN: 4 conv blocks (32→64→128→256 filters) + FC(512) + FC(128)
- Loss: Triplet loss with margin=1.0
- Training: Adam optimizer, early stopping, LR scheduling
- Clustering: KMeans (k=2) with silhouette score filtering
- Default threshold: silhouette ≥ 0.2 for ID assignment
- What: Combines short tracklets into continuous tracks (hard partition by identity)
- Input:
*_el.pickle(with corrected IDs) - Output:
*_el.h5: Stitched pose data in DLC format*_el.csv: CSV version
- Key Feature: Splits "conjoined" tracklets (those that switch identities) before stitching
- Functions:
stitch_by_identity(trial_manager, n_tracks, min_length, animal_names)
- What: Applies DeepLabCut's temporal smoothing to reduce jitter
- Input:
*_el.h5 - Output:
*_el_filtered.h5,*_el_filtered.csv - Functions:
filter_predictions(trial_manager)
- What: Extracts behavioral features (CICHLID-SPECIFIC)
- Input: Video + filtered pose data + optional annotations
- Output:
*_framefeatures.csv: Per-frame features*_clipfeatures.csv: Per-clip aggregated features*_featurevis.mp4: Visualization video (if enabled)
- Key Features: Mouthing events, double occupancy, spawning bouts, position tracking
- Functions:
process_video(trial_manager, quivering_annotation_path, visualize, n_minutes, min_likelihood)
- What: Creates labeled videos with skeleton overlays
- Input: Video + filtered pose data + config
- Output:
*_labeled.mp4: DLC labeled video- Identity consistency grids
- Functions:
create_labeled_video(trial_manager),create_identity_consistency_grids(trial_manager)
- What: Statistical analysis across all trials (PROJECT-LEVEL)
- Input: All trial feature CSVs
- Output: Boxplots, correlation plots, heatmaps
- Functions:
Plotterclass with methods for each plot type
Individual Stages:
python main.py pose --video Videos/trial1/trial1.mp4 --dlc-config config.yaml
python main.py id-correction --video Videos/trial1/trial1.mp4 --dlc-config config.yaml
python main.py stitch --video Videos/trial1/trial1.mp4 --dlc-config config.yaml
python main.py filter --video Videos/trial1/trial1.mp4 --dlc-config config.yaml
python main.py features --video Videos/trial1/trial1.mp4 --dlc-config config.yaml
python main.py visualize --video Videos/trial1/trial1.mp4 --dlc-config config.yaml
python main.py analyze --project-dir /path/to/AnalysisFull Pipeline (Single Trial):
python main.py full --video Videos/trial1/trial1.mp4 --dlc-config config.yamlBatch Mode (Multiple Trials):
python main.py batch --project-dir /path/to/AnalysisBatch Mode Flow:
- Phase 1 (Preparation): Pose + ID training (non-interactive, can run overnight)
- Phase 2 (Interactive): Cluster mapping for all trials (batched user input)
- Phase 3 (Finalization): ID assignment + remaining pipeline (non-interactive)
Key Benefit: All interactive steps done at once, rest runs unattended.
Shared Parameters:
VIDEO_FPS = 30DEFAULT_N_FISH = 2DEFAULT_SHUFFLE = 1ROI_RADIUS_MM = 79.375(breeding pipe radius)
ID Correction Parameters (Most Important):
DEFAULT_PATCH_SIZE = 128DEFAULT_PADDING = 10DEFAULT_ID_N_EPOCHS = 200(early stopping usually terminates earlier)DEFAULT_ID_BATCH_SIZE = 32DEFAULT_MIN_SILHOUETTE = 0.2(quality threshold for ID assignment)DEFAULT_ID_CACHE_FRAME_STRIDE = 5(sample every Nth frame for caching)DEFAULT_MIN_TRACKLET_LENGTH = 60DEFAULT_MIN_OVERLAP_FRAMES = 30
Feature Extraction Parameters:
DEFAULT_MOUTHING_DIST_MM = 10DEFAULT_MIN_LIKELIHOOD = 0.5
Problem: Low silhouette scores (<0.3 mean)
- Cause: Individuals too visually similar
- Solutions:
- Decrease
frame_stridefor more diverse training samples - Lower
min_silhouettethreshold to accept more assignments - Check if individuals actually have visual differences
- Decrease
Problem: Few co-occupancy frames (<100)
- Cause: Animals rarely visible together
- Solutions:
- Adjust
conf_threshold(lower to include more detections) - Verify both animals are in the video
- Check video quality
- Adjust
Problem: Poor clustering separation
- Cause: Individuals visually identical
- Solutions:
- Consider using behavioral features for post-hoc refinement
- Use location preferences or movement patterns
- May need different approach than visual appearance
Given: Video at Videos/trial1/trial1.mp4 and config.yaml
Expected Files:
- After pose:
Videos/trial1/trial1<scorer>_el.pickle - After ID:
Videos/trial1/id_correction/encoder_model.pth - After stitching:
Videos/trial1/trial1<scorer>_el.h5 - After filtering:
Videos/trial1/trial1<scorer>_el_filtered.h5 - After features:
Videos/trial1/trial1_mdist10mm_likelihood0.5_framefeatures.csv
Scorer Format: DLC_<backbone>_<project><date>shuffle<n>_detector_<snapshot>_snapshot_<snapshot>
import demba
# Create trial manager
from demba.file_manager import TrialManager
tm = TrialManager(
trial_dir='Videos/trial1',
config_path='config.yaml'
)
# Run individual stages
demba.estimate_pose(trial_manager=tm, n_fish=2)
demba.identity_correction.train_id_model(tracklet_path=tm.el_pickle_path())
cluster_mapping = demba.identity_correction.map_clusters_to_sex(prep_data)
demba.stitch_by_identity(trial_manager=tm, n_tracks=2)
demba.filter_predictions(trial_manager=tm)
demba.process_video(trial_manager=tm, visualize=False)- Current Branch:
tucker_dev - Main Branch:
main - Modified Files:
demba/tracklet_stitching.pymain.py
- Untracked:
.claude/(AI config)main_old.py(backup)
7dd44d0- Fixing missed pickle update between steps for batch operation399afed- Reweighting clip choice function for interactive ID7a6ebdf- Fixing tkinter thread safety violation89d1b25- Adding batch mode41e7b82- Adding batch mode
- DLC Approach: Graph optimization with ReID as soft bias
- DemBA Approach:
- Split tracklets at identity boundaries
- Partition by identity before stitching
- Stitch each identity group independently
- No cross-identity graph optimization
Benefit: Stricter identity enforcement, simpler, more robust on long videos
Challenge: Interactive step blocks automation
Solution: Three-phase separation
- Preparation: All non-interactive work (pose + training)
- Interactive: All user input at once (cluster mapping)
- Finalization: All remaining work (stitching + features)
Implementation: Uses metadata caching system in utils/gen_utils.py
- Each trial has
.demba_registry.jsontracking stage completion - Enables resume-on-failure for batch processing
- Prevents redundant computation
-
Mouthing Events: Male nose near female lateral line stripe
- Threshold:
DEFAULT_MOUTHING_DIST_MM = 10mm - Clustering: DBSCAN with
eps=5,min_samples=10
- Threshold:
-
Double Occupancy: Both fish in ROI simultaneously
- Clustering: DBSCAN with
eps=30,min_samples=30
- Clustering: DBSCAN with
-
Spawning Bouts: Clusters of mouthing events
- Clustering: DBSCAN on mouthing endpoints with
eps=300,min_samples=6
- Clustering: DBSCAN on mouthing endpoints with
-
Position Tracking: Coordinates relative to ROI center
Output Files:
framefeatures.csv: Per-frame boolean flags and continuous valuesclipfeatures.csv: Aggregated statistics per behavioral bout
- File Path Questions: Always reference
TrialManagerorProjectManagermethods - Pipeline Stage Questions: Check
VALID_STAGESlist and execution order - Configuration Questions: Reference
config.pyconstants - ID Correction Questions: This is the core innovation, explain thoroughly
- Batch Mode Questions: Emphasize three-phase structure
"How do I run X?" → Provide CLI command + mention corresponding function in API
"Where is file Y located?" → Reference TrialManager method that constructs the path
"Pipeline stage Z failed" → Check if it's ID correction (most complex), provide troubleshooting steps
"How does identity correction work?" → Explain triplet loss, co-occupancy detection, clustering, interactive mapping
"What's different from DeepLabCut?" → Highlight: (1) CNN vs Transformer ReID, (2) Hard-partition vs soft-constraint stitching, (3) Unsupervised vs supervised ID
- Don't re-read README.md unless user asks about high-level concepts
- Use this guide for file paths, stage order, and architecture
- Reference config.py for parameter defaults instead of searching code
- Use file_manager.py for understanding file naming conventions
- Focus on identity_correction.py only when ID-related questions arise
.mp4: Video files.pickle: DLC tracklet data (serialized Tracklet objects).h5: Pose data in HDF5 format (DLC standard).csv: Pose data in CSV format.pth: PyTorch model weights.pkl: Cached patch data or embeddings.json: Metadata (registry, cluster mapping, batch metadata).png: Images (ROI, visualizations).xlsx: Excel annotations (manual behavioral annotations)
This guide provides the essential orientation for understanding the DemBA codebase. For detailed algorithmic questions, refer to specific module docstrings. For usage questions, consult the CLI commands and API examples above.
Core Takeaway: DemBA is a 7-stage pipeline where identity correction (Stage 2) is the key innovation, using CNN triplet loss and hard-partition stitching to maintain consistent identities across long multi-animal videos.