diff --git a/painter/src/convert_seg.py b/painter/src/convert_seg.py index 5f084b1..1ce8abf 100644 --- a/painter/src/convert_seg.py +++ b/painter/src/convert_seg.py @@ -56,6 +56,12 @@ def convert_seg_to_annot(seg): annot[1] = seg_fg return annot +def convert_seg_to_fg_annot(seg): + seg_fg = seg > 0 + annot = np.zeros([2] + list(seg.shape)) + annot[1] = seg_fg + return annot + class ConvertProgressWidget(BaseProgressWidget): def __init__(self): diff --git a/painter/src/im_viewer.py b/painter/src/im_viewer.py index 95fbdde..0a4b81b 100644 --- a/painter/src/im_viewer.py +++ b/painter/src/im_viewer.py @@ -47,9 +47,11 @@ def __init__(self, parent, view_mode): self.seg_visible = False self.image_visible = True self.guide_image_visible = False + self.prelabel_visible = False self.outline_visible = False self.image_pixmap_holder = None self.guide_image_pixmap_holder = None + self.prelabel_pixmap_holder = None self.seg_pixmap_holder = None self.blank_pixmap = None self.black_pixmap = None @@ -108,13 +110,15 @@ def init_ui(self): self.inner_layout.addWidget(self.graphics_view) if self.mode == 'axial': self.vis_widget = VisibilityWidget(QtWidgets.QVBoxLayout, self, - show_guide=hasattr(self.parent, 'guide_image_dir')) + show_guide=hasattr(self.parent, 'guide_image_dir'), + show_prelabel=hasattr(self.parent, 'prelabel_dir')) self.vis_widget.setMaximumWidth(200) # left, top, right, bottom self.bottom_bar_layout.setContentsMargins(20, 0, 20, 0) else: self.vis_widget = VisibilityWidget(QtWidgets.QHBoxLayout, self, - show_guide=hasattr(self.parent, 'guide_image_dir')) + show_guide=hasattr(self.parent, 'guide_image_dir'), + show_prelabel=hasattr(self.parent, 'prelabel_dir')) self.vis_widget.setMaximumWidth(500) # left, top, right, bottom @@ -145,6 +149,12 @@ def im_checkbox_change(self, state): checked = (state == QtCore.Qt.Checked) if checked is not self.image_visible: self.show_hide_image() + + def prelabel_checkbox_change(self, state): + """ set checkbox to specified state and update visibility if required """ + checked = (state == QtCore.Qt.Checked) + if checked is not self.prelabel_visible: + self.show_hide_prelabel() def outline_checkbox_change(self, state): """ set checkbox to specified state and update visibility if required """ @@ -280,6 +290,18 @@ def show_hide_annot(self): self.annot_visible = True self.vis_widget.annot_checkbox.setChecked(self.annot_visible) + def show_hide_prelabel(self): + """ show or hide the preliminary labels. + Could be useful to use them as annotations, if they are good. + """ + if self.prelabel_visible: + self.prelabel_pixmap_holder.setPixmap(self.blank_pixmap) + self.prelabel_visible = False + else: + self.prelabel_pixmap_holder.setPixmap(self.prelabel_pixmap) + self.prelabel_visible = True + self.vis_widget.prelabel_checkbox.setChecked(self.prelabel_visible) + def show_hide_outline(self): """ show or hide the current outline. Could be useful to help inspect the @@ -424,7 +446,22 @@ def update_seg_slice(self): if not self.seg_visible: self.seg_pixmap_holder.setPixmap(self.blank_pixmap) + if self.parent.prelabel_data is not None: + prelabel_slice = im_utils.get_slice(self.parent.prelabel_data, + self.slice_nav.slice_idx, + self.mode) + self.prelabel_pixmap = im_utils.seg_slice_to_pixmap(prelabel_slice) + self.scene.prelabel_pixmap = self.prelabel_pixmap + + if self.prelabel_pixmap_holder: + self.prelabel_pixmap_holder.setPixmap(self.prelabel_pixmap) + self.scene.prelabel_pixmap = self.prelabel_pixmap + else: + self.prelabel_pixmap_holder = self.scene.addPixmap(self.prelabel_pixmap) + if not self.prelabel_visible: + self.prelabel_pixmap_holder.setPixmap(self.blank_pixmap) + def update_cursor(self, ctrl_press=False): """ render cursor based on zoom level, brush color and brush size """ diff --git a/painter/src/menus.py b/painter/src/menus.py index c69dfe4..b33a2a1 100644 --- a/painter/src/menus.py +++ b/painter/src/menus.py @@ -7,7 +7,7 @@ from PyQt5 import QtGui from segment_folder import SegmentFolderWidget from segment import segment_full_image -from convert_seg import ConvertSegWidget, convert_seg_to_annot +from convert_seg import ConvertSegWidget, convert_seg_to_annot, convert_seg_to_fg_annot from assign_corrections import AssignCorrectionsWidget from extract_image_props import ExtractSegImagePropsWidget from compute_metrics import ExtractSegMetricsWidget @@ -156,7 +156,7 @@ def add_help_menu(self, menu_bar): help_menu.addAction(shortcut_btn) -def add_extras_menu(main_window, menu_bar, project_open=False): +def add_extras_menu(main_window, menu_bar, project_open=False, prelabels = False): extras_menu = menu_bar.addMenu('Extras') def show_conv_to_annot(): @@ -196,6 +196,22 @@ def show_assign_corrections(): if project_open: + if prelabels: + conv_this_annot_btn = QtWidgets.QAction(QtGui.QIcon('missing.png'), + 'Convert preliminary labels to current annotation', + main_window) + def convert_prelabel(): + main_window.annot_data = convert_seg_to_fg_annot(main_window.prelabel_data) + for v in main_window.viewers: + v.update_image() + v.update_cursor() + # # hide the segmentation if we don't have it + # if main_window.seg_data is None and v.seg_visible: + # # show seg in order to show the loading message + # v.show_hide_seg() + conv_this_annot_btn.triggered.connect(convert_prelabel) + extras_menu.addAction(conv_this_annot_btn) + extend_dataset_btn = QtWidgets.QAction(QtGui.QIcon('missing.png'), 'Extend dataset', main_window) def update_dataset_after_check(): was_extended, file_names = check_extend_dataset(main_window, @@ -296,6 +312,11 @@ def add_view_menu(window, im_viewer, menu_bar): toggle_guide_image_visibility_btn.triggered.connect(im_viewer.show_hide_guide_image) view_menu.addAction(toggle_guide_image_visibility_btn) + toggle_prelabel_visibility_btn = QtWidgets.QAction(QtGui.QIcon('missing.png'), 'Toggle guide image visibility', window) + toggle_prelabel_visibility_btn.setShortcut('D') + toggle_prelabel_visibility_btn.setStatusTip('Show or hide image') + toggle_prelabel_visibility_btn.triggered.connect(im_viewer.show_hide_prelabel) + view_menu.addAction(toggle_prelabel_visibility_btn) # toggle outline visibility toggle_outline_visibility_btn = QtWidgets.QAction(QtGui.QIcon('missing.png'), diff --git a/painter/src/root_painter.py b/painter/src/root_painter.py index 1e39eaf..2508499 100644 --- a/painter/src/root_painter.py +++ b/painter/src/root_painter.py @@ -79,6 +79,8 @@ def __init__(self, sync_dir, contrast_presets, server_ip=None, server_port=None) self.im_height = None self.annot_data = None self.seg_data = None + self.prelabel_data = None + self.prelabel_exists = False # for patch segment, useful for knowing how much annotation to send to the server. self.input_shape = (52, 228, 228) @@ -146,6 +148,10 @@ def open_project(self, proj_file_path): self.seg_dir = self.proj_location / 'segmentations' self.log_dir = self.proj_location / 'logs' + if 'prelabel_dir' in settings: + self.prelabel_dir = self.proj_location / 'prelabel' + self.prelabel_exists = True + self.train_seg_dirs = [] self.train_annot_dirs = [] self.val_annot_dirs = [] @@ -304,7 +310,15 @@ def update_annot_and_seg(self): else: # it should come later self.seg_data = None - + + if hasattr(self, 'prelabel_dir'): + prelabel_image_path = os.path.join(os.path.join(self.prelabel_dir, self.fname)) + # and a guide image is available for the current image. + if os.path.isfile(prelabel_image_path): + self.prelabel_data = im_utils.load_image(prelabel_image_path) + else: + pass + for v in self.viewers: v.update_image() v.update_cursor() @@ -459,7 +473,7 @@ def init_missing_project_ui(self): menus.add_help_menu(self, menu_bar) - menus.add_extras_menu(self, menu_bar) + menus.add_extras_menu(self, menu_bar, prelabels=self.prelabel_exists) menus.add_measurements_menu(self, menu_bar) # Add project btns to open window (so it shows something useful) @@ -750,7 +764,7 @@ def add_menu(self): if len(self.classes) > 1: menus.add_class_menu(self, self.menu_bar) menus.add_help_menu(self, self.menu_bar) - menus.add_extras_menu(self, menu_bar, project_open=True) + menus.add_extras_menu(self, menu_bar, project_open=True, prelabels=self.prelabel_exists) menus.add_measurements_menu(self, menu_bar) diff --git a/painter/src/visibility_widget.py b/painter/src/visibility_widget.py index 72c24ee..29aeabc 100644 --- a/painter/src/visibility_widget.py +++ b/painter/src/visibility_widget.py @@ -21,11 +21,11 @@ class VisibilityWidget(QtWidgets.QWidget): - def __init__(self, layout_class, parent, show_guide=False): + def __init__(self, layout_class, parent, show_guide=False, show_prelabel=False): super().__init__() - self.initUI(layout_class, parent, show_guide) + self.initUI(layout_class, parent, show_guide, show_prelabel) - def initUI(self, layout_class, parent, show_guide): + def initUI(self, layout_class, parent, show_guide, show_prelabel): # container goes full width to allow contents to be center aligned within it. widget = QtWidgets.QWidget() layout = QtWidgets.QHBoxLayout() @@ -56,6 +56,13 @@ def initUI(self, layout_class, parent, show_guide): guide_image_checkbox.setChecked(False) self.guide_image_checkbox = guide_image_checkbox self.guide_image_checkbox.stateChanged.connect(parent.guide_checkbox_change) + + if show_prelabel: + prelabel_checkbox = QtWidgets.QCheckBox("Preliminary labels (D)") + container_layout.addWidget(prelabel_checkbox) + prelabel_checkbox.setChecked(False) + self.prelabel_checkbox = prelabel_checkbox + self.prelabel_checkbox.stateChanged.connect(parent.prelabel_checkbox_change) seg_checkbox.setChecked(False) annot_checkbox.setChecked(True)