diff --git a/coralnet_toolbox/MachineLearning/ExportDataset/QtBase.py b/coralnet_toolbox/MachineLearning/ExportDataset/QtBase.py index 5dc97452..fcb775b1 100644 --- a/coralnet_toolbox/MachineLearning/ExportDataset/QtBase.py +++ b/coralnet_toolbox/MachineLearning/ExportDataset/QtBase.py @@ -46,7 +46,7 @@ def __init__(self, main_window, parent=None): self.selected_labels = [] self.selected_annotations = [] self.updating_summary_statistics = False - + self.output_dir = None self.dataset_name = None self.train_ratio = 0.7 @@ -77,7 +77,7 @@ def showEvent(self, event): self.update_annotation_type_checkboxes() self.populate_class_filter_list() self.update_summary_statistics() - + def setup_info_layout(self): """ Set up the layout and widgets for the info layout. @@ -300,7 +300,7 @@ def get_class_mapping(self): """ # Get the label objects for the selected labels class_mapping = {} - + for label in self.main_window.label_window.labels: if label.short_label_code in self.selected_labels: class_mapping[label.short_label_code] = label.to_dict() @@ -364,7 +364,7 @@ def filter_annotations(self): # Filter annotations based on the selected image option if self.filtered_images_radio.isChecked(): annotations = [a for a in annotations if a.image_path in self.image_window.filtered_image_paths] - + return annotations def populate_class_filter_list(self): @@ -529,6 +529,13 @@ def check_label_distribution(self): return True + def update_image_selection(self): + """ + Update the table based on the selected image option. + """ + self.selected_annotations = self.filter_annotations() + self.update_summary_statistics() + def update_summary_statistics(self): """ Update the summary statistics for the dataset creation. @@ -592,7 +599,7 @@ def update_summary_statistics(self): self.ready_label.setText("✅ Ready" if (self.ready_status and self.split_status) else "❌ Not Ready") self.updating_summary_statistics = False - + def is_ready(self): """Check if the dataset is ready to be created.""" # Extract the input values, store them in the class variables @@ -620,9 +627,9 @@ def is_ready(self): "Input Error", "Train, Validation, and Test ratios must sum to 1.0") return False - + return True - + def accept(self): """ Handle the OK button click event to create the dataset. @@ -632,7 +639,7 @@ def accept(self): # Create the output folder output_dir_path = os.path.join(self.output_dir, self.dataset_name) - + # Check if the output directory exists if os.path.exists(output_dir_path): reply = QMessageBox.question(self, @@ -670,16 +677,9 @@ def accept(self): "Dataset Created", "Dataset has been successfully created.") super().accept() - - def create_dataset(self): - raise NotImplementedError("Method must be implemented in the subclass.") - - def process_annotations(self): + + def create_dataset(self, output_dir_path): raise NotImplementedError("Method must be implemented in the subclass.") - def update_image_selection(self): - """ - Update the table based on the selected image option. - """ - self.selected_annotations = self.filter_annotations() - self.update_summary_statistics() + def process_annotations(self, annotations, split_dir, split): + raise NotImplementedError("Method must be implemented in the subclass.") diff --git a/coralnet_toolbox/QtAnnotationWindow.py b/coralnet_toolbox/QtAnnotationWindow.py index e53fcda3..e7ccb3fe 100644 --- a/coralnet_toolbox/QtAnnotationWindow.py +++ b/coralnet_toolbox/QtAnnotationWindow.py @@ -408,8 +408,7 @@ def select_annotation(self, annotation, ctrl_pressed=False): if len(self.selected_annotations) > 1: self.main_window.label_window.deselect_active_label() self.main_window.confidence_window.clear_display() - - # TODO test + def select_annotations(self): """Select all annotations in the current image.""" annotations = self.get_image_annotations() @@ -417,7 +416,7 @@ def select_annotations(self): if self.main_window.label_window.label_locked: if annotation.label.id == self.main_window.label_window.locked_label.id: self.select_annotation(annotation, ctrl_pressed=True) - else: + else: self.select_annotation(annotation, ctrl_pressed=True) def unselect_annotation(self, annotation): diff --git a/coralnet_toolbox/QtEventFilter.py b/coralnet_toolbox/QtEventFilter.py index e14f4227..36c3c06d 100644 --- a/coralnet_toolbox/QtEventFilter.py +++ b/coralnet_toolbox/QtEventFilter.py @@ -75,13 +75,13 @@ def eventFilter(self, obj, event): self.image_window.cycle_next_image() return True - # Select all annotations on < key press - if event.key() == Qt.Key_Less: + # Select all annotations on < key press with Shift+Ctrl + if event.key() == Qt.Key_Less and event.modifiers() == (Qt.ShiftModifier | Qt.ControlModifier): self.annotation_window.select_annotations() return True - # Unselect all annotations on > key press - if event.key() == Qt.Key_Greater: + # Unselect all annotations on > key press with Shift+Ctrl + if event.key() == Qt.Key_Greater and event.modifiers() == (Qt.ShiftModifier | Qt.ControlModifier): self.annotation_window.unselect_annotations() return True diff --git a/docs/usage.md b/docs/usage.md index 7e170198..d2acb22a 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -135,8 +135,8 @@ The main window consists of several components: - **Ctrl + Mouse Wheel**: Adjust annotation size. - **Ctrl + Left/Right**: Cycle through annotations. - **Ctrl + Up/Down**: Cycle through images. -- **Ctrl + <**: Select all annotations. -- **Ctrl + >**: Unselect all annotations. +- **Ctrl + Shift + <**: Select all annotations. +- **Ctrl + Shift + >**: Unselect all annotations. - **Escape**: Exit the program. - **Machine Learning, SAM, and AutoDistill**: After a model is loaded