napari-tmidas 0.2.1__py3-none-any.whl → 0.2.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,11 +8,8 @@ The plugin supports both 2D (YX) and 3D (TYX/ZYX) data.
8
8
 
9
9
  import contextlib
10
10
  import os
11
-
12
- # Add this at the beginning of your plugin file
13
11
  import sys
14
12
 
15
- sys.path.append("/opt/sam2")
16
13
  import numpy as np
17
14
  import requests
18
15
  import torch
@@ -40,10 +37,30 @@ from tifffile import imwrite
40
37
 
41
38
  from napari_tmidas.processing_functions.sam2_mp4 import tif_to_mp4
42
39
 
40
+ sam2_paths = [
41
+ os.environ.get("SAM2_PATH"),
42
+ "/opt/sam2",
43
+ os.path.expanduser("~/sam2"),
44
+ "./sam2",
45
+ ]
46
+
47
+ for path in sam2_paths:
48
+ if path and os.path.exists(path):
49
+ sys.path.append(path)
50
+ break
51
+ else:
52
+ print(
53
+ "Warning: SAM2 not found in common locations. Please set SAM2_PATH environment variable."
54
+ )
55
+
56
+
43
57
  def get_device():
44
58
  if sys.platform == "darwin":
45
59
  # MacOS: Only check for MPS
46
- if hasattr(torch.backends, "mps") and torch.backends.mps.is_available():
60
+ if (
61
+ hasattr(torch.backends, "mps")
62
+ and torch.backends.mps.is_available()
63
+ ):
47
64
  device = torch.device("mps")
48
65
  print("Using Apple Silicon GPU (MPS)")
49
66
  else:
@@ -60,8 +77,6 @@ def get_device():
60
77
  return device
61
78
 
62
79
 
63
-
64
-
65
80
  class BatchCropAnything:
66
81
  """Class for processing images with SAM2 and cropping selected objects."""
67
82
 
@@ -104,7 +119,7 @@ class BatchCropAnything:
104
119
  filename = os.path.join(dest_folder, url.split("/")[-1])
105
120
  if not os.path.exists(filename):
106
121
  print(f"Downloading checkpoint to {filename}...")
107
- response = requests.get(url, stream=True)
122
+ response = requests.get(url, stream=True, timeout=30)
108
123
  response.raise_for_status()
109
124
  with open(filename, "wb") as f:
110
125
  for chunk in response.iter_content(chunk_size=8192):
@@ -733,6 +748,15 @@ class BatchCropAnything:
733
748
  border_width=1,
734
749
  opacity=0.8,
735
750
  )
751
+
752
+ with contextlib.suppress(AttributeError, ValueError):
753
+ points_layer.mouse_drag_callbacks.remove(
754
+ self._on_points_clicked
755
+ )
756
+ points_layer.mouse_drag_callbacks.append(
757
+ self._on_points_clicked
758
+ )
759
+
736
760
  # Initialize points for this object
737
761
  if not hasattr(self, "sam2_points_by_obj"):
738
762
  self.sam2_points_by_obj = {}
@@ -1107,6 +1131,14 @@ class BatchCropAnything:
1107
1131
  opacity=0.8,
1108
1132
  )
1109
1133
 
1134
+ with contextlib.suppress(AttributeError, ValueError):
1135
+ points_layer.mouse_drag_callbacks.remove(
1136
+ self._on_points_clicked
1137
+ )
1138
+ points_layer.mouse_drag_callbacks.append(
1139
+ self._on_points_clicked
1140
+ )
1141
+
1110
1142
  # Connect points layer mouse click event
1111
1143
  points_layer.mouse_drag_callbacks.append(self._on_points_clicked)
1112
1144
 
@@ -1646,6 +1678,14 @@ class BatchCropAnything:
1646
1678
  border_width=1,
1647
1679
  opacity=0.8,
1648
1680
  )
1681
+ with contextlib.suppress(AttributeError, ValueError):
1682
+ points_layer.mouse_drag_callbacks.remove(
1683
+ self._on_points_clicked
1684
+ )
1685
+ points_layer.mouse_drag_callbacks.append(
1686
+ self._on_points_clicked
1687
+ )
1688
+
1649
1689
  self.obj_points[current_obj_id] = [[x, y]]
1650
1690
  self.obj_labels[current_obj_id] = [point_label]
1651
1691
  else:
@@ -1923,6 +1963,14 @@ class BatchCropAnything:
1923
1963
  opacity=0.8,
1924
1964
  )
1925
1965
 
1966
+ with contextlib.suppress(AttributeError, ValueError):
1967
+ self.points_layer.mouse_drag_callbacks.remove(
1968
+ self._on_points_clicked
1969
+ )
1970
+ self.points_layer.mouse_drag_callbacks.append(
1971
+ self._on_points_clicked
1972
+ )
1973
+
1926
1974
  def create_label_table(self, parent_widget):
1927
1975
  """Create a table widget displaying all detected labels."""
1928
1976
  # Create table widget
@@ -558,6 +558,10 @@ class ProcessingWorker(QThread):
558
558
  self.stop_requested = False
559
559
  self.thread_count = max(1, (os.cpu_count() or 4) - 1) # Default value
560
560
 
561
+ def stop(self):
562
+ """Request the worker to stop processing"""
563
+ self.stop_requested = True
564
+
561
565
  def run(self):
562
566
  """Process files in a separate thread"""
563
567
  # Track processed files
@@ -653,9 +657,12 @@ class ProcessingWorker(QThread):
653
657
  # Generate new filename base
654
658
  filename = os.path.basename(filepath)
655
659
  name, ext = os.path.splitext(filename)
656
- new_filename_base = (
657
- name.replace(self.input_suffix, "") + self.output_suffix
658
- )
660
+ if name.endswith(self.input_suffix):
661
+ new_filename_base = (
662
+ name[: -len(self.input_suffix)] + self.output_suffix
663
+ )
664
+ else:
665
+ new_filename_base = name + self.output_suffix
659
666
 
660
667
  # Check if the first dimension should be treated as channels
661
668
  # If processed_image has more dimensions than the original image,
@@ -779,13 +786,8 @@ class ProcessingWorker(QThread):
779
786
  "labels" in new_filename_base
780
787
  or "semantic" in new_filename_base
781
788
  ):
782
- # Choose appropriate integer type based on data range
783
- if data_max <= 255:
784
- save_dtype = np.uint8
785
- elif data_max <= 65535:
786
- save_dtype = np.uint16
787
- else:
788
- save_dtype = np.uint32
789
+
790
+ save_dtype = np.uint32
789
791
 
790
792
  print(
791
793
  f"Saving label image as {save_dtype.__name__} with bigtiff={use_bigtiff}"
@@ -2,6 +2,7 @@
2
2
  """
3
3
  Registry for batch processing functions.
4
4
  """
5
+ import threading
5
6
  from typing import Any, Dict, List, Optional
6
7
 
7
8
 
@@ -11,6 +12,7 @@ class BatchProcessingRegistry:
11
12
  """
12
13
 
13
14
  _processing_functions = {}
15
+ _lock = threading.RLock() # Add thread lock
14
16
 
15
17
  @classmethod
16
18
  def register(
@@ -43,26 +45,25 @@ class BatchProcessingRegistry:
43
45
  parameters = {}
44
46
 
45
47
  def decorator(func):
46
- cls._processing_functions[name] = {
47
- "func": func,
48
- "suffix": suffix,
49
- "description": description,
50
- "parameters": parameters,
51
- }
48
+ with cls._lock: # Thread-safe registration
49
+ cls._processing_functions[name] = {
50
+ "func": func,
51
+ "suffix": suffix,
52
+ "description": description,
53
+ "parameters": parameters,
54
+ }
52
55
  return func
53
56
 
54
57
  return decorator
55
58
 
56
59
  @classmethod
57
60
  def get_function_info(cls, name: str) -> Optional[dict]:
58
- """
59
- Retrieve a registered processing function and its metadata
60
- """
61
- return cls._processing_functions.get(name)
61
+ """Thread-safe retrieval"""
62
+ with cls._lock:
63
+ return cls._processing_functions.get(name)
62
64
 
63
65
  @classmethod
64
66
  def list_functions(cls) -> List[str]:
65
- """
66
- List all registered processing function names
67
- """
68
- return list(cls._processing_functions.keys())
67
+ """Thread-safe listing"""
68
+ with cls._lock:
69
+ return list(cls._processing_functions.keys())
@@ -0,0 +1,90 @@
1
+ # src/napari_tmidas/_tests/test_file_selector.py
2
+ import os
3
+ import tempfile
4
+ from unittest.mock import Mock
5
+
6
+ import numpy as np
7
+
8
+ from napari_tmidas._file_selector import ProcessingWorker, file_selector
9
+ from napari_tmidas._registry import BatchProcessingRegistry
10
+
11
+
12
+ class TestProcessingWorker:
13
+ def setup_method(self):
14
+ """Setup test environment"""
15
+ self.temp_dir = tempfile.mkdtemp()
16
+ BatchProcessingRegistry._processing_functions.clear()
17
+
18
+ # Register a test function
19
+ @BatchProcessingRegistry.register(name="Test Process", suffix="_proc")
20
+ def test_process(image):
21
+ return image * 2
22
+
23
+ self.test_func = BatchProcessingRegistry.get_function_info(
24
+ "Test Process"
25
+ )["func"]
26
+
27
+ def teardown_method(self):
28
+ """Cleanup"""
29
+ import shutil
30
+
31
+ shutil.rmtree(self.temp_dir)
32
+
33
+ def test_process_file(self):
34
+ """Test processing a single file"""
35
+ # Create test image
36
+ test_image = np.random.rand(100, 100)
37
+ input_path = os.path.join(self.temp_dir, "test.tif")
38
+
39
+ import tifffile
40
+
41
+ tifffile.imwrite(input_path, test_image)
42
+
43
+ # Create worker
44
+ worker = ProcessingWorker(
45
+ [input_path], self.test_func, {}, self.temp_dir, "", "_proc"
46
+ )
47
+
48
+ # Process file
49
+ result = worker.process_file(input_path)
50
+
51
+ assert result is not None
52
+ assert "original_file" in result
53
+ assert "processed_file" in result
54
+ assert os.path.exists(result["processed_file"])
55
+
56
+ def test_multi_channel_output(self):
57
+ """Test processing that outputs multiple channels"""
58
+
59
+ @BatchProcessingRegistry.register(
60
+ name="Split Channels", suffix="_split"
61
+ )
62
+ def split_channels(image):
63
+ return np.stack([image, image * 2, image * 3])
64
+
65
+ test_image = np.random.rand(100, 100)
66
+ input_path = os.path.join(self.temp_dir, "test.tif")
67
+
68
+ import tifffile
69
+
70
+ tifffile.imwrite(input_path, test_image)
71
+
72
+ func_info = BatchProcessingRegistry.get_function_info("Split Channels")
73
+ worker = ProcessingWorker(
74
+ [input_path], func_info["func"], {}, self.temp_dir, "", "_split"
75
+ )
76
+
77
+ result = worker.process_file(input_path)
78
+
79
+ assert "processed_files" in result
80
+ assert len(result["processed_files"]) == 3
81
+
82
+
83
+ class TestFileSelector:
84
+ def test_file_selector_widget_creation(self):
85
+ """Test that file selector widget is created properly"""
86
+ viewer_mock = Mock()
87
+
88
+ # Test the widget can be called
89
+ result = file_selector(viewer_mock, "/tmp", ".tif")
90
+ assert isinstance(result, list)
@@ -0,0 +1,67 @@
1
+ # src/napari_tmidas/_tests/test_registry.py
2
+ from napari_tmidas._registry import BatchProcessingRegistry
3
+
4
+
5
+ class TestBatchProcessingRegistry:
6
+ def setup_method(self):
7
+ """Clear registry before each test"""
8
+ BatchProcessingRegistry._processing_functions.clear()
9
+
10
+ def test_register_function(self):
11
+ """Test registering a processing function"""
12
+
13
+ @BatchProcessingRegistry.register(
14
+ name="Test Function",
15
+ suffix="_test",
16
+ description="Test description",
17
+ parameters={"param1": {"type": int, "default": 5}},
18
+ )
19
+ def test_func(image, param1=5):
20
+ return image + param1
21
+
22
+ assert "Test Function" in BatchProcessingRegistry.list_functions()
23
+ info = BatchProcessingRegistry.get_function_info("Test Function")
24
+ assert info["suffix"] == "_test"
25
+ assert info["description"] == "Test description"
26
+ assert info["func"] == test_func
27
+
28
+ def test_list_functions(self):
29
+ """Test listing registered functions"""
30
+
31
+ @BatchProcessingRegistry.register(name="Func1")
32
+ def func1(image):
33
+ return image
34
+
35
+ @BatchProcessingRegistry.register(name="Func2")
36
+ def func2(image):
37
+ return image
38
+
39
+ functions = BatchProcessingRegistry.list_functions()
40
+ assert len(functions) == 2
41
+ assert "Func1" in functions
42
+ assert "Func2" in functions
43
+
44
+ def test_thread_safety(self):
45
+ """Test thread-safe registration"""
46
+ import threading
47
+
48
+ results = []
49
+
50
+ def register_func(i):
51
+ @BatchProcessingRegistry.register(name=f"ThreadFunc{i}")
52
+ def func(image):
53
+ return image
54
+
55
+ results.append(i)
56
+
57
+ threads = [
58
+ threading.Thread(target=register_func, args=(i,))
59
+ for i in range(10)
60
+ ]
61
+ for t in threads:
62
+ t.start()
63
+ for t in threads:
64
+ t.join()
65
+
66
+ assert len(results) == 10
67
+ assert len(BatchProcessingRegistry.list_functions()) == 10
napari_tmidas/_version.py CHANGED
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '0.2.1'
21
- __version_tuple__ = version_tuple = (0, 2, 1)
20
+ __version__ = version = '0.2.2'
21
+ __version_tuple__ = version_tuple = (0, 2, 2)
@@ -252,16 +252,35 @@ def trackastra_tracking(
252
252
 
253
253
  temp_dir = Path(os.path.dirname(img_path))
254
254
 
255
- # Save the mask data
256
- mask_path = img_path.replace(".tif", "_labels.tif")
257
255
  # Create the tracking script
258
256
  script_path = temp_dir / "run_tracking.py"
259
- output_path = temp_dir / os.path.basename(img_path).replace(
260
- ".tif", "_tracked.tif"
257
+ # Save the mask data
258
+ # For label images, use the original path as mask_path
259
+ if label_pattern in os.path.basename(img_path):
260
+ mask_path = img_path
261
+ # Find corresponding raw image by removing the label pattern
262
+ raw_base = os.path.basename(img_path).replace(label_pattern, "")
263
+ raw_path = os.path.join(os.path.dirname(img_path), raw_base + ".tif")
264
+ if not os.path.exists(raw_path):
265
+ print(f"Warning: Could not find raw image for {img_path}")
266
+ raw_path = img_path # Fallback to using label as input
267
+ else:
268
+ # For raw images, find the corresponding label image
269
+ raw_path = img_path
270
+ base_name = os.path.basename(img_path).replace(".tif", "")
271
+ mask_path = os.path.join(
272
+ os.path.dirname(img_path), base_name + label_pattern
273
+ )
274
+ if not os.path.exists(mask_path):
275
+ print(f"No label file found for {img_path}")
276
+ return image
277
+
278
+ output_path = temp_dir / os.path.basename(mask_path).replace(
279
+ label_pattern, "_tracked.tif"
261
280
  )
262
281
 
263
282
  script_content = create_trackastra_script(
264
- str(img_path), str(mask_path), model, mode, str(output_path)
283
+ str(raw_path), str(mask_path), model, mode, str(output_path)
265
284
  )
266
285
 
267
286
  with open(script_path, "w") as f:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: napari-tmidas
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: A plugin for batch processing of confocal and whole-slide microscopy images of biological tissues
5
5
  Author: Marco Meer
6
6
  Author-email: marco.meer@pm.me
@@ -48,13 +48,13 @@ Classifier: Programming Language :: Python :: 3 :: Only
48
48
  Classifier: Programming Language :: Python :: 3.9
49
49
  Classifier: Programming Language :: Python :: 3.10
50
50
  Classifier: Programming Language :: Python :: 3.11
51
- Classifier: Programming Language :: Python :: 3.12
52
51
  Classifier: Topic :: Scientific/Engineering :: Image Processing
53
52
  Requires-Python: >=3.9
54
53
  Description-Content-Type: text/markdown
55
54
  License-File: LICENSE
56
55
  Requires-Dist: numpy
57
56
  Requires-Dist: magicgui
57
+ Requires-Dist: tqdm
58
58
  Requires-Dist: qtpy
59
59
  Requires-Dist: scikit-image
60
60
  Requires-Dist: pyqt5
@@ -66,6 +66,14 @@ Requires-Dist: torch
66
66
  Requires-Dist: torchvision
67
67
  Requires-Dist: timm
68
68
  Requires-Dist: opencv-python
69
+ Requires-Dist: cmake
70
+ Requires-Dist: nd2
71
+ Requires-Dist: pylibCZIrw
72
+ Requires-Dist: readlif
73
+ Requires-Dist: tiffslide
74
+ Requires-Dist: hydra-core
75
+ Requires-Dist: eva-decord
76
+ Requires-Dist: acquifer-napari
69
77
  Provides-Extra: testing
70
78
  Requires-Dist: tox; extra == "testing"
71
79
  Requires-Dist: pytest; extra == "testing"
@@ -90,9 +98,11 @@ Currently, napari-tmidas provides pipelines as widgets for batch image conversio
90
98
 
91
99
  ## Installation
92
100
 
101
+ (Video installation guides: https://www.youtube.com/@macromeer/videos)
102
+
93
103
  First, install Napari in a virtual environment:
94
104
 
95
- mamba create -y -n napari-tmidas -c conda-forge python=3.11 tqdm
105
+ mamba create -y -n napari-tmidas -c conda-forge python=3.11
96
106
  mamba activate napari-tmidas
97
107
  python -m pip install "napari[all]"
98
108
 
@@ -100,34 +110,28 @@ Now you can install `napari-tmidas` via [pip]:
100
110
 
101
111
  pip install napari-tmidas
102
112
 
103
- It is recommended to install the latest development version. Please also regularly execute this command in the activated environment:
113
+ It is recommended though to install the **latest development version**. Please also execute this command from time to time in the activated environment to benefit from newly added features:
104
114
 
105
115
  pip install git+https://github.com/macromeer/napari-tmidas.git
106
116
 
107
- ### Dependencies
108
-
109
- To use the Batch Microscopy Image Conversion pipeline, we need some libraries to read microscopy formats:
110
-
111
- # mamba activate napari-tmidas
112
- pip install nd2 readlif tiffslide pylibCZIrw acquifer-napari
117
+ To use the Batch Crop Anything pipeline, we need to install **Segment Anything 2** (2D/3D):
113
118
 
114
- If you want to batch compress images using [Zstandard](https://github.com/facebook/zstd), use the package manager of your operating system to install it:
119
+ cd /opt # if the folder does not exist: mkdir /opt && cd /opt
120
+ git clone https://github.com/facebookresearch/sam2.git && cd sam2
121
+ pip install -e .
122
+ curl -L https://dl.fbaipublicfiles.com/segment_anything_2/092824/sam2.1_hiera_large.pt -o checkpoints/sam2.1_hiera_large.pt
123
+ mamba install -c conda-forge ffmpeg # we also need ffmpeg
115
124
 
116
- sudo apt-get install zstd # for Linux
117
- brew install zstd # for macOS
118
- choco install zstandard # for Windows
125
+ If you want to batch compress image data using [Zstandard](https://github.com/facebook/zstd), use the package manager of your operating system to install it:
119
126
 
120
- To use the Batch Crop Anything pipeline, we need to install SAM2 in the napari-tmidas environment:
127
+ ~~sudo apt-get install zstd~~ # Pre-installed on Linux :man_shrugging:
121
128
 
122
- # mamba activate napari-tmidas
123
- cd /opt
124
- git clone https://github.com/facebookresearch/sam2.git && cd sam2
125
- pip install -e .
126
- wget https://dl.fbaipublicfiles.com/segment_anything_2/092824/sam2.1_hiera_large.pt -P checkpoints/
127
- pip install decord
129
+ brew install zstd # for macOS (requires [Homebrew](https://brew.sh/)
130
+ pip install zstandard # Windows with Python >= 3.7
128
131
 
129
132
 
130
133
 
134
+ And you are done!
131
135
 
132
136
  ## Usage
133
137
 
@@ -166,18 +170,27 @@ You can start this pipeline via `Plugins > T-MIDAS > Batch Microscopy Image Conv
166
170
 
167
171
  Note that whenever you click on an `Original File` or `Processed File` in the table, it will replace the one that is currently shown in the viewer. So naturally, you'd first select the original image, and then the processed image to correctly see the image pair that you want to inspect.
168
172
 
173
+
174
+ #### Processing Function Credits
175
+
176
+ The image processing capabilities are powered by several excellent open-source tools:
177
+ - [Cellpose 4](https://github.com/MouseLand/cellpose): Advanced cell segmentation
178
+ - [Trackastra](https://github.com/weigertlab/trackastra): Cell tracking and analysis
179
+ - [CAREamics](https://github.com/CAREamics/careamics): Content-aware image restoration and enhancement
180
+
169
181
  ### Batch Label Inspection
170
182
  If you have already segmented a folder full of images and now you want to maybe inspect and edit each label image, you can use the `Plugins > T-MIDAS > Batch Label Inspection`, which automatically saves your changes to the existing label image once you click the `Save Changes and Continue` button (bottom right).
171
183
 
172
184
  <img src="https://github.com/user-attachments/assets/0bf8c6ae-4212-449d-8183-e91b23ba740e" alt="Batch Label Inspection Widget" style="width:75%; height:auto;">
173
185
 
174
-
175
186
  ### Crop Anything
176
- This pipeline combines the Segment Anything Model (SAM) for automatic object detection with an interactive interface for selecting and cropping multiple objects from images. To launch the widget, open `Plugins > T-MIDAS > Batch Crop Anything`. Click the image below to see a video demo.
187
+ This pipeline combines the Segment Anything Model (SAM) for automatic object detection with an interactive interface for selecting and cropping multiple objects from images. To launch the widget, open `Plugins > T-MIDAS > Batch Crop Anything`. Cropping works like this: Enter 2D view and go to the first z slice where the object to be cropped is appearing. Activate/select the points layer and click on the object. Terminal shows progress. You can then proceed to select another object (always do this in 2D mode)
177
188
 
178
189
  <img src="https://github.com/user-attachments/assets/6d72c2a2-1064-4a27-b398-a9b86fcbc443" alt="Crop Anything Widget" style="width:75%; height:auto;">
179
190
 
180
191
 
192
+
193
+
181
194
  ### ROI Colocalization
182
195
  This pipeline quantifies colocalization between labeled regions of interest (ROIs) across multiple image channels. It determines the extent of overlap between ROIs in a reference channel and those in one or two other channels. The output is a table of colocalization counts. Optionally, the size of reference channel ROIs, as well as the total or median size of colocalizing ROIs in the other channels, can be included. Colocalization is determined using Boolean masking. The number of colocalizing instances is determined by counting unique label IDs within the overlapping regions. Typically, the reference channel contains larger structures, while other channels contain smaller, potentially nested, structures. For example, the reference channel might contain cell bodies, with the second and third channels containing nuclei and sub-nuclear objects, respectively.
183
196
 
@@ -1,18 +1,20 @@
1
1
  napari_tmidas/__init__.py,sha256=YNBLESwk8jr_TlDdkSC1CwH0tf0CKHF1i2_efzLjdpk,589
2
- napari_tmidas/_crop_anything.py,sha256=KgGZhNEHaGbk6npDHXGi7FrgahsfivlVwvdNAAYdME0,101452
2
+ napari_tmidas/_crop_anything.py,sha256=2UMUddQ6mdX96FiJPKpQnG1P1atFrxlz41JYWM3933k,103088
3
3
  napari_tmidas/_file_conversion.py,sha256=V6evJmggUwOFzJO203Y5ltboHXEWNJQckZPedGRkrLI,72203
4
- napari_tmidas/_file_selector.py,sha256=JQ8t_nVzJXqlVUwIBjGE2jJDeyhuDKCXHJP_cPbzzBw,43091
4
+ napari_tmidas/_file_selector.py,sha256=tuWxfmHuvILp70cGl6bsEyhRxKNum45GKD6-st-1hnM,43056
5
5
  napari_tmidas/_label_inspection.py,sha256=74V36y5EnGs0vWK1FC7Kui4CPLBW_SIg885PSKeZsJ4,9184
6
6
  napari_tmidas/_reader.py,sha256=A9_hdDxtVkVGmbOsbqgnARCSvpEh7GGPo7ylzmbnu8o,2485
7
- napari_tmidas/_registry.py,sha256=Oz9HFJh41MKRLeKxRuc7x7yzc-OrmoTdRFnfngFU_XE,2007
7
+ napari_tmidas/_registry.py,sha256=fxBPLFCvXtjSHfcVIRb6KI9DkqIWRUpPPg_3pD8sXns,2110
8
8
  napari_tmidas/_roi_colocalization.py,sha256=OVjdHvtFN07DgrtTX8uqbrxZL6jVwl2L3klorgW2C9k,43196
9
9
  napari_tmidas/_sample_data.py,sha256=khuv1jemz_fCjqNwEKMFf83Ju0EN4S89IKydsUMmUxw,645
10
- napari_tmidas/_version.py,sha256=UoNvMtd4wCG76RwoSpNCUtaFyTwakGcZolfjXzNVSMY,511
10
+ napari_tmidas/_version.py,sha256=OjGGK5TcHVG44Y62aAqeJH4CskkZoY9ydbHOtCDew50,511
11
11
  napari_tmidas/_widget.py,sha256=u9uf9WILAwZg_InhFyjWInY4ej1TV1a59dR8Fe3vNF8,4794
12
12
  napari_tmidas/_writer.py,sha256=wbVfHFjjHdybSg37VR4lVmL-kdCkDZsUPDJ66AVLaFQ,1941
13
13
  napari_tmidas/napari.yaml,sha256=1Am1dA0-ZtCXk6veIT6jrMz3zwQ7dF8_p9tZTFx_vTg,2641
14
14
  napari_tmidas/_tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
+ napari_tmidas/_tests/test_file_selector.py,sha256=Sbu0BCXTaQAeUJLtOVjIC87AUARbi8J0bXBlMJe53ew,2687
15
16
  napari_tmidas/_tests/test_reader.py,sha256=gN_2StATLZYUL56X27ImJTVru_qSoFiY4vtgajcx3H0,975
17
+ napari_tmidas/_tests/test_registry.py,sha256=DSI6NdmuIS1sYAa3LrVge0rOS5Ycb3TXFXxol3vDyRA,2061
16
18
  napari_tmidas/_tests/test_sample_data.py,sha256=D1HU_C3hWpO3mlSW_7Z94xaYHDtxz0XUrMjQoYop9Ag,104
17
19
  napari_tmidas/_tests/test_widget.py,sha256=I_d-Cra_CTcS0QdMItg_HMphvhj0XCx81JnFyCHk9lg,2204
18
20
  napari_tmidas/_tests/test_writer.py,sha256=4_MlZM9a5So74J16_4tIOJc6pwTOw9R0-oAE_YioIx4,122
@@ -29,10 +31,10 @@ napari_tmidas/processing_functions/sam2_mp4.py,sha256=NF0dWar2uyP_yQWxC8e08J6198
29
31
  napari_tmidas/processing_functions/scipy_filters.py,sha256=kKpDAlQQ0ZNbkt77QUWi-Bwolk6MMDvtG_bZJV3MjOo,1612
30
32
  napari_tmidas/processing_functions/skimage_filters.py,sha256=tSBx0nal88ixxVbu5o7ojTn90HgsUTt-aA_T6XLvmyY,16320
31
33
  napari_tmidas/processing_functions/timepoint_merger.py,sha256=DwL5vZBSplXt9dBBrKtMm9aH_NvT3mY7cdbeGg2OU_Y,16567
32
- napari_tmidas/processing_functions/trackastra_tracking.py,sha256=4kswVZCRHJ68oY95ezZmSrXMNrhjjEeN5x8a7GIjh4E,9084
33
- napari_tmidas-0.2.1.dist-info/licenses/LICENSE,sha256=tSjiOqj57exmEIfP2YVPCEeQf0cH49S6HheQR8IiY3g,1485
34
- napari_tmidas-0.2.1.dist-info/METADATA,sha256=AYL6vxMkpxPlXBrYZdBOvH1_AuNAQ83X68hue3KfA_k,11874
35
- napari_tmidas-0.2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
36
- napari_tmidas-0.2.1.dist-info/entry_points.txt,sha256=fbVjzbJTm4aDMIBtel1Lyqvq-CwXY7wmCOo_zJ-jtRY,60
37
- napari_tmidas-0.2.1.dist-info/top_level.txt,sha256=63ybdxCZ4SeT13f_Ou4TsivGV_2Gtm_pJOXToAt30_E,14
38
- napari_tmidas-0.2.1.dist-info/RECORD,,
34
+ napari_tmidas/processing_functions/trackastra_tracking.py,sha256=IkFk5HoEZmKdcu5jXri4WMhHN1KTADDMxSpeYfPgSbo,9976
35
+ napari_tmidas-0.2.2.dist-info/licenses/LICENSE,sha256=tSjiOqj57exmEIfP2YVPCEeQf0cH49S6HheQR8IiY3g,1485
36
+ napari_tmidas-0.2.2.dist-info/METADATA,sha256=cY8vgH2bnjC9elLZ0uxIBVJeTckVbg7UxnV2L5u4wTc,12742
37
+ napari_tmidas-0.2.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
38
+ napari_tmidas-0.2.2.dist-info/entry_points.txt,sha256=fbVjzbJTm4aDMIBtel1Lyqvq-CwXY7wmCOo_zJ-jtRY,60
39
+ napari_tmidas-0.2.2.dist-info/top_level.txt,sha256=63ybdxCZ4SeT13f_Ou4TsivGV_2Gtm_pJOXToAt30_E,14
40
+ napari_tmidas-0.2.2.dist-info/RECORD,,