quantumjot / btrack

Bayesian multi-object tracking
https://btrack.readthedocs.io
MIT License
311 stars 50 forks source link

Can't print or assign tracks tracker.tracks or tracker.to_napari() #187

Closed joaomamede closed 1 year ago

joaomamede commented 1 year ago

Tracking runs well, but I can't get any of the data to plot and analyze. Only way something outputs is if I do something like tracker.tracks[0].t I tried in my usual conda env *python 3.8" and created a fresh conda env with python 3.10. Same errors occur in both of them. The same happens with the datasets from btrack.datasets Any hints?

import btrack

objects = btrack.dataio.localizations_to_objects(df_roi.loc[:,['ID','t','y','x','label','prob']])
tracker = btrack.BayesianTracker()
_config = datasets.cell_config()

tracker.configure_from_file(_config)
tracker.verbose = True
tracker.max_search_radius = 100
# FEATURES = ["prob"]
# tracker.features = FEATURES

tracker.append(objects)
tracker.volume = ((ymin,ymax), (xmin,xmax))
tracker.track_interactive(step_size=100)

[INFO][2022/11/06 11:13:58 AM] Loaded btrack: /home/uname/anaconda3/envs/btrack/lib/python3.10/site-packages/btrack/libs/libtracker.so [INFO][2022/11/06 11:13:58 AM] btrack (v0.4.6) library imported [INFO][2022/11/06 11:13:58 AM] Loading configuration file: /home/uname/.cache/btrack-examples/examples/cell_config.json [INFO][2022/11/06 11:13:58 AM] Setting max_search_radius -> 100 [INFO][2022/11/06 11:13:58 AM] Objects are of type: <class 'list'> [INFO][2022/11/06 11:13:58 AM] Setting volume -> ((3128.582761836401, 3749.9067173722374), (3725.1669374257453, 4465.871914985935)) [WARNING][2022/11/06 11:13:58 AM] track_interactive will be deprecated. Use track instead. [INFO][2022/11/06 11:13:58 AM] Starting tracking... [INFO][2022/11/06 11:13:58 AM] Tracking objects in frames 0 to 99 (of 224)... [INFO][2022/11/06 11:13:58 AM] - Timing (Bayesian updates: 0.00ms, Linking: 0.01ms) [INFO][2022/11/06 11:13:58 AM] - Probabilities (Link: 0.00000, Lost: 0.95877) [INFO][2022/11/06 11:13:58 AM] - Stats (Active: 0, Lost: 6, Conflicts resolved: 0) [INFO][2022/11/06 11:13:58 AM] Tracking objects in frames 100 to 199 (of 224)... [INFO][2022/11/06 11:13:58 AM] - Timing (Bayesian updates: 0.00ms, Linking: 0.02ms) [INFO][2022/11/06 11:13:58 AM] - Probabilities (Link: 0.00000, Lost: 0.95877) [INFO][2022/11/06 11:13:58 AM] - Stats (Active: 0, Lost: 6, Conflicts resolved: 0) [INFO][2022/11/06 11:13:58 AM] Tracking objects in frames 200 to 224 (of 224)... [INFO][2022/11/06 11:13:58 AM] - Timing (Bayesian updates: 0.00ms, Linking: 0.01ms) [INFO][2022/11/06 11:13:58 AM] - Probabilities (Link: 0.00000, Lost: 0.95877) [INFO][2022/11/06 11:13:58 AM] SUCCESS. [INFO][2022/11/06 11:13:58 AM] - Found 4898 tracks in 224 frames (in 0.0s) [INFO][2022/11/06 11:14:00 AM] - Inserted 0 dummy objects to fill tracking gaps

tracks = tracker.tracks

print(tracks[10].t,tracks[10].x,tracks[10].y)`

[0] [4018.0] [3736.0]

tracks

ValueError Traceback (most recent call last) File ~/anaconda3/envs/btrack/lib/python3.10/site-packages/IPython/core/formatters.py:706, in PlainTextFormatter.call(self, obj) 699 stream = StringIO() 700 printer = pretty.RepresentationPrinter(stream, self.verbose, 701 self.max_width, self.newline, 702 max_seq_length=self.max_seq_length, 703 singleton_pprinters=self.singleton_printers, 704 type_pprinters=self.type_printers, 705 deferred_pprinters=self.deferred_printers) --> 706 printer.pretty(obj) 707 printer.flush() 708 return stream.getvalue()

File ~/anaconda3/envs/btrack/lib/python3.10/site-packages/IPython/lib/pretty.py:393, in RepresentationPrinter.pretty(self, obj) 390 for cls in _get_mro(obj_class): 391 if cls in self.type_pprinters: 392 # printer registered in self.type_pprinters --> 393 return self.type_pprinters[cls](obj, self, cycle) 394 else: 395 # deferred printer 396 printer = self._in_deferred_types(cls)

File ~/anaconda3/envs/btrack/lib/python3.10/site-packages/IPython/lib/pretty.py:640, in _seq_pprinter_factory..inner(obj, p, cycle) 638 p.text(',') ... 713 'error in %s.missing: returned %r instead of None or a valid member' 714 % (cls.name, result) 715 )

ValueError: 88 is not a valid States

data, properties, graph = tracker.to_napari()

ValueError Traceback (most recent call last) Cell In [30], line 2 1 # tracker.export('/home/jmamede/tracks.h5', obj_type='obj_type_1') ----> 2 data, properties, graph = tracker.to_napari() 3 #

File ~/anaconda3/envs/btrack/lib/python3.10/site-packages/btrack/core.py:672, in BayesianTracker.to_napari(self, replace_nan, ndim) 667 """Return the data in a format for a napari tracks layer. 668 See :py:meth:btrack.utils.tracks_to_napari.""" 670 ndim = self.configuration.volume.ndim if ndim is None else ndim --> 672 return utils.tracks_to_napari( 673 self.tracks, ndim, replace_nan=replace_nan 674 )

File ~/anaconda3/envs/btrack/lib/python3.10/site-packages/btrack/utils.py:194, in tracks_to_napari(tracks, ndim, replace_nan) 192 ordered = sorted(list(tracks), key=lambda t: t.ID) 193 header = t_header + p_header --> 194 tracks_as_dict = _cat_tracks_as_dict(ordered, header) 196 # note that there may be other metadata in the tracks, grab that too 197 prop_keys = p_header + [ 198 k for k in tracks_as_dict.keys() if k not in t_header 199 ]

File ~/anaconda3/envs/btrack/lib/python3.10/site-packages/btrack/utils.py:111, in _cat_tracks_as_dict(tracks, properties) ... 713 'error in %s.missing: returned %r instead of None or a valid member' 714 % (cls.name, result) 715 )

ValueError: 88 is not a valid States

quantumjot commented 1 year ago

Super weird! It looks like something is going wrong with localizations_to_objects(). What happens when you print(objects[0])?

joaomamede commented 1 year ago

localization_to_objects() is working well. I have the objects the same way I would with all the other available methods. Then it tracks and runs all the steps. It's the output after tracking that fails. either tracker.to_napari() or tracker.tracks

If I do something likethis: print(tracks[10].t,tracks[10].x,tracks[10].y)

It outputs the values of the tracking: [0] [4018.0] [3736.0]

joaomamede commented 1 year ago

I will try to make a custom _cat_tracks_as_dict() and a tracks_to_napari() using pandas/pytables to see if I can do the same as the code intends. Hopefully I can find the bug in the meantime.

quantumjot commented 1 year ago

It's this line that makes me wonder if something has happened with the objects: ValueError: 88 is not a valid States

joaomamede commented 1 year ago

Somehow it works in my laptop but not in the server. It might be an ipython incompatiblity? I'll just upgrade as much as I can to see if it goes away.

They don't seem to have been modified original == objects

True

original == tracker.objects

True

First few objects:

[{'ID': 0, 'x': 752.3367346938776, 'y': 223.6887755102041, 'z': 0.0, 't': 0, 'dummy': False, 'states': 0, 'label': 31, 'prob': 0.0, 'intensity_mean': 4965.189239332097, 'intensity_max': 14326.0, 'intensity_min': 1158.0, 'area': 2156, 'orientation': 1.3761437671912058, 'axis_major_length': 58.08160972865572, 'axis_minor_length': 47.42154293541069, 'eccentricity': 0.5773963460335567}, {'ID': 1, 'x': 677.355309218203, 'y': 610.8733955659277, 'z': 0.0, 't': 0, 'dummy': False, 'states': 0, 'label': 212, 'prob': 0.0, 'intensity_mean': 6125.360560093349, 'intensity_max': 17822.0, 'intensity_min': 1670.0, 'area': 1714, 'orientation': -0.1482594019766971, 'axis_major_length': 51.9901911947701, 'axis_minor_length': 42.54465571011461, 'eccentricity': 0.5747617373037514}, After: [{'ID': 0, 'x': 752.3367346938776, 'y': 223.6887755102041, 'z': 0.0, 't': 0, 'dummy': False, 'states': 0, 'label': 31, 'prob': 0.0, 'intensity_mean': 4965.189239332097, 'intensity_max': 14326.0, 'intensity_min': 1158.0, 'area': 2156, 'orientation': 1.3761437671912058, 'axis_major_length': 58.08160972865572, 'axis_minor_length': 47.42154293541069, 'eccentricity': 0.5773963460335567}, {'ID': 1, 'x': 677.355309218203, 'y': 610.8733955659277, 'z': 0.0, 't': 0, 'dummy': False, 'states': 0, 'label': 212, 'prob': 0.0, 'intensity_mean': 6125.360560093349, 'intensity_max': 17822.0, 'intensity_min': 1670.0, 'area': 1714, 'orientation': -0.1482594019766971, 'axis_major_length': 51.9901911947701, 'axis_minor_length': 42.54465571011461, 'eccentricity': 0.5747617373037514},

joaomamede commented 1 year ago

I updated conda, installed a environment based on the yml on the one that works on my laptop, same libs exactly. I still get the same error:

ValueError                                Traceback (most recent call last)
Cell In [17], line 5
      3 tracks
      4 # tracker.export('/home/jmamede/tracks.h5', obj_type='obj_type_1')
----> 5 data, properties, graph = tracker.to_napari()
      6 # 
      8 tracks = tracker.tracks

File ~/anaconda3/envs/tensorflow/lib/python3.9/site-packages/btrack/core.py:672, in BayesianTracker.to_napari(self, replace_nan, ndim)
    667 """Return the data in a format for a napari tracks layer.
    668 See :py:meth:`btrack.utils.tracks_to_napari`."""
    670 ndim = self.configuration.volume.ndim if ndim is None else ndim
--> 672 return utils.tracks_to_napari(
    673     self.tracks, ndim, replace_nan=replace_nan
    674 )

File ~/anaconda3/envs/tensorflow/lib/python3.9/site-packages/btrack/utils.py:194, in tracks_to_napari(tracks, ndim, replace_nan)
    192 ordered = sorted(list(tracks), key=lambda t: t.ID)
    193 header = t_header + p_header
--> 194 tracks_as_dict = _cat_tracks_as_dict(ordered, header)
    196 # note that there may be other metadata in the tracks, grab that too
    197 prop_keys = p_header + [
    198     k for k in tracks_as_dict.keys() if k not in t_header
    199 ]

File ~/anaconda3/envs/tensorflow/lib/python3.9/site-packages/btrack/utils.py:111, in _cat_tracks_as_dict(tracks, properties)
    108 data: dict = {}
    110 for track in tracks:
--> 111     trk = track.to_dict(properties)
    113     for key in trk.keys():
    114         trk_property = np.asarray(trk[key])

File ~/anaconda3/envs/tensorflow/lib/python3.9/site-packages/btrack/btypes.py:468, in Tracklet.to_dict(self, properties)
    464 def to_dict(self, properties: list = constants.DEFAULT_EXPORT_PROPERTIES):
    465     """Return a dictionary of the tracklet which can be used for JSON
    466     export. This is an ordered dictionary for nicer JSON output.
    467     """
--> 468     trk_tuple = tuple([(p, getattr(self, p)) for p in properties])
    469     data = OrderedDict(trk_tuple)
    470     data.update(self.properties)

File ~/anaconda3/envs/tensorflow/lib/python3.9/site-packages/btrack/btypes.py:468, in <listcomp>(.0)
    464 def to_dict(self, properties: list = constants.DEFAULT_EXPORT_PROPERTIES):
    465     """Return a dictionary of the tracklet which can be used for JSON
    466     export. This is an ordered dictionary for nicer JSON output.
    467     """
--> 468     trk_tuple = tuple([(p, getattr(self, p)) for p in properties])
    469     data = OrderedDict(trk_tuple)
    470     data.update(self.properties)

File ~/anaconda3/envs/tensorflow/lib/python3.9/site-packages/btrack/btypes.py:425, in Tracklet.state(self)
    423 @property
    424 def state(self) -> list:
--> 425     return [o.state.value for o in self._data]

File ~/anaconda3/envs/tensorflow/lib/python3.9/site-packages/btrack/btypes.py:425, in <listcomp>(.0)
    423 @property
    424 def state(self) -> list:
--> 425     return [o.state.value for o in self._data]

File ~/anaconda3/envs/tensorflow/lib/python3.9/site-packages/btrack/btypes.py:123, in PyTrackObject.state(self)
    121 @property
    122 def state(self) -> constants.States:
--> 123     return constants.States(self.label)

File ~/anaconda3/envs/tensorflow/lib/python3.9/enum.py:384, in EnumMeta.__call__(cls, value, names, module, qualname, type, start)
    359 """
    360 Either returns an existing member, or creates a new enum class.
    361 
   (...)
    381 `type`, if set, will be mixed in as the first base class.
    382 """
    383 if names is None:  # simple value lookup
--> 384     return cls.__new__(cls, value)
    385 # otherwise, functional API: we're creating a new Enum type
    386 return cls._create_(
    387         value,
    388         names,
   (...)
    392         start=start,
    393         )

File ~/anaconda3/envs/tensorflow/lib/python3.9/enum.py:702, in Enum.__new__(cls, value)
    700 ve_exc = ValueError("%r is not a valid %s" % (value, cls.__qualname__))
    701 if result is None and exc is None:
--> 702     raise ve_exc
    703 elif exc is None:
    704     exc = TypeError(
    705             'error in %s._missing_: returned %r instead of None or a valid member'
    706             % (cls.__name__, result)
    707             )

ValueError: 212 is not a valid States
quantumjot commented 1 year ago

OK - I see the issue now. Does it work if you omit label?

objects = btrack.dataio.localizations_to_objects(df_roi.loc[:,['ID','t','y','x','prob']])
joaomamede commented 1 year ago

I'll confirm tomorrow. But that was my hack indeed. To export everything but the label. It's superweird because it works completely fine on my laptop with more or less the same anaconda installed packaged.

joaomamede commented 1 year ago

That was indeed the problem. My cell pandas had the column "label" that I passed to the btrack objects and that was making everything break. I'll change the column name to "original_label" from my dataset. I'll close the issue.

In short, we can't add a "label" key to the dictionary.