Add hierarchical track classification - #1847
Open
PaulHax wants to merge 6 commits into
Open
Conversation
Additive configuration import now follows JSON merge semantics at the top level: an explicit null clears the stored hierarchy, an empty map still makes no change, and a non-empty map still adds edges.
`markTypeHierarchyPersisted` cleared the dirty flag unconditionally once the save resolved. A hierarchy edit made while that save was in flight was acknowledged as persisted and never sent. The acknowledgement now carries the patch that was actually sent and only clears the flag when the current state still matches it. Renaming a type on a flat multicamera dataset walked the merged track view, whose confidence vector can hide a type an individual camera still carries, so those tracks kept the old name. `updateTypeName` follows the base pass with a per-camera pass, next to the equivalent walk its hierarchy branch already does. `CameraStore.changeTrackTypes` provided this before and has had no callers since; it goes rather than sit alongside a second implementation.
Python's str.strip() treats U+001C-U+001F and U+0085 as blank and JS's String.trim() does not; trim() treats U+FEFF as blank and strip() does not. A name built from those characters was an empty child on one platform and a legitimate type on the other, so the same configuration validated differently depending on where it was imported. Both normalizers test the union instead. The two shared-spec cases cover a child blank only under strip() and a parent blank only under trim(), so neither platform can drift again without the other's suite failing.
This was referenced Aug 14, 2026
PaulHax
marked this pull request as ready for review
August 14, 2026 03:45
BryonLewis
self-requested a review
August 14, 2026 15:21
BryonLewis
approved these changes
Aug 14, 2026
BryonLewis
left a comment
Collaborator
There was a problem hiding this comment.
Going to approve with some notes about missing or future PRs that should be done.
First internal Notes for me:
- easily over 2/3 of the changes are tests modifications
- The front-end touches many files because of a difference in how styling and confidence pairs are passed to UI elements and Layers. This means most UI elements that display types or colors (lots of them) and the Layers that display colors needed to be updated
- Expansive logic for preventing circular or weird hierarchy data imports
- care given to supporting multicamera and hierarchy types
Future PRs/Notes:
- Type list is completely flat even with a hierarchy specified it is set as flat
- When toggling a parent type I would assume that children should be toggled on/off as well. This can be done after this stack is merged
- Counts for a parent should be a sum of all of the children types
- If a confidence pair parent isn't explicitly stated it won't automtically fallover to displaying the parent if the child is toggled off
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add hierarchical track classification
This PR adds an optional type hierarchy to each dataset. For example, a dataset can define
fishas the parent of
shark. It can then definesharkas the parent ofgreat white shark.DIVE keeps the existing
confidencePairson each track. The hierarchy is a display and editingrule. It does not add hierarchy data to tracks or change the annotation schema.
Selection
The viewer selects the deepest checked type that meets its confidence threshold. If
great white sharkdoes not meet its threshold, the viewer can selectshark.Configuration
DIVE stores the hierarchy as
typeHierarchyin DIVE Configuration JSON. The value maps each childtype to its direct parent.
nulland{}delete the hierarchy during an overwrite import.nulldeletes and{}makes no change.DIVE Annotation JSON, VIAME CSV, KPF, and NIST files do not carry the hierarchy. PR 5 adds KWCOCO
transport.
Type editing
Counterpart tracks now copy the complete confidence vector from the source track. Delete Type now
checks the tracks in every camera. These two corrections also apply to flat multicamera datasets.
Validation
The server and client use the same validation examples. Server code validates stored hierarchy
data. Client code handles traversal, rename, selection, and editing.
Manual tests
Test data: download and extract
classification.zip. Paths
below are relative to
dive-classification-test-data/. If the attachment is not available, generatethe same ZIP from PaulHax/dive-devkit.
Web single-camera import
media/image-sequence/, importclassification/single-camera-linked-types/tracks.annotations.jsonandtype-hierarchy.config.json, then play all frames, save, and reload.Verify: The three leaf types display, and the hierarchy and confidence pairs remain after reload.
Desktop single-camera import
media/image-sequence/, importclassification/single-camera-linked-types/tracks.annotations.jsonandtype-hierarchy.config.json, then play all frames, save, and reload.Verify: The three leaf types display, and the hierarchy and confidence pairs remain after reload.
Matching multicamera import
media/multicamera/, import the matching port and starboardfiles from
classification/multicamera-linked-types/, then import its hierarchy configuration.Verify: Both cameras show the same three linked tracks and confidence pairs.
Real SEFSC-SEAMAP video import
classification/sefsc-seamap-fish-taxonomy/, wait for processing, then import its VIAME CSV andconfiguration JSON.
Verify: The dataset contains 24 real tracks across eight observed species. The hierarchy includes
seriola_rivoliana→seriola→carangidaeand remains after reload.Hierarchy threshold fallback
media/image-sequence/, then import the annotations andconfiguration from
hierarchy/valid-three-level-forest/.bluefin-tunato0.95, then settunato0.25.Verify: The first change selects the parent, and the second change selects the root.
Invalid hierarchy import
dive-classification-test-data/hierarchy/valid-three-level-forest/multipair.annotations.jsonand
three-level-forest.config.json.dive-classification-test-data/hierarchy/invalid-configurations/as DIVE Configuration JSON.Verify: DIVE rejects the file and keeps the valid hierarchy.
Limits
Stack
This is PR 4 of 9. Previous: isolate soft-clone metadata.
Next: centralize classification changes.
This PR is stacked on
clone-metadata-copy.Overall: 56 files, +6,213/-385. Commits:
951ad2f1throughf583e248.