coralnet-toolbox 0.0.70__py2.py3-none-any.whl → 0.0.71__py2.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.
@@ -130,7 +130,7 @@ class EmbeddingViewer(QWidget):
130
130
  # Create a QToolButton to have both a primary action and a dropdown menu
131
131
  self.find_mislabels_button = QToolButton()
132
132
  self.find_mislabels_button.setText("Find Potential Mislabels")
133
- self.find_mislabels_button.setPopupMode(QToolButton.MenuButtonPopup) # Key change for split-button style
133
+ self.find_mislabels_button.setPopupMode(QToolButton.MenuButtonPopup) # Key change for split-button style
134
134
  self.find_mislabels_button.setToolButtonStyle(Qt.ToolButtonTextOnly)
135
135
  self.find_mislabels_button.setStyleSheet(
136
136
  "QToolButton::menu-indicator {"
@@ -186,9 +186,18 @@ class EmbeddingViewer(QWidget):
186
186
 
187
187
  uncertainty_settings_widget.parameters_changed.connect(self.uncertainty_parameters_changed.emit)
188
188
  toolbar_layout.addWidget(self.find_uncertain_button)
189
-
189
+
190
+ # Add a strech and separator
190
191
  toolbar_layout.addStretch()
191
-
192
+ toolbar_layout.addWidget(self._create_separator())
193
+
194
+ # Center on selection button
195
+ self.center_on_selection_button = QPushButton()
196
+ self.center_on_selection_button.setIcon(get_icon("target.png"))
197
+ self.center_on_selection_button.setToolTip("Center view on selected point(s)")
198
+ self.center_on_selection_button.clicked.connect(self.center_on_selection)
199
+ toolbar_layout.addWidget(self.center_on_selection_button)
200
+
192
201
  # Home button to reset view
193
202
  self.home_button = QPushButton()
194
203
  self.home_button.setIcon(get_icon("home.png"))
@@ -258,6 +267,7 @@ class EmbeddingViewer(QWidget):
258
267
 
259
268
  self.find_mislabels_button.setEnabled(points_exist)
260
269
  self.find_uncertain_button.setEnabled(points_exist and self.is_uncertainty_analysis_available)
270
+ self.center_on_selection_button.setEnabled(points_exist and selection_exists)
261
271
 
262
272
  if self.isolated_mode:
263
273
  self.isolate_button.hide()
@@ -270,12 +280,46 @@ class EmbeddingViewer(QWidget):
270
280
  def reset_view(self):
271
281
  """Reset the view to fit all embedding points."""
272
282
  self.fit_view_to_points()
283
+
284
+ def center_on_selection(self):
285
+ """Centers the view on selected point(s) or maintains the current view if no points are selected."""
286
+ selected_items = self.graphics_scene.selectedItems()
287
+ if not selected_items:
288
+ # No selection, show a message
289
+ QMessageBox.information(self, "No Selection", "Please select one or more points first.")
290
+ return
291
+
292
+ # Create a bounding rect that encompasses all selected points
293
+ selection_rect = None
294
+
295
+ for item in selected_items:
296
+ if isinstance(item, EmbeddingPointItem):
297
+ # Get the item's bounding rect in scene coordinates
298
+ item_rect = item.sceneBoundingRect()
299
+
300
+ # Add padding around the point for better visibility
301
+ padding = 50 # pixels
302
+ item_rect = item_rect.adjusted(-padding, -padding, padding, padding)
303
+
304
+ if selection_rect is None:
305
+ selection_rect = item_rect
306
+ else:
307
+ selection_rect = selection_rect.united(item_rect)
308
+
309
+ if selection_rect:
310
+ # Add extra margin for better visibility
311
+ margin = 20
312
+ selection_rect = selection_rect.adjusted(-margin, -margin, margin, margin)
313
+
314
+ # Fit the view to the selection rect
315
+ self.graphics_view.fitInView(selection_rect, Qt.KeepAspectRatio)
273
316
 
274
317
  def show_placeholder(self):
275
318
  """Show the placeholder message and hide the graphics view."""
276
319
  self.graphics_view.setVisible(False)
277
320
  self.placeholder_label.setVisible(True)
278
321
  self.home_button.setEnabled(False)
322
+ self.center_on_selection_button.setEnabled(False) # Disable center button
279
323
  self.find_mislabels_button.setEnabled(False)
280
324
  self.find_uncertain_button.setEnabled(False)
281
325
 
@@ -1422,6 +1466,7 @@ class ExplorerWindow(QMainWindow):
1422
1466
 
1423
1467
  self.device = main_window.device
1424
1468
  self.loaded_model = None
1469
+ self.loaded_model_imgsz = 128
1425
1470
 
1426
1471
  self.feature_store = FeatureStore()
1427
1472
 
@@ -1775,13 +1820,15 @@ class ExplorerWindow(QMainWindow):
1775
1820
  """
1776
1821
  Identifies annotations whose label does not match the majority of its
1777
1822
  k-nearest neighbors in the high-dimensional feature space.
1823
+ Skips any annotation or neighbor with an invalid label (id == -1).
1778
1824
  """
1779
1825
  # Get parameters from the stored property instead of hardcoding
1780
1826
  K = self.mislabel_params.get('k', 5)
1781
1827
  agreement_threshold = self.mislabel_params.get('threshold', 0.6)
1782
1828
 
1783
1829
  if not self.embedding_viewer.points_by_id or len(self.embedding_viewer.points_by_id) < K:
1784
- QMessageBox.information(self, "Not Enough Data",
1830
+ QMessageBox.information(self,
1831
+ "Not Enough Data",
1785
1832
  f"This feature requires at least {K} points in the embedding viewer.")
1786
1833
  return
1787
1834
 
@@ -1792,7 +1839,6 @@ class ExplorerWindow(QMainWindow):
1792
1839
  model_info = self.model_settings_widget.get_selected_model()
1793
1840
  model_name, feature_mode = model_info if isinstance(model_info, tuple) else (model_info, "default")
1794
1841
  sanitized_model_name = os.path.basename(model_name).replace(' ', '_')
1795
- # FIX: Also replace the forward slash to handle "N/A"
1796
1842
  sanitized_feature_mode = feature_mode.replace(' ', '_').replace('/', '_')
1797
1843
  model_key = f"{sanitized_model_name}_{sanitized_feature_mode}"
1798
1844
 
@@ -1802,13 +1848,17 @@ class ExplorerWindow(QMainWindow):
1802
1848
  index = self.feature_store._get_or_load_index(model_key)
1803
1849
  faiss_idx_to_ann_id = self.feature_store.get_faiss_index_to_annotation_id_map(model_key)
1804
1850
  if index is None or not faiss_idx_to_ann_id:
1805
- QMessageBox.warning(self, "Error", "Could not find a valid feature index for the current model.")
1851
+ QMessageBox.warning(self,
1852
+ "Error",
1853
+ "Could not find a valid feature index for the current model.")
1806
1854
  return
1807
1855
 
1808
1856
  # Get the high-dimensional features for the points in the current view
1809
1857
  features_dict, _ = self.feature_store.get_features(data_items_in_view, model_key)
1810
1858
  if not features_dict:
1811
- QMessageBox.warning(self, "Error", "Could not retrieve features for the items in view.")
1859
+ QMessageBox.warning(self,
1860
+ "Error",
1861
+ "Could not retrieve features for the items in view.")
1812
1862
  return
1813
1863
 
1814
1864
  query_ann_ids = list(features_dict.keys())
@@ -1819,25 +1869,33 @@ class ExplorerWindow(QMainWindow):
1819
1869
 
1820
1870
  mislabeled_ann_ids = []
1821
1871
  for i, ann_id in enumerate(query_ann_ids):
1822
- current_label = self.data_item_cache[ann_id].effective_label.id
1823
-
1872
+ data_item = self.data_item_cache[ann_id]
1873
+ # Use preview_label if present, else effective_label
1874
+ label_obj = getattr(data_item, "preview_label", None) or data_item.effective_label
1875
+ current_label_id = getattr(label_obj, "id", "-1")
1876
+ if current_label_id == "-1":
1877
+ continue # Skip if label is invalid
1878
+
1824
1879
  # Get neighbor labels, ignoring the first result (the point itself)
1825
1880
  neighbor_faiss_indices = I[i][1:]
1826
-
1881
+
1827
1882
  neighbor_labels = []
1828
1883
  for n_idx in neighbor_faiss_indices:
1829
- # THIS IS THE CORRECTED LOGIC
1830
1884
  if n_idx in faiss_idx_to_ann_id:
1831
1885
  neighbor_ann_id = faiss_idx_to_ann_id[n_idx]
1832
- # ADD THIS CHECK to ensure the neighbor hasn't been deleted
1833
1886
  if neighbor_ann_id in self.data_item_cache:
1834
- neighbor_labels.append(self.data_item_cache[neighbor_ann_id].effective_label.id)
1887
+ neighbor_item = self.data_item_cache[neighbor_ann_id]
1888
+ neighbor_label_obj = getattr(neighbor_item, "preview_label", None)
1889
+ if neighbor_label_obj is None:
1890
+ neighbor_label_obj = neighbor_item.effective_label
1891
+ neighbor_label_id = getattr(neighbor_label_obj, "id", "-1")
1892
+ if neighbor_label_id != "-1":
1893
+ neighbor_labels.append(neighbor_label_id)
1835
1894
 
1836
1895
  if not neighbor_labels:
1837
1896
  continue
1838
1897
 
1839
- # Use the agreement threshold instead of strict majority
1840
- num_matching_neighbors = neighbor_labels.count(current_label)
1898
+ num_matching_neighbors = neighbor_labels.count(current_label_id)
1841
1899
  agreement_ratio = num_matching_neighbors / len(neighbor_labels)
1842
1900
 
1843
1901
  if agreement_ratio < agreement_threshold:
@@ -2082,16 +2140,36 @@ class ExplorerWindow(QMainWindow):
2082
2140
  print(f"Model or mode changed. Reloading {model_name} for '{feature_mode}'.")
2083
2141
  try:
2084
2142
  model = YOLO(model_name)
2143
+
2144
+ # Check if the model task is compatible with the selected feature mode
2145
+ if model.task != 'classify' and feature_mode == "Predictions":
2146
+ QMessageBox.warning(self,
2147
+ "Invalid Mode for Model",
2148
+ f"The selected model is a '{model.task}' model. "
2149
+ "The 'Predictions' feature mode is only available for 'classify' models. "
2150
+ "Reverting to 'Embed Features' mode.")
2151
+
2152
+ # Force the feature mode combo box back to "Embed Features"
2153
+ self.model_settings_widget.feature_mode_combo.setCurrentText("Embed Features")
2154
+
2155
+ # On failure, reset the model cache
2156
+ self.loaded_model = None
2157
+ self.current_feature_generating_model = None
2158
+ return None, None
2159
+
2085
2160
  # Update the cache key to the new successful combination
2086
2161
  self.current_feature_generating_model = current_run_key
2087
2162
  self.loaded_model = model
2088
- imgsz = getattr(model.model.args, 'imgsz', 128)
2163
+
2164
+ # Get the imgsz, but if it's larger than 128, default to 128
2165
+ imgsz = min(getattr(model.model.args, 'imgsz', 128), 128)
2166
+ self.loaded_model_imgsz = imgsz
2089
2167
 
2090
2168
  # Warm up the model
2091
2169
  dummy_image = np.zeros((imgsz, imgsz, 3), dtype=np.uint8)
2092
2170
  model.predict(dummy_image, imgsz=imgsz, half=True, device=self.device, verbose=False)
2093
2171
 
2094
- return model, imgsz
2172
+ return model, self.loaded_model_imgsz
2095
2173
 
2096
2174
  except Exception as e:
2097
2175
  print(f"ERROR: Could not load YOLO model '{model_name}': {e}")
@@ -2100,8 +2178,8 @@ class ExplorerWindow(QMainWindow):
2100
2178
  self.current_feature_generating_model = None
2101
2179
  return None, None
2102
2180
 
2103
- # Model already loaded and cached
2104
- return self.loaded_model, getattr(self.loaded_model.model.args, 'imgsz', 128)
2181
+ # Model already loaded and cached, return it and its image size
2182
+ return self.loaded_model, self.loaded_model_imgsz
2105
2183
 
2106
2184
  def _prepare_images_from_data_items(self, data_items, progress_bar=None):
2107
2185
  """
Binary file
@@ -660,6 +660,10 @@ class Base(QDialog):
660
660
  QMessageBox.warning(self, "Import Warning", "The YAML file appears to be empty or invalid.")
661
661
  return
662
662
 
663
+ # For backward compatibility, check if the old nested 'parameters' key exists.
664
+ # If not, use the whole data dictionary.
665
+ params_to_load = data.get('parameters', data)
666
+
663
667
  # Helper function to infer type from value
664
668
  def infer_type_and_value(value):
665
669
  """
@@ -673,12 +677,9 @@ class Base(QDialog):
673
677
  elif isinstance(value, float):
674
678
  return "float", value
675
679
  elif isinstance(value, str):
676
- # Check for boolean strings
677
680
  if value.lower() in ['true', 'false']:
678
681
  return "bool", value.lower() == 'true'
679
- # Check for numeric strings
680
682
  try:
681
- # Try to convert to int first
682
683
  if '.' not in value:
683
684
  return "int", int(value)
684
685
  else:
@@ -686,14 +687,13 @@ class Base(QDialog):
686
687
  except ValueError:
687
688
  return "string", value
688
689
  else:
689
- # For any other type, convert to string
690
690
  return "string", str(value)
691
691
 
692
692
  # Clear existing custom parameters before importing
693
693
  while self.custom_params:
694
694
  self.remove_parameter_pair()
695
695
 
696
- # Map parameters to UI controls
696
+ # Map standard parameters to their UI controls
697
697
  param_mapping = {
698
698
  'epochs': self.epochs_spinbox,
699
699
  'patience': self.patience_spinbox,
@@ -712,37 +712,31 @@ class Base(QDialog):
712
712
  }
713
713
 
714
714
  # Update UI controls with imported values
715
- for param_name, value in data.items():
715
+ for param_name, value in params_to_load.items():
716
716
  param_type, converted_value = infer_type_and_value(value)
717
717
 
718
718
  if param_name in param_mapping:
719
719
  widget = param_mapping[param_name]
720
720
 
721
721
  if isinstance(widget, QSpinBox):
722
- if param_type in ['int', 'float'] and isinstance(converted_value, (int, float)):
722
+ if isinstance(converted_value, (int, float)):
723
723
  widget.setValue(int(converted_value))
724
724
  elif isinstance(widget, QDoubleSpinBox):
725
- if param_type in ['int', 'float'] and isinstance(converted_value, (int, float)):
725
+ if isinstance(converted_value, (int, float)):
726
726
  widget.setValue(float(converted_value))
727
727
  elif isinstance(widget, QComboBox):
728
728
  if param_name in ['multi_scale', 'save', 'weighted', 'val', 'verbose']:
729
- # Boolean parameters
730
- if param_type == 'bool':
731
- widget.setCurrentText("True" if converted_value else "False")
732
- else:
733
- # String parameters like optimizer
734
- if str(converted_value) in [widget.itemText(i) for i in range(widget.count())]:
735
- widget.setCurrentText(str(converted_value))
729
+ widget.setCurrentText("True" if converted_value else "False")
730
+ elif str(converted_value) in [widget.itemText(i) for i in range(widget.count())]:
731
+ widget.setCurrentText(str(converted_value))
736
732
  else:
737
- # Add as custom parameter using inferred type
733
+ # Add as a custom parameter
738
734
  self.add_parameter_pair()
739
- param_widgets = self.custom_params[-1]
740
- param_name_widget, param_value_widget, param_type_widget = param_widgets
735
+ param_name_widget, param_value_widget, param_type_widget = self.custom_params[-1]
741
736
 
742
737
  param_name_widget.setText(param_name)
743
738
  param_type_widget.setCurrentText(param_type)
744
739
 
745
- # Set value based on type
746
740
  if param_type == "bool":
747
741
  param_value_widget.setText("True" if converted_value else "False")
748
742
  else:
@@ -750,14 +744,14 @@ class Base(QDialog):
750
744
 
751
745
  QMessageBox.information(self,
752
746
  "Import Success",
753
- "Parameters successfully imported with automatic type inference")
747
+ "Parameters successfully imported with automatic type inference.")
754
748
 
755
749
  except Exception as e:
756
750
  QMessageBox.critical(self, "Import Error", f"Failed to import parameters: {str(e)}")
757
751
 
758
752
  def export_parameters(self):
759
753
  """
760
- Export current parameters to a YAML file with explicit type information.
754
+ Export current parameters to a flat YAML file.
761
755
  """
762
756
  file_path, _ = QFileDialog.getSaveFileName(self,
763
757
  "Export Parameters to YAML",
@@ -767,69 +761,56 @@ class Base(QDialog):
767
761
  return
768
762
 
769
763
  try:
770
- # Structure: types section followed by parameters section
771
- export_data = {
772
- 'types': {},
773
- 'parameters': {}
774
- }
775
-
776
- # Standard parameters with their types
777
- standard_params = {
778
- 'epochs': ('int', self.epochs_spinbox.value()),
779
- 'patience': ('int', self.patience_spinbox.value()),
780
- 'imgsz': ('int', self.imgsz_spinbox.value()),
781
- 'batch': ('int', self.batch_spinbox.value()),
782
- 'workers': ('int', self.workers_spinbox.value()),
783
- 'save_period': ('int', self.save_period_spinbox.value()),
784
- 'freeze_layers': ('float', self.freeze_layers_spinbox.value()),
785
- 'dropout': ('float', self.dropout_spinbox.value()),
786
- 'multi_scale': ('bool', self.multi_scale_combo.currentText() == "True"),
787
- 'save': ('bool', self.save_combo.currentText() == "True"),
788
- 'weighted': ('bool', self.weighted_combo.currentText() == "True"),
789
- 'val': ('bool', self.val_combo.currentText() == "True"),
790
- 'verbose': ('bool', self.verbose_combo.currentText() == "True"),
791
- 'optimizer': ('string', self.optimizer_combo.currentText())
792
- }
793
-
794
- # Add standard parameters
795
- for param_name, (param_type, value) in standard_params.items():
796
- export_data['types'][param_name] = param_type
797
- export_data['parameters'][param_name] = value
764
+ # Use a single flat dictionary for export
765
+ export_data = {}
766
+
767
+ # Standard parameters
768
+ export_data['epochs'] = self.epochs_spinbox.value()
769
+ export_data['patience'] = self.patience_spinbox.value()
770
+ export_data['imgsz'] = self.imgsz_spinbox.value()
771
+ export_data['batch'] = self.batch_spinbox.value()
772
+ export_data['workers'] = self.workers_spinbox.value()
773
+ export_data['save_period'] = self.save_period_spinbox.value()
774
+ export_data['freeze_layers'] = self.freeze_layers_spinbox.value()
775
+ export_data['dropout'] = self.dropout_spinbox.value()
776
+ export_data['multi_scale'] = self.multi_scale_combo.currentText() == "True"
777
+ export_data['save'] = self.save_combo.currentText() == "True"
778
+ export_data['weighted'] = self.weighted_combo.currentText() == "True"
779
+ export_data['val'] = self.val_combo.currentText() == "True"
780
+ export_data['verbose'] = self.verbose_combo.currentText() == "True"
781
+ export_data['optimizer'] = self.optimizer_combo.currentText()
798
782
 
799
783
  # Custom parameters
800
784
  for param_info in self.custom_params:
801
- param_name, param_value, param_type = param_info
802
- name = param_name.text().strip()
803
- value = param_value.text().strip()
804
- type_name = param_type.currentText()
785
+ param_name_widget, param_value_widget, param_type_widget = param_info
786
+ name = param_name_widget.text().strip()
787
+ value_str = param_value_widget.text().strip()
788
+ type_name = param_type_widget.currentText()
805
789
 
806
- if name and value:
807
- export_data['types'][name] = type_name
808
-
809
- if type_name == "bool":
810
- export_data['parameters'][name] = value.lower() == "true"
811
- elif type_name == "int":
812
- try:
813
- export_data['parameters'][name] = int(value)
814
- except ValueError:
815
- export_data['parameters'][name] = value
816
- export_data['types'][name] = "string" # Fallback to string
817
- elif type_name == "float":
818
- try:
819
- export_data['parameters'][name] = float(value)
820
- except ValueError:
821
- export_data['parameters'][name] = value
822
- export_data['types'][name] = "string" # Fallback to string
823
- else: # string type
824
- export_data['parameters'][name] = value
825
-
826
- # Write to YAML file
790
+ if name and value_str:
791
+ # Convert value to the correct type before exporting
792
+ try:
793
+ if type_name == "bool":
794
+ value = value_str.lower() == "true"
795
+ elif type_name == "int":
796
+ value = int(value_str)
797
+ elif type_name == "float":
798
+ value = float(value_str)
799
+ else: # string type
800
+ value = value_str
801
+ export_data[name] = value
802
+ except ValueError:
803
+ # If conversion fails, save it as a string
804
+ print(f"Warning: Could not convert '{value_str}' to {type_name} for parameter '{name}'. Saving as string.")
805
+ export_data[name] = value_str
806
+
807
+ # Write the flat dictionary to the YAML file
827
808
  with open(file_path, 'w') as f:
828
- yaml.dump(export_data, f, default_flow_style=False, indent=2)
809
+ yaml.dump(export_data, f, default_flow_style=False, sort_keys=False, indent=2)
829
810
 
830
811
  QMessageBox.information(self,
831
812
  "Export Success",
832
- "Parameters successfully exported")
813
+ "Parameters successfully exported.")
833
814
 
834
815
  except Exception as e:
835
816
  QMessageBox.critical(self,
@@ -1,6 +1,6 @@
1
1
  """Top-level package for CoralNet-Toolbox."""
2
2
 
3
- __version__ = "0.0.70"
3
+ __version__ = "0.0.71"
4
4
  __author__ = "Jordan Pierce"
5
5
  __email__ = "jordan.pierce@noaa.gov"
6
6
  __credits__ = "National Center for Coastal and Ocean Sciences (NCCOS)"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: coralnet-toolbox
3
- Version: 0.0.70
3
+ Version: 0.0.71
4
4
  Summary: Tools for annotating and developing ML models for benthic imagery
5
5
  Author-email: Jordan Pierce <jordan.pierce@noaa.gov>
6
6
  License: MIT License
@@ -179,7 +179,7 @@ Enhance your CoralNet experience with these tools:
179
179
  - 🚀 Optimize: Productionize models for faster inferencing
180
180
  - ⚙️ Batch Inference: Perform predictions on multiple images, automatically
181
181
  - 🎞️ Video Inference: Perform predictions on a video in real-time, record the output and analytics
182
- - 🔮 Explorer: Cluster, view, and re-label annotations using embeddings, mapped from feature-space
182
+ - 🔮 [Explorer](https://youtu.be/68eZt5l_7nA): Cluster, view, and re-label annotations using embeddings, mapped from feature-space
183
183
  - ↔️ I/O: Import and Export annotations from / to CoralNet, Viscore, and TagLab
184
184
  - Export annotations as [GeoJSONs](https://datatracker.ietf.org/doc/html/rfc7946), segmentation masks
185
185
  - 📸 YOLO: Import and Export YOLO datasets for machine learning
@@ -7,7 +7,7 @@ coralnet_toolbox/QtMainWindow.py,sha256=W86kc-ZFmZHcSKcNTWN5RFCvt7sysvTCYZrPWZPW
7
7
  coralnet_toolbox/QtPatchSampling.py,sha256=Ehj06auBGfQwIruLNYQjF8eFOCpl8G72p42UXXb2mUo,29013
8
8
  coralnet_toolbox/QtProgressBar.py,sha256=pnozUOcVjfO_yTS9z8wOMPcrrrOtG_FeCknTcdI6eyk,6250
9
9
  coralnet_toolbox/QtWorkArea.py,sha256=YXRvHQKpWUtWyv_o9lZ8rmxfm28dUOG9pmMUeimDhQ4,13578
10
- coralnet_toolbox/__init__.py,sha256=jJh2Y95YrQKB66vTaSKx69MySCS7FLjHdOkQcpz04A4,207
10
+ coralnet_toolbox/__init__.py,sha256=K-BGYPTYU1ySXgZWS4vmpHfRksFJb3SAyX73veK1hdE,207
11
11
  coralnet_toolbox/main.py,sha256=6j2B_1reC_KDmqvq1C0fB-UeSEm8eeJOozp2f4XXMLQ,1573
12
12
  coralnet_toolbox/utilities.py,sha256=eUkxXuWaNFH83LSW-KniwujkXKJ2rK04czx3k3OPiAY,27115
13
13
  coralnet_toolbox/Annotations/QtAnnotation.py,sha256=-3ASbjl1dXw9U731vyCgwyiyZT9zOD5Mvp1jt-7bCnA,29242
@@ -36,7 +36,7 @@ coralnet_toolbox/CoralNet/QtAuthenticate.py,sha256=Y__iY0Kcosz6AOV7dlJBwiB6Hte40
36
36
  coralnet_toolbox/CoralNet/QtDownload.py,sha256=HBb8TpZRIEFirGIaIAV1v8qg3fL4cP6Bf-hUiqXoiLE,48516
37
37
  coralnet_toolbox/CoralNet/__init__.py,sha256=ILkAZh6mlAK1UaCCZjCB9JZxd-oY4cIgfnIC8UgjjIU,188
38
38
  coralnet_toolbox/Explorer/QtDataItem.py,sha256=-O2Tneh9wYbAZarqwb_Cvy5cP1F_zQH2IAw9c-rHy1Y,13572
39
- coralnet_toolbox/Explorer/QtExplorer.py,sha256=iKtp3m7PowAZCOmJSx-Z34M50kmVCUNHrbCBQIBd12k,118900
39
+ coralnet_toolbox/Explorer/QtExplorer.py,sha256=IATLlZi57m5XU1KIG-oGNGqhcZEpjxQeilmKGrKMIFo,122968
40
40
  coralnet_toolbox/Explorer/QtFeatureStore.py,sha256=kMn--vuBed6wZS-BQhHt_KBA5z-tL1ydFgFkkIoGiB4,6742
41
41
  coralnet_toolbox/Explorer/QtSettingsWidgets.py,sha256=hIMj2lzqGKBoFWKYolH7bEPm5ePAIzYcGjYRQv2uWFE,27656
42
42
  coralnet_toolbox/Explorer/__init__.py,sha256=wZPhf2oaUUyIQ2WK48Aj-4q1ENIZG2dGl1HF_mjhI6w,116
@@ -89,6 +89,7 @@ coralnet_toolbox/Icons/rocket.png,sha256=iMlRGlrNBS_dNBD2XIpN4RSrphCGbw_Ds1AYJ01
89
89
  coralnet_toolbox/Icons/select.png,sha256=twnMIO9ylQYjvyGnAR28V6K3ds6xpArZQTrvf0uxS6g,1896
90
90
  coralnet_toolbox/Icons/settings.png,sha256=rklROt3oKrfEk_qwN9J-JwvKok08iOkZy3OD4oNsLJQ,1376
91
91
  coralnet_toolbox/Icons/snake.png,sha256=cwcekSkXwDi_fhtTU48u7FN4bIybbY53cWK0n7-IN9A,2361
92
+ coralnet_toolbox/Icons/target.png,sha256=jzb-S_sXWT8MfbvefhDNsuTdAZgV2nGf1ieawaCkByM,1702
92
93
  coralnet_toolbox/Icons/tile.png,sha256=WiXKBpWVBfPv7gC8dnkc_gW3wuLQmLUyxYMWEM-G9ZU,382
93
94
  coralnet_toolbox/Icons/transparent.png,sha256=ZkuGkVzh6zLVNau1Wj166-TtUlbCRqJObGt4vxMxnLk,1098
94
95
  coralnet_toolbox/Icons/turtle.png,sha256=55OG5atmEs8nIUiN2B5hW-Jx1fpuY9QI-zolQoUOKWw,1971
@@ -147,7 +148,7 @@ coralnet_toolbox/MachineLearning/MergeDatasets/QtClassify.py,sha256=FI4WdxJ4-vtn
147
148
  coralnet_toolbox/MachineLearning/MergeDatasets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
148
149
  coralnet_toolbox/MachineLearning/OptimizeModel/QtBase.py,sha256=06irheL8aKvtwKBQLLJUohvWvrMqKFC-jhEEoVqIYdg,8890
149
150
  coralnet_toolbox/MachineLearning/OptimizeModel/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
150
- coralnet_toolbox/MachineLearning/TrainModel/QtBase.py,sha256=lLGmgDSvjQFYD2RdF7eC6U5xU5in2rC26RQ3lmKvfLY,37460
151
+ coralnet_toolbox/MachineLearning/TrainModel/QtBase.py,sha256=f__pgcG8yyV4IQbICED4q4YWO6GnNtD5b5UGpWuv4c0,36580
151
152
  coralnet_toolbox/MachineLearning/TrainModel/QtClassify.py,sha256=ss5ppGbrpULzUPmeRmfqZjiqZPp7XbdUZ4BzSX0ehu0,3267
152
153
  coralnet_toolbox/MachineLearning/TrainModel/QtDetect.py,sha256=uxopZkrNkl3tImMNSDwC2ENpFAxdG0NLiwRwqNnbep0,4467
153
154
  coralnet_toolbox/MachineLearning/TrainModel/QtSegment.py,sha256=y8bpNS24SQxyg967RSi6TraqHSmlJYj8kbvC_5HMBIM,3597
@@ -215,9 +216,9 @@ coralnet_toolbox/Tools/QtTool.py,sha256=2MCjT151gYBN8KbsK0GX4WOrEg1uw3oeSkp7Elw1
215
216
  coralnet_toolbox/Tools/QtWorkAreaTool.py,sha256=-CDrEPenOdSI3sf5wn19Cip4alE1ef7WsRDxQFDkHlc,22162
216
217
  coralnet_toolbox/Tools/QtZoomTool.py,sha256=F9CAoABv1jxcUS7dyIh1FYjgjOXYRI1xtBPNIR1g62o,4041
217
218
  coralnet_toolbox/Tools/__init__.py,sha256=218iQ8IFXIkKXiUDVYtXk9e08UY9-LhHjcryaJAanQ0,797
218
- coralnet_toolbox-0.0.70.dist-info/licenses/LICENSE.txt,sha256=AURacZ_G_PZKqqPQ9VB9Sqegblk67RNgWSGAYKwXXMY,521
219
- coralnet_toolbox-0.0.70.dist-info/METADATA,sha256=2BX8ksbRkMXuBR4m5xY6ks_qfTqmCZjEPwkpwCDccW0,18120
220
- coralnet_toolbox-0.0.70.dist-info/WHEEL,sha256=JNWh1Fm1UdwIQV075glCn4MVuCRs0sotJIq-J6rbxCU,109
221
- coralnet_toolbox-0.0.70.dist-info/entry_points.txt,sha256=oEeMoDlJ_2lq95quOeDHIx9hZpubUlSo80OLtgbcrbM,63
222
- coralnet_toolbox-0.0.70.dist-info/top_level.txt,sha256=SMWPh4_9JfB8zVpPOOvjucV2_B_hvWW7bNWmMjG0LsY,17
223
- coralnet_toolbox-0.0.70.dist-info/RECORD,,
219
+ coralnet_toolbox-0.0.71.dist-info/licenses/LICENSE.txt,sha256=AURacZ_G_PZKqqPQ9VB9Sqegblk67RNgWSGAYKwXXMY,521
220
+ coralnet_toolbox-0.0.71.dist-info/METADATA,sha256=LltT45S41MrUplIQGHLJ_1rjuFT8PccNnbRCUw2ODRQ,18152
221
+ coralnet_toolbox-0.0.71.dist-info/WHEEL,sha256=JNWh1Fm1UdwIQV075glCn4MVuCRs0sotJIq-J6rbxCU,109
222
+ coralnet_toolbox-0.0.71.dist-info/entry_points.txt,sha256=oEeMoDlJ_2lq95quOeDHIx9hZpubUlSo80OLtgbcrbM,63
223
+ coralnet_toolbox-0.0.71.dist-info/top_level.txt,sha256=SMWPh4_9JfB8zVpPOOvjucV2_B_hvWW7bNWmMjG0LsY,17
224
+ coralnet_toolbox-0.0.71.dist-info/RECORD,,