Skip to content

Miscellaneous imports and code fixes - #3411

Merged
deruyter92 merged 20 commits into
mainfrom
external/hwang-misc-fixes
Jul 20, 2026
Merged

Miscellaneous imports and code fixes#3411
deruyter92 merged 20 commits into
mainfrom
external/hwang-misc-fixes

Conversation

claude and others added 11 commits July 15, 2026 15:43
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
@C-Achard C-Achard self-assigned this Jul 16, 2026
@C-Achard C-Achard added the bug fix! fix for a real buggy one... label Jul 16, 2026
C-Achard added 8 commits July 16, 2026 09:22
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
C-Achard marked this pull request as ready for review July 16, 2026 07:42
@deruyter92

Copy link
Copy Markdown
Collaborator

Good, well scoped fixes! Would be nice to include in the next release

@C-Achard

Copy link
Copy Markdown
Collaborator Author

Thanks @Denny-Hwang !

@C-Achard C-Achard added this to the v3.0.1 milestone Jul 16, 2026
@C-Achard

Copy link
Copy Markdown
Collaborator Author

Good, well scoped fixes! Would be nice to include in the next release

Milestone added

@C-Achard
C-Achard requested review from AlexEMG and MMathisLab July 16, 2026 11:30
@deruyter92
deruyter92 merged commit 040db9f into main Jul 20, 2026
12 checks passed
@deruyter92
deruyter92 deleted the external/hwang-misc-fixes branch July 20, 2026 11:39
@deruyter92 deruyter92 mentioned this pull request Jul 20, 2026
9 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug fix! fix for a real buggy one...

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants