Miscellaneous imports and code fixes - #3411
Merged
Merged
Conversation
analyzebone() computed each skeleton bone's likelihood as min(bp2.likelihood, bp2.likelihood), stacking the second bodypart twice and discarding bp1. The adjacent comment states the intent is 'keep the smallest of the two likelihoods', so the result should be min(bp1.likelihood, bp2.likelihood). As written, a bone whose first bodypart is occluded (low confidence) but whose second bodypart is confident was reported as fully confident, silently corrupting the likelihood column of every skeleton analysis output.
In SORTSkeleton.track, the reverse-iteration cleanup loop maintains i as the current tracker's index but removed dead trackers with self.trackers.pop() (removes the last element) instead of self.trackers.pop(i). The sibling classes SORTBox and SORTEllipse correctly use pop(i). With a stale tracker in the middle of the list, pop() deleted a different (often still-live) tracker; the dead one persisted and animalindex[i] alignment broke, corrupting identity/tracklet assignment for the skeleton track method.
When a frame lost all individuals (NMS mask all-False), the reset branch assigned self._idx_ages = None, but the tracking-age attribute is _ctd_track_ages (initialised in __init__ and used by _ctd_tracking_postprocess). _idx_ages is never read anywhere, so the intended reset silently did nothing and a dead attribute was created. As a result _ctd_track_ages kept its stale values; on the next BU-seeded frame the OKS-NMS ordering was biased toward stale-old indices, retaining the wrong pose/identity, and the bias compounded over subsequent frames. Reset the correct attribute.
filterpredictions() and analyzeskeleton() reassigned the destfolder parameter inside their 'for video in Videos' loop when it was None. After the first iteration destfolder stayed pinned to the first video's folder, so videos located in a different folder were looked up in the wrong place: load_analyzed_data raised FileNotFoundError and the video was silently reported as not analyzed (and any output would go to the wrong folder). Use a per-iteration local 'videofolder' instead of mutating the parameter, matching plot_trajectories and extract_outlier_frames.
In extract_outlier_frames (outlieralgorithm='list'), the handler was written 'except ValueError():', which evaluates ValueError() to an instance. When the try body raised a ValueError, Python's exception matching hit a non-class handler and raised 'TypeError: catching classes that do not inherit from BaseException is not allowed', masking the real error and the intended message. Catch the ValueError type instead.
…mespace) predict_multianimal.py imported 'from scipy.ndimage import measurements'. The scipy.ndimage.measurements submodule was deprecated in scipy 1.8 and removed in scipy 1.14; since the project pins scipy>=1.9 with no upper bound, a fresh install resolves a scipy where this import raises ImportError at module load. Because the module is imported at the top of the TensorFlow multi-animal inference path, analyze_videos on a TF maDLC project failed immediately on import. Import label and center_of_mass directly from scipy.ndimage (their canonical public location) and call them without the measurements prefix.
test.py used np.zeros(..., dtype=np.object). np.object was a deprecated alias for the builtin object and was removed in numpy 1.24, so it raises AttributeError under the pinned numpy (>=1.18.5,<2 resolves to 1.26). Use dtype=object.
The mask 'conds <= 0 | np.isnan(conds)' parses as 'conds <= (0 | np.isnan(conds))' because bitwise | binds tighter than the <= comparison, so the NaN check was not OR-ed with the non-positive check as intended. Parenthesize to '(conds <= 0) | np.isnan(conds)'. Verified: for conds=[0.5, -0.1, nan] the buggy expression yields [False, True, False] (misses the NaN), while the fixed expression yields [False, True, True].
SORTEllipse.track indexed mode(identities[i])[0][0]. Since scipy 1.11 mode defaults to keepdims=False, so mode(1d)[0] is already a scalar and the second [0] raises IndexError. Pass keepdims=False explicitly and take a single [0], matching the pattern already used in refine_training_dataset/stitch.py. These sites are in the identity-aware branch of SORTEllipse.track, which is currently only reached when 'identities' is passed to track() (no in-tree caller does), so this is a latent fix rather than a live regression.
Fix bone likelihood in analyzebone to use both bodyparts
Fix except clause catching a ValueError instance instead of the type
Import scipy.ndimage functions directly (drop removed measurements namespace) predict_multianimal.py imported 'from scipy.ndimage import measurements'. The scipy.ndimage.measurements submodule was deprecated in scipy 1.8 and removed in scipy 1.14; since the project pins scipy>=1.9 with no upper bound, a fresh install resolves a scipy where this import raises ImportError at module load. Because the module is imported at the top of the TensorFlow multi-animal inference path, analyze_videos on a TF maDLC project failed immediately on import. Import label and center_of_mass directly from scipy.ndimage (their canonical public location) and call them without the measurements prefix.
Replace removed np.object alias with builtin object
Fix scipy.stats.mode usage for keepdims=False default (scipy>=1.11)
Fix operator precedence in condition NaN/non-positive mask
Fix SORTSkeleton removing the wrong tracker on cleanup
Fix CTD tracklet-age reset writing to a non-existent attribute
Fix destfolder leaking across videos in filter/skeleton loops
C-Achard
marked this pull request as ready for review
July 16, 2026 07:42
deruyter92
approved these changes
Jul 16, 2026
Collaborator
|
Good, well scoped fixes! Would be nice to include in the next release |
Collaborator
Author
|
Thanks @Denny-Hwang ! |
Collaborator
Author
Milestone added |
MMathisLab
approved these changes
Jul 17, 2026
AlexEMG
approved these changes
Jul 18, 2026
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.
This PR groups several patches contributed by @Denny-Hwang.
Includes: