From 0c848d401aeb2de9e221e3e20531b78009fd9c10 Mon Sep 17 00:00:00 2001 From: Ines del Val Date: Fri, 22 Nov 2024 12:13:33 +0100 Subject: [PATCH 1/7] Key binding for changing bounding box color and adding class in csv file --- napari_organoid_counter/_utils.py | 6 +- napari_organoid_counter/_widget.py | 125 +++++++++++++++++++++++++++-- 2 files changed, 124 insertions(+), 7 deletions(-) diff --git a/napari_organoid_counter/_utils.py b/napari_organoid_counter/_utils.py index 541fa84..9a75394 100644 --- a/napari_organoid_counter/_utils.py +++ b/napari_organoid_counter/_utils.py @@ -62,12 +62,13 @@ def write_to_json(name, data): with open(name, 'w') as outfile: json.dump(data, outfile) -def get_bboxes_as_dict(bboxes, bbox_ids, scores, scales): +def get_bboxes_as_dict(bboxes, bbox_ids, scores, scales, labels): """ Write all data, boxes, ids and scores and scale, to a dict so we can later save as a json """ data_json = {} for idx, bbox in enumerate(bboxes): x1, y1 = bbox[0] x2, y2 = bbox[2] + data_json.update({str(bbox_ids[idx]): {'box_id': str(bbox_ids[idx]), 'x1': str(x1), 'x2': str(x2), @@ -75,7 +76,8 @@ def get_bboxes_as_dict(bboxes, bbox_ids, scores, scales): 'y2': str(y2), 'confidence': str(scores[idx]), 'scale_x': str(scales[0]), - 'scale_y': str(scales[1]) + 'scale_y': str(scales[1]), + 'class': labels[idx] } }) return data_json diff --git a/napari_organoid_counter/_widget.py b/napari_organoid_counter/_widget.py index 37fe7d0..f9e2993 100644 --- a/napari_organoid_counter/_widget.py +++ b/napari_organoid_counter/_widget.py @@ -3,9 +3,13 @@ from skimage.io import imsave from datetime import datetime +import napari + from napari import layers from napari.utils.notifications import show_info +import numpy as np + from qtpy.QtCore import Qt from qtpy.QtWidgets import QWidget, QVBoxLayout, QApplication, QDialog, QFileDialog, QGroupBox, QHBoxLayout, QLabel, QComboBox, QPushButton, QLineEdit, QProgressBar, QSlider @@ -112,9 +116,86 @@ def __init__(self, self.viewer.layers.events.inserted.connect(self._added_layer) self.viewer.layers.events.removed.connect(self._removed_layer) self.viewer.layers.selection.events.changed.connect(self._sel_layer_changed) + # setup flags used for changing slider and text of min diameter and confidence threshold self.diameter_slider_changed = False - self.confidence_slider_changed = False + self.confidence_slider_changed = False + + # Key binding to return the ID of the bounding boxes selected from the GUI + @self.viewer.bind_key('s') + def selected_boxes(viewer: napari.Viewer): + if self.cur_shapes_layer is not None: # Check if there is a valid shapes layer selected + selected_shapes = self.cur_shapes_layer.selected_data + print(f"Selected shapes indices: {selected_shapes}") + + # Dictionary where key are shape indices and values are RGBA colors + self.original_colors = {} + + # Key binding to change the edge_color of the bounding boxes to green + @self.viewer.bind_key('g') + def change_edge_color_to_green(viewer: napari.Viewer): + if self.cur_shapes_layer is not None: # Ensure shapes layer exists + selected_shapes = self.cur_shapes_layer.selected_data # Retrieves indices of shapes currently selected, returns a set + if len(selected_shapes) > 0: + # Set the edge color of selected shapes to green + new_edge_color = [85/255, 1., 0, 1.] # RGBA for green + # Modify the edge color only for the selected shapes + current_edge_colors = self.cur_shapes_layer.edge_color + for idx in selected_shapes: + # Save original color + if idx not in self.original_colors: + self.original_colors[idx] = current_edge_colors[idx].copy() + # Update to the new color + current_edge_colors[idx] = new_edge_color + + self.cur_shapes_layer.edge_color = current_edge_colors # Apply the changes + print(f"Changed edge color of {idx} to {new_edge_color}") + else: + print("No shapes selected to change edge color.") + + # Key binding to change the edge_color of the bounding boxes to blue + @self.viewer.bind_key('h') + def change_edge_color_to_blue(viewer: napari.Viewer): + if self.cur_shapes_layer is not None: # Ensure shapes layer exists + selected_shapes = self.cur_shapes_layer.selected_data + if len(selected_shapes) > 0: + # Set the edge color of selected shapes to green + new_edge_color = [0, 29/255, 1., 1.] # RGBA for blue + # Modify the edge color only for the selected shapes + current_edge_colors = self.cur_shapes_layer.edge_color + for idx in selected_shapes: + # Save original color + if idx not in self.original_colors: + self.original_colors[idx] = current_edge_colors[idx].copy() + # Update to the new color + current_edge_colors[idx] = new_edge_color + self.cur_shapes_layer.edge_color = current_edge_colors # Apply the changes + print(f"Changed edge color of {idx} to {new_edge_color}") + else: + print("No shapes selected to change edge color.") + + # Key binding to reset the edge_color of selected bounding boxes to their original color + @self.viewer.bind_key('z') + def reset_edge_color(viewer: napari.Viewer): + if self.cur_shapes_layer is not None: # Ensure shapes layer exists + selected_shapes = self.cur_shapes_layer.selected_data + if len(selected_shapes) > 0: + current_edge_colors = self.cur_shapes_layer.edge_color + + for idx in selected_shapes: + if idx in self.original_colors: + # Revert to the original color + current_edge_colors[idx] = self.original_colors[idx] + # Remove from the dictionary after reverting + del self.original_colors[idx] + else: + print(f"No original color stored for shape {idx}, skipping reset.") + + self.cur_shapes_layer.edge_color = current_edge_colors # Apply the changes + print(f"Reset edge color of {idx} to their original color.") + else: + print("No shapes selected to reset edge color.") + def handle_progress(self, blocknum, blocksize, totalsize): """ When the model is being downloaded, this method is called and th progress of the download @@ -218,6 +299,7 @@ def _update_vis_bboxes(self, bboxes, scores, box_ids, labels_layer_name): # set current_edge_width so edge width is the same when users annotate - doesnt' fix new preds being added! self.viewer.layers[labels_layer_name].current_edge_width = 12 + def _on_preprocess_click(self): """ Is called whenever preprocess button is clicked """ @@ -423,10 +505,41 @@ def _on_save_json_click(self): #scores = #add if not bboxes: show_info('No organoids detected! Please run auto organoid counter or run algorithm first and try again!') else: + # Get the edge colors for all bounding boxes + edge_colors = self.cur_shapes_layer.edge_color + labels = [] + + # Check if all bounding boxes have their edge color set (not green or blue) + green = np.array([85/255, 1., 0, 1.]) + blue = np.array([29/255, 0, 1., 1.]) + + all_colored = True + for edge_color in edge_colors: + # Compare the colors with a tolerance using np.allclose to account for floating-point errors + if not (np.allclose(edge_color[:3], green[:3]) or np.allclose(edge_color[:3], blue[:3])): + all_colored = False + break + + if not all_colored: + show_info('Please change the color of all bounding boxes before saving.') + return + + # Assign organoid label based on edge_color + for edge_color in edge_colors: + if np.allclose(edge_color[:3], green[:3]): + labels.append(0) # Label for green + elif np.allclose(edge_color[:3], blue[:3]): + labels.append(1) # Label for blue + else: + labels.append(-1) # Label for other colors + data_json = utils.get_bboxes_as_dict(bboxes, - self.viewer.layers[self.save_layer_name].properties['box_id'], - self.viewer.layers[self.save_layer_name].properties['scores'], - self.viewer.layers[self.save_layer_name].scale) + self.viewer.layers[self.save_layer_name].properties['box_id'], + self.viewer.layers[self.save_layer_name].properties['scores'], + self.viewer.layers[self.save_layer_name].scale, + labels=labels) + + # write bbox coordinates to json fd = QFileDialog() name,_ = fd.getSaveFileName(self, 'Save File', self.save_layer_name, 'JSON files (*.json)')#, 'CSV Files (*.csv)') @@ -471,7 +584,8 @@ def _update_added_shapes(self, added_items): self.organoiDL.update_bboxes_scores(self.cur_shapes_name, self.cur_shapes_layer.data, self.cur_shapes_layer.properties['scores'], - self.cur_shapes_layer.properties['box_id']) + self.cur_shapes_layer.properties['box_id'] + ) self.cur_shapes_layer.events.data.connect(self.shapes_event_handler) def _update_remove_shapes(self, removed_layers): @@ -507,6 +621,7 @@ def shapes_event_handler(self, event): new_ids[-1] = self.organoiDL.next_id[self.cur_shapes_name] new_scores = self.viewer.layers[self.cur_shapes_name].properties['scores'] new_scores[-1] = 1 + # set new properties to shapes layer self.viewer.layers[self.cur_shapes_name].properties ={'box_id': new_ids,'scores': new_scores} # refresh text displayed From 439211191da490d1af01e0838cd3933a85a3f9e9 Mon Sep 17 00:00:00 2001 From: Ines del Val Date: Mon, 25 Nov 2024 11:47:06 +0100 Subject: [PATCH 2/7] single/multi annotation mode drop down box --- napari_organoid_counter/_widget.py | 80 +++++++++++++++++++++++++----- 1 file changed, 68 insertions(+), 12 deletions(-) diff --git a/napari_organoid_counter/_widget.py b/napari_organoid_counter/_widget.py index f9e2993..1761d1f 100644 --- a/napari_organoid_counter/_widget.py +++ b/napari_organoid_counter/_widget.py @@ -99,6 +99,10 @@ def __init__(self, self.stored_confidences = {} self.stored_diameters = {} + # Initialize multi_annotation_mode to False by default + self.multi_annotation_mode = False + self.single_annotation_mode = True # Initially, it's single annotation mode + # setup gui self.setLayout(QVBoxLayout()) self.layout().addWidget(self._setup_input_widget()) @@ -134,6 +138,10 @@ def selected_boxes(viewer: napari.Viewer): # Key binding to change the edge_color of the bounding boxes to green @self.viewer.bind_key('g') def change_edge_color_to_green(viewer: napari.Viewer): + if self.single_annotation_mode: # Check if single-annotation mode is active + show_info("Cannot change edge color. Change to multi-annotation mode to enable this feature.") + return + if self.cur_shapes_layer is not None: # Ensure shapes layer exists selected_shapes = self.cur_shapes_layer.selected_data # Retrieves indices of shapes currently selected, returns a set if len(selected_shapes) > 0: @@ -156,6 +164,10 @@ def change_edge_color_to_green(viewer: napari.Viewer): # Key binding to change the edge_color of the bounding boxes to blue @self.viewer.bind_key('h') def change_edge_color_to_blue(viewer: napari.Viewer): + if self.single_annotation_mode: # Check if single-annotation mode is active + show_info("Cannot change edge color. Change to multi-annotation mode to enable this feature.") + return + if self.cur_shapes_layer is not None: # Ensure shapes layer exists selected_shapes = self.cur_shapes_layer.selected_data if len(selected_shapes) > 0: @@ -177,6 +189,10 @@ def change_edge_color_to_blue(viewer: napari.Viewer): # Key binding to reset the edge_color of selected bounding boxes to their original color @self.viewer.bind_key('z') def reset_edge_color(viewer: napari.Viewer): + if self.single_annotation_mode: # Check if single-annotation mode is active + show_info("Cannot change edge color. Change to multi-annotation mode to enable this feature.") + return + if self.cur_shapes_layer is not None: # Ensure shapes layer exists selected_shapes = self.cur_shapes_layer.selected_data if len(selected_shapes) > 0: @@ -486,6 +502,17 @@ def _on_screenshot_click(self): name,_ = fd.getSaveFileName(self, 'Save File', potential_name, 'Image files (*.png);;(*.tiff)') #, 'CSV Files (*.csv)') if name: imsave(name, screenshot) + def on_annotation_mode_changed(self, index): + """Callback for dropdown selection.""" + if index == 0: # Single Annotation + self.multi_annotation_mode = False + self.single_annotation_mode = True + print("Switched to Single Annotation mode.") + elif index == 1: # Multi Annotation + self.multi_annotation_mode = True + self.single_annotation_mode = False + print("Switched to Multi Annotation mode.") + def _on_save_csv_click(self): """ Is called whenever Save features button is clicked """ bboxes = self.viewer.layers[self.save_layer_name].data @@ -503,15 +530,20 @@ def _on_save_json_click(self): """ Is called whenever Save boxes button is clicked """ bboxes = self.viewer.layers[self.save_layer_name].data #scores = #add - if not bboxes: show_info('No organoids detected! Please run auto organoid counter or run algorithm first and try again!') - else: + if not bboxes: + show_info('No organoids detected! Please run auto organoid counter or run algorithm first and try again!') + return + + # Check for multi-annotation mode + if self.multi_annotation_mode: + # Get the edge colors for all bounding boxes edge_colors = self.cur_shapes_layer.edge_color labels = [] # Check if all bounding boxes have their edge color set (not green or blue) green = np.array([85/255, 1., 0, 1.]) - blue = np.array([29/255, 0, 1., 1.]) + blue = np.array([0, 29/255, 1., 1.]) all_colored = True for edge_color in edge_colors: @@ -533,17 +565,21 @@ def _on_save_json_click(self): else: labels.append(-1) # Label for other colors - data_json = utils.get_bboxes_as_dict(bboxes, - self.viewer.layers[self.save_layer_name].properties['box_id'], - self.viewer.layers[self.save_layer_name].properties['scores'], - self.viewer.layers[self.save_layer_name].scale, - labels=labels) + elif self.single_annotation_mode: + # Single annotation mode: all bounding boxes get a default label + labels = [0] * len(bboxes) # Default label for single annotation mode + + data_json = utils.get_bboxes_as_dict(bboxes, + self.viewer.layers[self.save_layer_name].properties['box_id'], + self.viewer.layers[self.save_layer_name].properties['scores'], + self.viewer.layers[self.save_layer_name].scale, + labels=labels) - # write bbox coordinates to json - fd = QFileDialog() - name,_ = fd.getSaveFileName(self, 'Save File', self.save_layer_name, 'JSON files (*.json)')#, 'CSV Files (*.csv)') - if name: utils.write_to_json(name, data_json) + # write bbox coordinates to json + fd = QFileDialog() + name,_ = fd.getSaveFileName(self, 'Save File', self.save_layer_name, 'JSON files (*.json)')#, 'CSV Files (*.csv)') + if name: utils.write_to_json(name, data_json) def _update_added_image(self, added_items): """ @@ -645,6 +681,7 @@ def _setup_input_widget(self): window_sizes_box = self._setup_window_sizes_box() downsampling_box = self._setup_downsampling_box() run_box = self._setup_run_box() + annotation_mode_box = self._setup_annotation_mode_box() # Annotation mode dropdown to select single or multi-annotation self._setup_progress_box() # and add all these to the layout @@ -655,6 +692,7 @@ def _setup_input_widget(self): vbox.addLayout(window_sizes_box) vbox.addLayout(downsampling_box) vbox.addLayout(run_box) + vbox.addLayout(annotation_mode_box) # Add the annotation dropdown vbox.addWidget(self.progress_box) input_widget.setLayout(vbox) return input_widget @@ -797,6 +835,24 @@ def _setup_run_box(self): hbox.addWidget(run_btn) hbox.addStretch(1) return hbox + + def _setup_annotation_mode_box(self): + """ + Sets up the GUI part where the annotation mode is selected. + """ + hbox = QHBoxLayout() + + # Label + annotation_mode_label = QLabel("Annotation Mode:", self) + hbox.addWidget(annotation_mode_label) + + # Dropdown + self.annotation_mode_dropdown = QComboBox() + self.annotation_mode_dropdown.addItems(["Single Annotation", "Multi Annotation"]) + self.annotation_mode_dropdown.currentIndexChanged.connect(self.on_annotation_mode_changed) + hbox.addWidget(self.annotation_mode_dropdown) + + return hbox def _setup_progress_box(self): """ From 30b63842d29718c723b8d297b393e90d5ca094ea Mon Sep 17 00:00:00 2001 From: Ines del Val Date: Fri, 29 Nov 2024 10:57:44 +0100 Subject: [PATCH 3/7] Saving colors as global variables --- napari_organoid_counter/settings.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/napari_organoid_counter/settings.py b/napari_organoid_counter/settings.py index b8b4039..ced0c20 100644 --- a/napari_organoid_counter/settings.py +++ b/napari_organoid_counter/settings.py @@ -38,7 +38,15 @@ def init(): "rtmdet": {"source": "https://zenodo.org/records/11388549/files/rtmdet_l_organoid.py", "destination": ".mim/configs/rtmdet/rtmdet_l_organoid.py" } + } + + # Add color definitions + global COLOR_CLASS_1 + COLOR_CLASS_1 = [85 / 255, 1.0, 0, 1.0] # Green + + global COLOR_CLASS_2 + COLOR_CLASS_2 = [0, 29 / 255, 1.0, 1.0] # Blue From 6917838ce137e084be832c8298ac94a535ccaab3 Mon Sep 17 00:00:00 2001 From: Ines del Val Date: Fri, 29 Nov 2024 11:01:04 +0100 Subject: [PATCH 4/7] Addressed reviewed comments --- napari_organoid_counter/_utils.py | 2 +- napari_organoid_counter/_widget.py | 107 +++++++++++++---------------- 2 files changed, 48 insertions(+), 61 deletions(-) diff --git a/napari_organoid_counter/_utils.py b/napari_organoid_counter/_utils.py index 9a75394..be95840 100644 --- a/napari_organoid_counter/_utils.py +++ b/napari_organoid_counter/_utils.py @@ -63,7 +63,7 @@ def write_to_json(name, data): json.dump(data, outfile) def get_bboxes_as_dict(bboxes, bbox_ids, scores, scales, labels): - """ Write all data, boxes, ids and scores and scale, to a dict so we can later save as a json """ + """ Write all data, boxes, ids and scores, scale and class label, to a dict so we can later save as a json """ data_json = {} for idx, bbox in enumerate(bboxes): x1, y1 = bbox[0] diff --git a/napari_organoid_counter/_widget.py b/napari_organoid_counter/_widget.py index 1761d1f..a838f38 100644 --- a/napari_organoid_counter/_widget.py +++ b/napari_organoid_counter/_widget.py @@ -6,7 +6,7 @@ import napari from napari import layers -from napari.utils.notifications import show_info +from napari.utils.notifications import show_info, show_error, show_warning import numpy as np @@ -101,7 +101,7 @@ def __init__(self, # Initialize multi_annotation_mode to False by default self.multi_annotation_mode = False - self.single_annotation_mode = True # Initially, it's single annotation mode + # self.single_annotation_mode = True # Initially, it's single annotation mode # setup gui self.setLayout(QVBoxLayout()) @@ -125,92 +125,78 @@ def __init__(self, self.diameter_slider_changed = False self.confidence_slider_changed = False - # Key binding to return the ID of the bounding boxes selected from the GUI - @self.viewer.bind_key('s') - def selected_boxes(viewer: napari.Viewer): - if self.cur_shapes_layer is not None: # Check if there is a valid shapes layer selected - selected_shapes = self.cur_shapes_layer.selected_data - print(f"Selected shapes indices: {selected_shapes}") - - # Dictionary where key are shape indices and values are RGBA colors - self.original_colors = {} - # Key binding to change the edge_color of the bounding boxes to green @self.viewer.bind_key('g') def change_edge_color_to_green(viewer: napari.Viewer): - if self.single_annotation_mode: # Check if single-annotation mode is active - show_info("Cannot change edge color. Change to multi-annotation mode to enable this feature.") + if not self.multi_annotation_mode: # Check if single-annotation mode is active + show_error("Cannot change edge color. Change to multi-annotation mode to enable this feature.") return - if self.cur_shapes_layer is not None: # Ensure shapes layer exists selected_shapes = self.cur_shapes_layer.selected_data # Retrieves indices of shapes currently selected, returns a set if len(selected_shapes) > 0: - # Set the edge color of selected shapes to green - new_edge_color = [85/255, 1., 0, 1.] # RGBA for green # Modify the edge color only for the selected shapes current_edge_colors = self.cur_shapes_layer.edge_color + changed_indices = [] # To collect all changed indices for idx in selected_shapes: # Save original color - if idx not in self.original_colors: - self.original_colors[idx] = current_edge_colors[idx].copy() + # if idx not in self.original_colors: + # self.original_colors[idx] = current_edge_colors[idx].copy() # Update to the new color - current_edge_colors[idx] = new_edge_color - + current_edge_colors[idx] = settings.COLOR_CLASS_1 + changed_indices.append(idx) # Add the index to the list self.cur_shapes_layer.edge_color = current_edge_colors # Apply the changes - print(f"Changed edge color of {idx} to {new_edge_color}") + show_info(f"Changed edge color of shapes {changed_indices} to green.") else: - print("No shapes selected to change edge color.") + show_warning("No shapes selected to change edge color.") # Key binding to change the edge_color of the bounding boxes to blue @self.viewer.bind_key('h') def change_edge_color_to_blue(viewer: napari.Viewer): - if self.single_annotation_mode: # Check if single-annotation mode is active - show_info("Cannot change edge color. Change to multi-annotation mode to enable this feature.") - return - + if not self.multi_annotation_mode: # Check if single-annotation mode is active + show_error("Cannot change edge color. Change to multi-annotation mode to enable this feature.") + return if self.cur_shapes_layer is not None: # Ensure shapes layer exists selected_shapes = self.cur_shapes_layer.selected_data if len(selected_shapes) > 0: - # Set the edge color of selected shapes to green - new_edge_color = [0, 29/255, 1., 1.] # RGBA for blue # Modify the edge color only for the selected shapes current_edge_colors = self.cur_shapes_layer.edge_color + changed_indices = [] # To collect all changed indices for idx in selected_shapes: # Save original color - if idx not in self.original_colors: - self.original_colors[idx] = current_edge_colors[idx].copy() + # if idx not in self.original_colors: + # self.original_colors[idx] = current_edge_colors[idx].copy() # Update to the new color - current_edge_colors[idx] = new_edge_color + current_edge_colors[idx] = settings.COLOR_CLASS_2 + changed_indices.append(idx) # Add the index to the list self.cur_shapes_layer.edge_color = current_edge_colors # Apply the changes - print(f"Changed edge color of {idx} to {new_edge_color}") + show_info(f"Changed edge color of {changed_indices} to blue.") else: - print("No shapes selected to change edge color.") + show_warning("No shapes selected to change edge color.") - # Key binding to reset the edge_color of selected bounding boxes to their original color - @self.viewer.bind_key('z') - def reset_edge_color(viewer: napari.Viewer): - if self.single_annotation_mode: # Check if single-annotation mode is active + # Key binding to reset the edge_color of selected bounding boxes to the original magenta color + @self.viewer.bind_key('m') + def change_to_original_color(viewer: napari.Viewer): + if not self.multi_annotation_mode: # Check if single-annotation mode is active show_info("Cannot change edge color. Change to multi-annotation mode to enable this feature.") return - if self.cur_shapes_layer is not None: # Ensure shapes layer exists selected_shapes = self.cur_shapes_layer.selected_data if len(selected_shapes) > 0: current_edge_colors = self.cur_shapes_layer.edge_color - + # Set the edge color back to magenta + new_edge_color = [1., 0, 1., 1.] # RGBA for magenta + # Modify the edge color only for the selected shapes + current_edge_colors = self.cur_shapes_layer.edge_color + changed_indices = [] # To collect all changed indices for idx in selected_shapes: - if idx in self.original_colors: + # if idx in self.original_colors: # Revert to the original color - current_edge_colors[idx] = self.original_colors[idx] - # Remove from the dictionary after reverting - del self.original_colors[idx] - else: - print(f"No original color stored for shape {idx}, skipping reset.") - + current_edge_colors[idx] = new_edge_color + changed_indices.append(idx) # Add the index to the list self.cur_shapes_layer.edge_color = current_edge_colors # Apply the changes - print(f"Reset edge color of {idx} to their original color.") + show_info(f"Reset edge color of {changed_indices} to magenta.") else: - print("No shapes selected to reset edge color.") + show_warning("No shapes selected to reset edge color.") def handle_progress(self, blocknum, blocksize, totalsize): @@ -506,12 +492,12 @@ def on_annotation_mode_changed(self, index): """Callback for dropdown selection.""" if index == 0: # Single Annotation self.multi_annotation_mode = False - self.single_annotation_mode = True - print("Switched to Single Annotation mode.") + # self.single_annotation_mode = True + show_info("Switched to Single Annotation mode.") elif index == 1: # Multi Annotation self.multi_annotation_mode = True - self.single_annotation_mode = False - print("Switched to Multi Annotation mode.") + # self.single_annotation_mode = False + show_info("Switched to Multi Annotation mode.") def _on_save_csv_click(self): """ Is called whenever Save features button is clicked """ @@ -542,8 +528,8 @@ def _on_save_json_click(self): labels = [] # Check if all bounding boxes have their edge color set (not green or blue) - green = np.array([85/255, 1., 0, 1.]) - blue = np.array([0, 29/255, 1., 1.]) + green = np.array(settings.COLOR_CLASS_1) + blue = np.array(settings.COLOR_CLASS_2) all_colored = True for edge_color in edge_colors: @@ -553,19 +539,20 @@ def _on_save_json_click(self): break if not all_colored: - show_info('Please change the color of all bounding boxes before saving.') + show_error('Please change the color of all bounding boxes before saving.') return # Assign organoid label based on edge_color for edge_color in edge_colors: if np.allclose(edge_color[:3], green[:3]): - labels.append(0) # Label for green + labels.append(1) # Label for green elif np.allclose(edge_color[:3], blue[:3]): - labels.append(1) # Label for blue + labels.append(2) # Label for blue else: - labels.append(-1) # Label for other colors + raise ValueError(f"Unexpected edge color {edge_color[:3]} encountered.") - elif self.single_annotation_mode: + #elif self.single_annotation_mode: + else: # Single annotation mode: all bounding boxes get a default label labels = [0] * len(bboxes) # Default label for single annotation mode From f0b932f2e5a31eef88fccfa17d13d9a75fb7b5bc Mon Sep 17 00:00:00 2001 From: Ines del Val Date: Fri, 29 Nov 2024 12:13:29 +0100 Subject: [PATCH 5/7] saved magenta color as global variable --- napari_organoid_counter/settings.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/napari_organoid_counter/settings.py b/napari_organoid_counter/settings.py index ced0c20..2eef96f 100644 --- a/napari_organoid_counter/settings.py +++ b/napari_organoid_counter/settings.py @@ -48,5 +48,8 @@ def init(): global COLOR_CLASS_2 COLOR_CLASS_2 = [0, 29 / 255, 1.0, 1.0] # Blue + global COLOR_DEFAULT + COLOR_DEFAULT = [1., 0, 1., 1.] # Magenta + From 3405f3488ec5898b4dec705d9cdbce9f60083cc9 Mon Sep 17 00:00:00 2001 From: Ines del Val Date: Fri, 29 Nov 2024 12:14:18 +0100 Subject: [PATCH 6/7] selected_shapes already keeps track of the indices of the boxes changed --- napari_organoid_counter/_widget.py | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/napari_organoid_counter/_widget.py b/napari_organoid_counter/_widget.py index a838f38..e29fa0c 100644 --- a/napari_organoid_counter/_widget.py +++ b/napari_organoid_counter/_widget.py @@ -136,16 +136,14 @@ def change_edge_color_to_green(viewer: napari.Viewer): if len(selected_shapes) > 0: # Modify the edge color only for the selected shapes current_edge_colors = self.cur_shapes_layer.edge_color - changed_indices = [] # To collect all changed indices for idx in selected_shapes: # Save original color # if idx not in self.original_colors: # self.original_colors[idx] = current_edge_colors[idx].copy() # Update to the new color current_edge_colors[idx] = settings.COLOR_CLASS_1 - changed_indices.append(idx) # Add the index to the list self.cur_shapes_layer.edge_color = current_edge_colors # Apply the changes - show_info(f"Changed edge color of shapes {changed_indices} to green.") + show_info(f"Changed edge color of shapes {list(selected_shapes)} to green.") else: show_warning("No shapes selected to change edge color.") @@ -160,16 +158,14 @@ def change_edge_color_to_blue(viewer: napari.Viewer): if len(selected_shapes) > 0: # Modify the edge color only for the selected shapes current_edge_colors = self.cur_shapes_layer.edge_color - changed_indices = [] # To collect all changed indices for idx in selected_shapes: # Save original color # if idx not in self.original_colors: # self.original_colors[idx] = current_edge_colors[idx].copy() # Update to the new color current_edge_colors[idx] = settings.COLOR_CLASS_2 - changed_indices.append(idx) # Add the index to the list self.cur_shapes_layer.edge_color = current_edge_colors # Apply the changes - show_info(f"Changed edge color of {changed_indices} to blue.") + show_info(f"Changed edge color of {list(selected_shapes)} to blue.") else: show_warning("No shapes selected to change edge color.") @@ -183,18 +179,14 @@ def change_to_original_color(viewer: napari.Viewer): selected_shapes = self.cur_shapes_layer.selected_data if len(selected_shapes) > 0: current_edge_colors = self.cur_shapes_layer.edge_color - # Set the edge color back to magenta - new_edge_color = [1., 0, 1., 1.] # RGBA for magenta # Modify the edge color only for the selected shapes current_edge_colors = self.cur_shapes_layer.edge_color - changed_indices = [] # To collect all changed indices for idx in selected_shapes: # if idx in self.original_colors: # Revert to the original color - current_edge_colors[idx] = new_edge_color - changed_indices.append(idx) # Add the index to the list + current_edge_colors[idx] = settings.COLOR_DEFAULT self.cur_shapes_layer.edge_color = current_edge_colors # Apply the changes - show_info(f"Reset edge color of {changed_indices} to magenta.") + show_info(f"Reset edge color of {list(selected_shapes)} to magenta.") else: show_warning("No shapes selected to reset edge color.") @@ -295,7 +287,7 @@ def _update_vis_bboxes(self, bboxes, scores, box_ids, labels_layer_name): face_color='transparent', properties = properties, text = text_params, - edge_color='magenta', + edge_color=settings.COLOR_DEFAULT, shape_type='rectangle', edge_width=12) # warning generated here From 2b661cbc4fc96ce837f901bd947f554a2df92e03 Mon Sep 17 00:00:00 2001 From: Ines del Val Date: Fri, 29 Nov 2024 15:07:05 +0100 Subject: [PATCH 7/7] changed class labels to 0 and 1 --- napari_organoid_counter/_widget.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/napari_organoid_counter/_widget.py b/napari_organoid_counter/_widget.py index e29fa0c..9d0b1c9 100644 --- a/napari_organoid_counter/_widget.py +++ b/napari_organoid_counter/_widget.py @@ -537,9 +537,9 @@ def _on_save_json_click(self): # Assign organoid label based on edge_color for edge_color in edge_colors: if np.allclose(edge_color[:3], green[:3]): - labels.append(1) # Label for green + labels.append(0) # Label for green elif np.allclose(edge_color[:3], blue[:3]): - labels.append(2) # Label for blue + labels.append(1) # Label for blue else: raise ValueError(f"Unexpected edge color {edge_color[:3]} encountered.")