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.
- coralnet_toolbox/Explorer/QtExplorer.py +97 -19
- coralnet_toolbox/Icons/target.png +0 -0
- coralnet_toolbox/MachineLearning/TrainModel/QtBase.py +57 -76
- coralnet_toolbox/__init__.py +1 -1
- {coralnet_toolbox-0.0.70.dist-info → coralnet_toolbox-0.0.71.dist-info}/METADATA +2 -2
- {coralnet_toolbox-0.0.70.dist-info → coralnet_toolbox-0.0.71.dist-info}/RECORD +10 -9
- {coralnet_toolbox-0.0.70.dist-info → coralnet_toolbox-0.0.71.dist-info}/WHEEL +0 -0
- {coralnet_toolbox-0.0.70.dist-info → coralnet_toolbox-0.0.71.dist-info}/entry_points.txt +0 -0
- {coralnet_toolbox-0.0.70.dist-info → coralnet_toolbox-0.0.71.dist-info}/licenses/LICENSE.txt +0 -0
- {coralnet_toolbox-0.0.70.dist-info → coralnet_toolbox-0.0.71.dist-info}/top_level.txt +0 -0
@@ -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)
|
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,
|
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,
|
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,
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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,
|
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,
|
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
|
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
|
722
|
+
if isinstance(converted_value, (int, float)):
|
723
723
|
widget.setValue(int(converted_value))
|
724
724
|
elif isinstance(widget, QDoubleSpinBox):
|
725
|
-
if
|
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
|
-
|
730
|
-
|
731
|
-
|
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
|
733
|
+
# Add as a custom parameter
|
738
734
|
self.add_parameter_pair()
|
739
|
-
|
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
|
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
|
-
#
|
771
|
-
export_data = {
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
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
|
-
|
802
|
-
name =
|
803
|
-
|
804
|
-
type_name =
|
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
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
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,
|
coralnet_toolbox/__init__.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: coralnet-toolbox
|
3
|
-
Version: 0.0.
|
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=
|
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=
|
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=
|
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.
|
219
|
-
coralnet_toolbox-0.0.
|
220
|
-
coralnet_toolbox-0.0.
|
221
|
-
coralnet_toolbox-0.0.
|
222
|
-
coralnet_toolbox-0.0.
|
223
|
-
coralnet_toolbox-0.0.
|
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,,
|
File without changes
|
File without changes
|
{coralnet_toolbox-0.0.70.dist-info → coralnet_toolbox-0.0.71.dist-info}/licenses/LICENSE.txt
RENAMED
File without changes
|
File without changes
|