コード例 #1
0
    def ResetLiveImgView(self):
        """Closes the widget nicely, making sure to clear the graphics scene and release memory."""
        self.selection_view.close()

        # Replot the imageview
        self.selection_view = DrawingWidget(self)
        self.selection_view.enable_drawing(True)
        self.selection_view.getView().setLimits(xMin = 0, xMax = 2048, yMin = 0, yMax = 2048, minXRange = 2048, \
                                                minYRange = 2048, maxXRange = 2048, maxYRange = 2048)
        self.selection_view.ui.roiBtn.hide()
        self.selection_view.ui.menuBtn.hide()
        self.selection_view.ui.normGroup.hide()
        self.selection_view.ui.roiPlot.hide()

        self.image_mask_stack.addTab(self.selection_view, 'Select')
コード例 #2
0
    def init_gui(self):
        self.setWindowTitle("Coordinate control")

        self.layout = QGridLayout()
        self.setMinimumSize(1250, 1000)
        self.setLayout(self.layout)

        self.image_mask_stack = QTabWidget()

        self.selection_view = DrawingWidget(self)
        self.selection_view.enable_drawing(True)
        self.selection_view.getView().setLimits(xMin=0,
                                                xMax=2048,
                                                yMin=0,
                                                yMax=2048,
                                                minXRange=2048,
                                                minYRange=2048,
                                                maxXRange=2048,
                                                maxYRange=2048)
        self.selection_view.ui.roiBtn.hide()
        self.selection_view.ui.menuBtn.hide()
        self.selection_view.ui.normGroup.hide()
        self.selection_view.ui.roiPlot.hide()
        # self.selection_view.setImage(plt.imread('CoordinatesManager/Registration_Images/StageRegistration/Distance200_Offset0/A1.png'))

        self.mask_view = SquareImageView()
        self.mask_view.getView().setLimits(xMin=0,
                                           xMax=2048,
                                           yMin=0,
                                           yMax=2048,
                                           minXRange=2048,
                                           minYRange=2048,
                                           maxXRange=2048,
                                           maxYRange=2048)
        self.mask_view.ui.roiBtn.hide()
        self.mask_view.ui.menuBtn.hide()
        self.mask_view.ui.normGroup.hide()
        self.mask_view.ui.roiPlot.hide()
        self.mask_view.ui.histogram.hide()

        self.image_mask_stack.addTab(self.selection_view, 'Select')
        self.image_mask_stack.addTab(self.mask_view, 'Mask')

        self.layout.addWidget(self.image_mask_stack, 0, 0, 5, 1)

        # ---------------------- Mask generation Container  --------------

        self.maskGeneratorContainer = roundQGroupBox()
        self.maskGeneratorContainer.setFixedSize(320, 220)
        self.maskGeneratorContainer.setTitle("Mask generator")
        self.maskGeneratorContainerLayout = QGridLayout()

        self.maskGeneratorLayout = QGridLayout()
        self.maskGeneratorContainer.setLayout(
            self.maskGeneratorContainerLayout)

        self.loadMaskFromFileButton = QPushButton('Open mask')
        self.loadMaskFromFileButton.clicked.connect(self.load_mask_from_file)

        self.addRoiButton = QPushButton("Add ROI")
        self.createMaskButton = QPushButton("Create mask")
        self.removeSelectionButton = QPushButton("Remove ROIs")
        self.addRoiButton.clicked.connect(self.add_polygon_roi)

        self.createMaskButton.clicked.connect(self.create_mask)
        self.removeSelectionButton.clicked.connect(self.remove_selection)

        self.maskGeneratorContainerLayout.addWidget(self.addRoiButton, 1, 0)
        self.maskGeneratorContainerLayout.addWidget(self.createMaskButton, 2,
                                                    0)
        self.maskGeneratorContainerLayout.addWidget(self.removeSelectionButton,
                                                    1, 1)
        self.selectionOptionsContainer = roundQGroupBox()
        self.selectionOptionsContainer.setTitle('Options')
        self.selectionOptionsLayout = QGridLayout()
        self.fillContourButton = QCheckBox()
        self.invertMaskButton = QCheckBox()
        self.thicknessSpinBox = QSpinBox()
        self.thicknessSpinBox.setRange(1, 25)
        self.selectionOptionsLayout.addWidget(QLabel('Fill contour:'), 0, 0)
        self.selectionOptionsLayout.addWidget(self.fillContourButton, 0, 1)
        self.selectionOptionsLayout.addWidget(QLabel('Invert mask:'), 1, 0)
        self.selectionOptionsLayout.addWidget(self.invertMaskButton, 1, 1)
        self.selectionOptionsLayout.addWidget(QLabel('Thickness:'), 2, 0)
        self.selectionOptionsLayout.addWidget(self.thicknessSpinBox, 2, 1)
        self.selectionOptionsContainer.setLayout(self.selectionOptionsLayout)

        self.snapFovButton = QPushButton('Image FOV')
        self.snapFovButton.clicked.connect(self.snap_fov)

        self.maskGeneratorContainerLayout.addWidget(self.snapFovButton, 0, 0,
                                                    1, 1)
        self.maskGeneratorContainerLayout.addWidget(
            self.loadMaskFromFileButton, 0, 1, 1, 1)
        self.maskGeneratorContainerLayout.addWidget(
            self.selectionOptionsContainer, 2, 1, 2, 1)

        self.layout.addWidget(self.maskGeneratorContainer, 0, 1)

        self.DMDWidget = DMDWidget.DMDWidget()
        self.layout.addWidget(self.DMDWidget, 1, 1)

        self.DMDWidget.sig_request_mask_coordinates.connect(
            lambda: self.cast_mask_coordinates('dmd'))
        self.sig_cast_mask_coordinates_to_dmd.connect(
            self.DMDWidget.receive_mask_coordinates)
        self.DMDWidget.sig_start_registration.connect(
            lambda: self.sig_start_registration.emit())
        self.DMDWidget.sig_finished_registration.connect(
            lambda: self.sig_finished_registration.emit())

        self.GalvoWidget = GalvoWidget.GalvoWidget()
        self.layout.addWidget(self.GalvoWidget, 2, 1)

        self.GalvoWidget.sig_request_mask_coordinates.connect(
            lambda: self.cast_mask_coordinates('galvo'))
        self.sig_cast_mask_coordinates_to_galvo.connect(
            self.GalvoWidget.receive_mask_coordinates)
        self.GalvoWidget.sig_start_registration.connect(
            lambda: self.sig_start_registration.emit())
        self.GalvoWidget.sig_finished_registration.connect(
            lambda: self.sig_finished_registration.emit())

        self.ManualRegistrationWidget = ManualRegistration.ManualRegistrationWidget(
            self)
        self.ManualRegistrationWidget.sig_request_camera_image.connect(
            self.cast_camera_image)
        self.sig_cast_camera_image.connect(
            self.ManualRegistrationWidget.receive_camera_image)

        self.layout.addWidget(self.ManualRegistrationWidget, 3, 1)

        self.StageRegistrationWidget = StageRegistrationWidget.StageWidget(
            self)
        self.layout.addWidget(self.StageRegistrationWidget, 4, 1)
コード例 #3
0
class CoordinatesWidgetUI(QWidget):

    sig_cast_mask_coordinates_to_dmd = pyqtSignal(list)
    sig_cast_mask_coordinates_to_galvo = pyqtSignal(list)
    sig_start_registration = pyqtSignal()
    sig_finished_registration = pyqtSignal()
    sig_cast_camera_image = pyqtSignal(np.ndarray)

    def __init__(self, parent=None, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.main_application = parent
        self.init_gui()

    def closeEvent(self, event):
        try:
            self.DMD
        except:
            pass
        else:
            self.DMD.disconnect_DMD()

        QtWidgets.QApplication.quit()
        event.accept()

    def init_gui(self):
        self.setWindowTitle("Coordinate control")

        self.layout = QGridLayout()
        self.setMinimumSize(1250, 1000)
        self.setLayout(self.layout)

        self.image_mask_stack = QTabWidget()

        self.selection_view = DrawingWidget(self)
        self.selection_view.enable_drawing(True)
        self.selection_view.getView().setLimits(xMin=0,
                                                xMax=2048,
                                                yMin=0,
                                                yMax=2048,
                                                minXRange=2048,
                                                minYRange=2048,
                                                maxXRange=2048,
                                                maxYRange=2048)
        self.selection_view.ui.roiBtn.hide()
        self.selection_view.ui.menuBtn.hide()
        self.selection_view.ui.normGroup.hide()
        self.selection_view.ui.roiPlot.hide()
        # self.selection_view.setImage(plt.imread('CoordinatesManager/Registration_Images/StageRegistration/Distance200_Offset0/A1.png'))

        self.mask_view = SquareImageView()
        self.mask_view.getView().setLimits(xMin=0,
                                           xMax=2048,
                                           yMin=0,
                                           yMax=2048,
                                           minXRange=2048,
                                           minYRange=2048,
                                           maxXRange=2048,
                                           maxYRange=2048)
        self.mask_view.ui.roiBtn.hide()
        self.mask_view.ui.menuBtn.hide()
        self.mask_view.ui.normGroup.hide()
        self.mask_view.ui.roiPlot.hide()
        self.mask_view.ui.histogram.hide()

        self.image_mask_stack.addTab(self.selection_view, 'Select')
        self.image_mask_stack.addTab(self.mask_view, 'Mask')

        self.layout.addWidget(self.image_mask_stack, 0, 0, 5, 1)

        # ---------------------- Mask generation Container  --------------

        self.maskGeneratorContainer = roundQGroupBox()
        self.maskGeneratorContainer.setFixedSize(320, 220)
        self.maskGeneratorContainer.setTitle("Mask generator")
        self.maskGeneratorContainerLayout = QGridLayout()

        self.maskGeneratorLayout = QGridLayout()
        self.maskGeneratorContainer.setLayout(
            self.maskGeneratorContainerLayout)

        self.loadMaskFromFileButton = QPushButton('Open mask')
        self.loadMaskFromFileButton.clicked.connect(self.load_mask_from_file)

        self.addRoiButton = QPushButton("Add ROI")
        self.createMaskButton = QPushButton("Create mask")
        self.removeSelectionButton = QPushButton("Remove ROIs")
        self.addRoiButton.clicked.connect(self.add_polygon_roi)

        self.createMaskButton.clicked.connect(self.create_mask)
        self.removeSelectionButton.clicked.connect(self.remove_selection)

        self.maskGeneratorContainerLayout.addWidget(self.addRoiButton, 1, 0)
        self.maskGeneratorContainerLayout.addWidget(self.createMaskButton, 2,
                                                    0)
        self.maskGeneratorContainerLayout.addWidget(self.removeSelectionButton,
                                                    1, 1)
        self.selectionOptionsContainer = roundQGroupBox()
        self.selectionOptionsContainer.setTitle('Options')
        self.selectionOptionsLayout = QGridLayout()
        self.fillContourButton = QCheckBox()
        self.invertMaskButton = QCheckBox()
        self.thicknessSpinBox = QSpinBox()
        self.thicknessSpinBox.setRange(1, 25)
        self.selectionOptionsLayout.addWidget(QLabel('Fill contour:'), 0, 0)
        self.selectionOptionsLayout.addWidget(self.fillContourButton, 0, 1)
        self.selectionOptionsLayout.addWidget(QLabel('Invert mask:'), 1, 0)
        self.selectionOptionsLayout.addWidget(self.invertMaskButton, 1, 1)
        self.selectionOptionsLayout.addWidget(QLabel('Thickness:'), 2, 0)
        self.selectionOptionsLayout.addWidget(self.thicknessSpinBox, 2, 1)
        self.selectionOptionsContainer.setLayout(self.selectionOptionsLayout)

        self.snapFovButton = QPushButton('Image FOV')
        self.snapFovButton.clicked.connect(self.snap_fov)

        self.maskGeneratorContainerLayout.addWidget(self.snapFovButton, 0, 0,
                                                    1, 1)
        self.maskGeneratorContainerLayout.addWidget(
            self.loadMaskFromFileButton, 0, 1, 1, 1)
        self.maskGeneratorContainerLayout.addWidget(
            self.selectionOptionsContainer, 2, 1, 2, 1)

        self.layout.addWidget(self.maskGeneratorContainer, 0, 1)

        self.DMDWidget = DMDWidget.DMDWidget()
        self.layout.addWidget(self.DMDWidget, 1, 1)

        self.DMDWidget.sig_request_mask_coordinates.connect(
            lambda: self.cast_mask_coordinates('dmd'))
        self.sig_cast_mask_coordinates_to_dmd.connect(
            self.DMDWidget.receive_mask_coordinates)
        self.DMDWidget.sig_start_registration.connect(
            lambda: self.sig_start_registration.emit())
        self.DMDWidget.sig_finished_registration.connect(
            lambda: self.sig_finished_registration.emit())

        self.GalvoWidget = GalvoWidget.GalvoWidget()
        self.layout.addWidget(self.GalvoWidget, 2, 1)

        self.GalvoWidget.sig_request_mask_coordinates.connect(
            lambda: self.cast_mask_coordinates('galvo'))
        self.sig_cast_mask_coordinates_to_galvo.connect(
            self.GalvoWidget.receive_mask_coordinates)
        self.GalvoWidget.sig_start_registration.connect(
            lambda: self.sig_start_registration.emit())
        self.GalvoWidget.sig_finished_registration.connect(
            lambda: self.sig_finished_registration.emit())

        self.ManualRegistrationWidget = ManualRegistration.ManualRegistrationWidget(
            self)
        self.ManualRegistrationWidget.sig_request_camera_image.connect(
            self.cast_camera_image)
        self.sig_cast_camera_image.connect(
            self.ManualRegistrationWidget.receive_camera_image)

        self.layout.addWidget(self.ManualRegistrationWidget, 3, 1)

        self.StageRegistrationWidget = StageRegistrationWidget.StageWidget(
            self)
        self.layout.addWidget(self.StageRegistrationWidget, 4, 1)

    def cast_transformation_to_DMD(self, transformation, laser):
        self.DMDWidget.transform[laser] = transformation
        self.DMDWidget.save_transformation()

    def cast_transformation_to_galvos(self, sig):
        transformation = sig
        self.GalvoWidget.transform = transformation
        self.GalvoWidget.save_transformation()

    def cast_camera_image(self):
        image = self.selection_view.image
        if type(image) == np.ndarray:
            self.sig_cast_camera_image.emit(image)

    def snap_fov(self):
        self.DMDWidget.interupt_projection()

        self.DMDWidget.project_full_white()

        self.cam = CamActuator()
        self.cam.initializeCamera()
        image = self.cam.SnapImage(0.04)
        self.cam.Exit()
        self.selection_view.setImage(image)

    def cast_mask_coordinates(self, receiver):
        list_of_rois = self.get_list_of_rois()

        sig = [
            list_of_rois,
            self.fillContourButton.isChecked(),
            self.thicknessSpinBox.value(),
            self.invertMaskButton.isChecked()
        ]

        if receiver == 'dmd':
            self.sig_cast_mask_coordinates_to_dmd.emit(sig)
        else:
            self.sig_cast_mask_coordinates_to_galvo.emit(sig)

    def get_list_of_rois(self):
        view = self.selection_view
        list_of_rois = []

        for roi in view.roilist:
            roi_handle_positions = roi.getLocalHandlePositions()
            roi_origin = roi.pos()

            for idx, pos in enumerate(roi_handle_positions):
                roi_handle_positions[idx] = pos[1]

            num_vertices = len(roi_handle_positions)
            vertices = np.zeros([num_vertices, 2])

            for idx, vertex in enumerate(roi_handle_positions):
                vertices[idx, :] = np.array(
                    [vertex.x() + roi_origin.x(),
                     vertex.y() + roi_origin.y()])

            list_of_rois.append(vertices)

        return list_of_rois

    def create_mask(self):
        flag_fill_contour = self.fillContourButton.isChecked()
        flag_invert_mode = self.invertMaskButton.isChecked()
        contour_thickness = self.thicknessSpinBox.value()

        list_of_rois = self.get_list_of_rois()

        self.mask = ProcessImage.CreateBinaryMaskFromRoiCoordinates(list_of_rois, \
                                                       fill_contour = flag_fill_contour, \
                                                       contour_thickness = contour_thickness, \
                                                       invert_mask = flag_invert_mode)

        self.mask_view.setImage(self.mask)

    def remove_selection(self):
        self.selection_view.clear_rois()

    def set_camera_image(self, sig):
        self.selection_view.setImage(sig)

    def add_polygon_roi(self):
        view = self.selection_view

        x = (view.getView().viewRect().x()) * 0.3
        y = (view.getView().viewRect().y()) * 0.3
        a = (view.getView().viewRect().width() + x) * 0.3
        b = (view.getView().viewRect().height() + y) * 0.3
        c = (view.getView().viewRect().width() + x) * 0.7
        d = (view.getView().viewRect().height() + y) * 0.7
        polygon_roi = pg.PolyLineROI([[a, b], [c, b], [c, d], [a, d]],
                                     pen=view.pen,
                                     closed=True,
                                     movable=True,
                                     removable=True)

        view.getView().addItem(polygon_roi)
        view.append_to_roilist(polygon_roi)

    def load_mask_from_file(self):
        """
        Open a file manager to browse through files, load image file
        """
        self.loadFileName, _ = QtWidgets.QFileDialog.getOpenFileName(
            self, 'Select file', './CoordinateManager/Images/',
            "(*.png, *.tiff, *.jpg)")
        try:
            image = plt.imread(self.loadFileName)

            self.mask = image
            self.mask_view.setImage(self.mask)
        except:
            print('fail to load file.')
コード例 #4
0
class CoordinatesWidgetUI(QWidget):

    sig_cast_mask_coordinates_to_dmd = pyqtSignal(dict)
    sig_cast_mask_coordinates_to_galvo = pyqtSignal(list)
    sig_start_registration = pyqtSignal()
    sig_finished_registration = pyqtSignal()
    sig_cast_camera_image = pyqtSignal(np.ndarray)

    MessageBack = pyqtSignal(str)

    def __init__(self, parent=None, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.main_application = parent
        self.init_gui()
        self.sig_to_calling_widget = {}
        self.untransformed_mask_dict = {}
        # HamamatsuUI.CameraUI.signal_SnapImg.connect(self.receive_image_from_camera)

    def closeEvent(self, event):
        try:
            self.DMD
        except:
            pass
        else:
            self.DMD.disconnect_DMD()

        QtWidgets.QApplication.quit()
        event.accept()

    #%%
    def init_gui(self):
        self.setWindowTitle("Coordinate control")

        self.layout = QGridLayout()
        self.setMinimumSize(1250, 1000)
        self.setLayout(self.layout)

        self.image_mask_stack = QTabWidget()

        #---------------------------ROIs win----------------------------------
        self.selection_view = DrawingWidget(self)
        self.selection_view.setMinimumWidth(900)
        self.selection_view.enable_drawing(True)
        # self.selection_view.getView().setLimits(xMin = 0, xMax = 2048, yMin = 0, yMax = 2048, \
        #                                         minXRange = 2048, minYRange = 2048, maxXRange = 2048, maxYRange = 2048)
        self.selection_view.ui.roiBtn.hide()
        self.selection_view.ui.menuBtn.hide()
        self.selection_view.ui.normGroup.hide()
        self.selection_view.ui.roiPlot.hide()
        # self.selection_view.setImage(plt.imread('CoordinatesManager/Registration_Images/StageRegistration/Distance200_Offset0/A1.png'))

        #---------------------------Mask win----------------------------------
        self.mask_view = SquareImageView()
        self.mask_view.getView().setLimits(xMin = 0, xMax = 2048, yMin = 0, yMax = 2048, \
                                           minXRange = 2048, minYRange = 2048, maxXRange = 2048, maxYRange = 2048)
        self.mask_view.ui.roiBtn.hide()
        self.mask_view.ui.menuBtn.hide()
        self.mask_view.ui.normGroup.hide()
        self.mask_view.ui.roiPlot.hide()
        self.mask_view.ui.histogram.hide()

        #-------------------------MAsk RCNN-----------------------------------
        MLmaskviewBox = QWidget()
        MLmaskviewBoxLayout = QGridLayout()

        self.Matdisplay_Figure = Figure()
        self.Matdisplay_Canvas = FigureCanvas(self.Matdisplay_Figure)
        # self.Matdisplay_Canvas.setFixedWidth(900)
        # self.Matdisplay_Canvas.setFixedHeight(900)
        self.Matdisplay_Canvas.mpl_connect('button_press_event', self._onclick)

        self.Matdisplay_toolbar = NavigationToolbar(self.Matdisplay_Canvas,
                                                    self)

        MLmaskviewBoxLayout.addWidget(self.Matdisplay_toolbar, 0, 0)
        MLmaskviewBoxLayout.addWidget(self.Matdisplay_Canvas, 1, 0)

        MLmaskviewBox.setLayout(MLmaskviewBoxLayout)

        self.image_mask_stack.addTab(self.selection_view, 'Select')
        self.image_mask_stack.addTab(self.mask_view, 'Mask')
        self.image_mask_stack.addTab(MLmaskviewBox, 'Mask-RCNN')

        self.layout.addWidget(self.image_mask_stack, 0, 0, 4, 7)

        # ---------------------- Mask generation Container  --------------

        self.maskGeneratorContainer = roundQGroupBox()
        self.maskGeneratorContainer.setFixedSize(320, 220)
        self.maskGeneratorContainer.setTitle("Mask generator")
        self.maskGeneratorContainerLayout = QGridLayout()

        self.maskGeneratorLayout = QGridLayout()
        self.maskGeneratorContainer.setLayout(
            self.maskGeneratorContainerLayout)

        # self.loadMaskFromFileButton = QPushButton('Load mask')
        # self.loadMaskFromFileButton.clicked.connect(self.load_mask_from_file)

        self.addRoiButton = QPushButton("Add ROI")
        self.createMaskButton = QPushButton("Add mask")
        self.deleteMaskButton = QPushButton("Delete mask")
        self.removeSelectionButton = cleanButton()
        self.removeSelectionButton.setFixedHeight(25)
        self.removeSelectionButton.setToolTip("Remove rois and output signals")
        self.addRoiButton.clicked.connect(self.add_polygon_roi)

        self.createMaskButton.clicked.connect(self.create_mask)
        self.deleteMaskButton.clicked.connect(self.delete_mask)
        self.removeSelectionButton.clicked.connect(self.remove_selection)

        self.maskGeneratorContainerLayout.addWidget(self.addRoiButton, 0, 0)
        self.maskGeneratorContainerLayout.addWidget(self.createMaskButton, 2,
                                                    0)
        self.maskGeneratorContainerLayout.addWidget(self.deleteMaskButton, 2,
                                                    2)
        self.maskGeneratorContainerLayout.addWidget(self.removeSelectionButton,
                                                    2, 3)
        # self.maskGeneratorContainerLayout.addWidget(self.loadMaskFromFileButton, 2, 1)

        self.clearRoiButton = QPushButton("Clear ROI")
        self.clearRoiButton.clicked.connect(
            lambda: self.selection_view.clear_rois())
        self.maskGeneratorContainerLayout.addWidget(self.clearRoiButton, 0, 1)

        self.maskGeneratorContainerLayout.addWidget(QLabel("Mask index:"), 1,
                                                    0)
        self.mask_index_spinbox = QSpinBox()
        self.mask_index_spinbox.setMinimum(1)
        self.mask_index_spinbox.setValue(1)
        self.maskGeneratorContainerLayout.addWidget(self.mask_index_spinbox, 1,
                                                    1)

        self.previous_mask_button = QPushButton()
        self.previous_mask_button.setStyleSheet(
            "QPushButton {color:white;background-color: #FFCCE5;}"
            "QPushButton:hover:!pressed {color:white;background-color: #CCFFFF;}"
        )
        self.previous_mask_button.setToolTip(
            "Click arrow to enable WASD keyboard control")
        self.previous_mask_button.setFixedWidth(60)
        self.previous_mask_button.setIcon(QIcon('./Icons/LeftArrow.png'))
        self.previous_mask_button.clicked.connect(
            lambda: self.show_mask_with_index(-1))
        self.maskGeneratorContainerLayout.addWidget(self.previous_mask_button,
                                                    1, 2)

        self.next_mask_button = QPushButton()
        self.next_mask_button.setStyleSheet(
            "QPushButton {color:white;background-color: #FFCCE5;}"
            "QPushButton:hover:!pressed {color:white;background-color: #CCFFFF;}"
        )
        self.next_mask_button.setToolTip(
            "Click arrow to enable WASD keyboard control")
        self.next_mask_button.setFixedWidth(60)
        self.next_mask_button.setIcon(QIcon('./Icons/RightArrow.png'))
        self.next_mask_button.clicked.connect(
            lambda: self.show_mask_with_index(1))
        self.maskGeneratorContainerLayout.addWidget(self.next_mask_button, 1,
                                                    3)

        self.selectionOptionsContainer = roundQGroupBox()
        self.selectionOptionsContainer.setTitle('Options')
        self.selectionOptionsLayout = QGridLayout()
        self.fillContourButton = QCheckBox()
        self.invertMaskButton = QCheckBox()
        self.thicknessSpinBox = QSpinBox()
        self.thicknessSpinBox.setRange(1, 25)
        self.selectionOptionsLayout.addWidget(QLabel('Fill contour:'), 0, 0)
        self.selectionOptionsLayout.addWidget(self.fillContourButton, 0, 1)
        self.selectionOptionsLayout.addWidget(QLabel('Invert mask:'), 1, 0)
        self.selectionOptionsLayout.addWidget(self.invertMaskButton, 1, 1)
        self.selectionOptionsLayout.addWidget(QLabel('Thickness:'), 2, 0)
        self.selectionOptionsLayout.addWidget(self.thicknessSpinBox, 2, 1)

        lasers = ['640', '532', '488']
        self.transform_for_laser_menu = QListWidget()
        self.transform_for_laser_menu.addItems(lasers)
        self.transform_for_laser_menu.setFixedHeight(48)
        self.transform_for_laser_menu.setFixedWidth(65)
        self.transform_for_laser_menu.setCurrentRow(0)

        self.selectionOptionsLayout.addWidget(QLabel('To be used with laser:'),
                                              0, 2)
        self.selectionOptionsLayout.addWidget(self.transform_for_laser_menu, 1,
                                              2)

        self.selectionOptionsContainer.setLayout(self.selectionOptionsLayout)

        self.maskGeneratorContainerLayout.addWidget(
            self.selectionOptionsContainer, 3, 0, 2, 3)

        #----------------------------Mask-RCNN--------------------------------
        self.MLOptionsContainer = roundQGroupBox()
        self.MLOptionsContainer.setTitle('Mask-RCNN')
        self.MLOptionsContainerLayout = QGridLayout()

        self.init_ML_button = QPushButton('Init. ML', self)
        self.MLOptionsContainerLayout.addWidget(self.init_ML_button, 0, 0)
        self.init_ML_button.clicked.connect(
            lambda: self.run_in_thread(self.init_ML))

        self.run_ML_button = QPushButton('Analysis', self)
        self.MLOptionsContainerLayout.addWidget(self.run_ML_button, 1, 0)
        self.run_ML_button.clicked.connect(self.run_ML_onImg_and_display)

        self.generate_MLmask_button = QPushButton('To ROIs', self)
        self.MLOptionsContainerLayout.addWidget(self.generate_MLmask_button, 2,
                                                0)
        self.generate_MLmask_button.clicked.connect(
            lambda: self.run_in_thread(self.generate_MLmask))

        self.MLOptionsContainer.setLayout(self.MLOptionsContainerLayout)

        self.maskGeneratorContainerLayout.addWidget(self.MLOptionsContainer, 3,
                                                    3, 2, 1)

        self.layout.addWidget(self.maskGeneratorContainer, 0, 8, 1, 3)

        self.DMDWidget = DMDWidget.DMDWidget()
        self.layout.addWidget(self.DMDWidget, 1, 8, 1, 3)
        """--------------------------------------------------------------------
        # Singal sent out from DMDWidget to ask for mask generated here.
        # And then the generated roi list is sent back to function:receive_mask_coordinates in DMDWidget.
        #  --------------------------------------------------------------------
        """
        self.DMDWidget.sig_request_mask_coordinates.connect(
            lambda: self.cast_mask_coordinates('dmd'))
        self.sig_cast_mask_coordinates_to_dmd.connect(
            self.DMDWidget.receive_mask_coordinates)

        self.DMDWidget.sig_start_registration.connect(
            lambda: self.sig_start_registration.emit())
        self.DMDWidget.sig_finished_registration.connect(
            lambda: self.sig_finished_registration.emit())

        #---------------------------Galvo control-----------------------------
        self.GalvoWidget = GalvoWidget.GalvoWidget()
        self.GalvoWidget.setFixedWidth(200)
        self.GalvoWidget.setFixedHeight(180)
        self.layout.addWidget(self.GalvoWidget, 2, 8, 2, 1)

        self.GalvoWidget.sig_request_mask_coordinates.connect(
            lambda: self.cast_mask_coordinates('galvo'))
        self.sig_cast_mask_coordinates_to_galvo.connect(
            self.GalvoWidget.receive_mask_coordinates)
        self.GalvoWidget.sig_start_registration.connect(
            lambda: self.sig_start_registration.emit())
        self.GalvoWidget.sig_finished_registration.connect(
            lambda: self.sig_finished_registration.emit())

        #-------------------------Manual registration-------------------------
        self.ManualRegistrationWidget = ManualRegistration.ManualRegistrationWidget(
        )
        self.ManualRegistrationWidget.setFixedWidth(100)
        self.ManualRegistrationWidget.sig_request_camera_image.connect(
            self.cast_camera_image)
        self.sig_cast_camera_image.connect(
            self.ManualRegistrationWidget.receive_camera_image)

        self.layout.addWidget(self.ManualRegistrationWidget, 2, 9, 1, 1)

        #-------------------------Stage collect-------------------------------
        self.StageRegistrationWidget = StageRegistrationWidget.StageWidget()
        self.StageRegistrationWidget.setFixedWidth(100)
        self.layout.addWidget(self.StageRegistrationWidget, 3, 9, 1, 1)

        #=====================================================================

    #%%

    def cast_transformation_to_DMD(self, transformation, laser):
        self.DMDWidget.transform[laser] = transformation
        self.DMDWidget.save_transformation()

    def cast_transformation_to_galvos(self, transformation):
        self.GalvoWidget.transform = transformation
        self.GalvoWidget.save_transformation()

    def cast_camera_image(self):
        """ Send out the image in the image view to ManualRegistration """
        image = self.selection_view.image
        if type(image) == np.ndarray:
            self.sig_cast_camera_image.emit(image)

    def receive_image_from_camera(self, snap_from_camera):
        """ Receive the emitted snap image singal from camera. """
        self.selection_view.setImage(snap_from_camera)

    def cast_mask_coordinates(self, receiver):
        """
        Upon receiving mask rois request signal from DMD or galvo widget, generate list signal including
        list of rois from the current ROIitems in "Select" Drawwidget and send it back to the calling widget.
        
        Parameters
        ----------
        receiver : string.
            Specifies which widget is requesting.
                   
        """
        if receiver == 'dmd':
            self.sig_cast_mask_coordinates_to_dmd.emit(
                self.sig_to_calling_widget)
        else:
            self.sig_cast_mask_coordinates_to_galvo.emit(
                self.sig_to_calling_widget)

    def get_list_of_rois(self):
        """
        Return the list of rois from the current ROIitems in "Select" Drawwidget.
        """
        view = self.selection_view
        list_of_rois = []

        for roi in view.roilist:

            roi_handle_positions = roi.getLocalHandlePositions()
            roi_origin = roi.pos()

            for idx, pos in enumerate(roi_handle_positions):
                roi_handle_positions[idx] = pos[1]

            num_vertices = len(roi_handle_positions)
            vertices = np.zeros([num_vertices, 2])

            for idx, vertex in enumerate(roi_handle_positions):
                vertices[idx, :] = np.array(
                    [vertex.x() + roi_origin.x(),
                     vertex.y() + roi_origin.y()])

            list_of_rois.append(vertices)

        return list_of_rois

    def create_mask(self):
        """
        Create untransformed binary mask, sent out the signal to DMD widget for
        further transformation.

        Returns
        -------
        None.

        """
        flag_fill_contour = self.fillContourButton.isChecked()
        flag_invert_mode = self.invertMaskButton.isChecked()
        contour_thickness = self.thicknessSpinBox.value()
        target_laser = self.transform_for_laser_menu.selectedItems()[0].text()

        # Get the list of rois from the current ROIitems in "Select" Drawwidget.
        list_of_rois = self.get_list_of_rois()

        # Signal to mask requesting widget.
        current_mask_sig = [
            list_of_rois, flag_fill_contour, contour_thickness,
            flag_invert_mode, target_laser
        ]

        #---- This is the roi list sent to DMD to generate final stack of masks.----
        self.sig_to_calling_widget["mask_{}".format(
            self.mask_index_spinbox.value())] = current_mask_sig

        # Show the untransformed mask
        self.current_mask = ProcessImage.CreateBinaryMaskFromRoiCoordinates(list_of_rois, \
                                                       fill_contour = flag_fill_contour, \
                                                       contour_thickness = contour_thickness, \
                                                       invert_mask = flag_invert_mode)
        self.untransformed_mask_dict["mask_{}".format(
            self.mask_index_spinbox.value())] = self.current_mask

        self.mask_view.setImage(self.current_mask)

    def show_mask_with_index(self, direction):
        """
        If direction == 1, then show next mask, elif direction == -1, show previous one.

        Parameters
        ----------
        direction : TYPE
            -1: Previous; 1: Next.

        Returns
        -------
        None.

        """
        try:
            self.mask_index_spinbox.setValue(self.mask_index_spinbox.value() +
                                             direction)
            self.mask_view.setImage(
                self.untransformed_mask_dict["mask_{}".format(
                    self.mask_index_spinbox.value())])
        except:
            print("show_mask failed.")

    def delete_mask(self):
        """
        Remove the last mask from the list.
        """
        del self.sig_to_calling_widget["mask_{}".format(
            self.mask_index_spinbox.value())]
        del self.untransformed_mask_dict["mask_{}".format(
            self.mask_index_spinbox.value())]

    def remove_selection(self):
        self.sig_to_calling_widget = {}
        self.selection_view.clear_rois()

    def add_polygon_roi(self):
        view = self.selection_view

        x = (view.getView().viewRect().x()) * 0.3
        y = (view.getView().viewRect().y()) * 0.3
        a = (view.getView().viewRect().width() + x) * 0.3
        b = (view.getView().viewRect().height() + y) * 0.3
        c = (view.getView().viewRect().width() + x) * 0.7
        d = (view.getView().viewRect().height() + y) * 0.7
        polygon_roi = pg.PolyLineROI([[a, b], [c, b], [c, d], [a, d]],
                                     pen=view.pen,
                                     closed=True,
                                     movable=True,
                                     removable=True)

        view.getView().addItem(polygon_roi)
        view.append_to_roilist(polygon_roi)

    def load_mask_from_file(self):
        """
        Open a file manager to browse through files, load image file
        """
        self.loadFileName, _ = QtWidgets.QFileDialog.getOpenFileName(
            self, 'Select file', './CoordinateManager/Images/',
            "Image files (*.jpg *.tif *.png)")
        try:
            image = plt.imread(self.loadFileName)

            self.current_mask = image
            self.mask_view.setImage(self.current_mask)
            self.untransformed_mask_dict["mask_{}".format(
                self.mask_index_spinbox.value())] = self.current_mask

        except:
            print('fail to load file.')

    # =============================================================================
    #     MaskRCNN detection part
    # =============================================================================

    def init_ML(self):
        # Initialize the detector instance and load the model.
        self.ProcessML = ProcessImageML()
        self.MessageBack.emit("Mask-RCNN environment configured.")

    def run_ML_onImg_and_display(self):
        # self.ResetLiveImgView()
        # For testing
        # snap_from_camera = plt.imread\
        # (r"M:\tnw\ist\do\projects\Neurophotonics\Brinkslab\Data\Vidya\Imaging\Octoscope\2020-10-08 Archon lib V7\V7_gfp_5v_telescope_2.TIF")
        # self.selection_view.setImage(snap_from_camera)
        """Run MaskRCNN on input image"""
        self.Matdisplay_Figure.clear()
        self.Matdisplay_Figure_axis = self.Matdisplay_Figure.add_subplot(111)

        self.MLtargetedImg = self.selection_view.image
        print(self.MLtargetedImg.shape)

        # Depends on show_mask or not, the returned figure will be input raw image with mask or not.
        self.MLresults = self.ProcessML.DetectionOnImage(
            self.MLtargetedImg,
            axis=self.Matdisplay_Figure_axis,
            show_mask=False,
            show_bbox=False)
        self.Mask = self.MLresults['masks']
        self.Label = self.MLresults['class_ids']
        self.Score = self.MLresults['scores']
        self.Bbox = self.MLresults['rois']

        self.SelectedCellIndex = 0
        self.NumCells = int(len(self.Label))
        self.selected_ML_Index = []
        self.selected_cells_infor_dict = {}

        self.Matdisplay_Figure_axis.imshow(self.MLtargetedImg.astype(np.uint8))

        self.Matdisplay_Figure.tight_layout()
        self.Matdisplay_Canvas.draw()

    #%%
    # =============================================================================
    #     Configure click event to add clicked cell mask
    # =============================================================================

    def _onclick(self, event):
        """Highlights the cell selected in the figure by the user when clicked on"""
        if self.NumCells > 0:
            ShapeMask = np.shape(self.Mask)
            # get coorinates at selected location in image coordinates
            if event.xdata == None or event.ydata == None:
                return
            xcoor = min(max(int(event.xdata), 0), ShapeMask[1])
            ycoor = min(max(int(event.ydata), 0), ShapeMask[0])

            # search for the mask coresponding to the selected cell
            for EachCell in range(self.NumCells):
                if self.Mask[ycoor, xcoor, EachCell]:
                    self.SelectedCellIndex = EachCell
                    break

            # highlight selected cell
            if self.SelectedCellIndex not in self.selected_ML_Index:
                # Get the selected cell's contour coordinates and mask patch
                self.contour_verts, self.Cell_patch = self.get_cell_polygon(
                    self.Mask[:, :, self.SelectedCellIndex])

                self.Matdisplay_Figure_axis.add_patch(self.Cell_patch)
                self.Matdisplay_Canvas.draw()

                self.selected_ML_Index.append(self.SelectedCellIndex)
                self.selected_cells_infor_dict['cell{}_verts'.format(
                    str(self.SelectedCellIndex))] = self.contour_verts
            else:
                # If click on the same cell
                self.Cell_patch.remove()
                self.Matdisplay_Canvas.draw()
                self.selected_ML_Index.remove(self.SelectedCellIndex)
                self.selected_cells_infor_dict.pop('cell{}_verts'.format(
                    str(self.SelectedCellIndex)))

    def get_cell_polygon(self, mask):
        # Mask Polygon
        # Pad to ensure proper polygons for masks that touch image edges.
        padded_mask = np.zeros((mask.shape[0] + 2, mask.shape[1] + 2),
                               dtype=np.uint8)
        padded_mask[1:-1, 1:-1] = mask
        contours = find_contours(padded_mask, 0.5)
        for verts in contours:
            # Subtract the padding and flip (y, x) to (x, y)
            verts = np.fliplr(verts) - 1
            contour_polygon = mpatches.Polygon(
                verts, facecolor=self.random_colors(1)[0])

        return contours, contour_polygon

    def random_colors(self, N, bright=True):
        """
        Generate random colors.
        To get visually distinct colors, generate them in HSV space then
        convert to RGB.
        """
        brightness = 1.0 if bright else 0.7
        hsv = [(i / N, 1, brightness) for i in range(N)]
        colors = list(map(lambda c: colorsys.hsv_to_rgb(*c), hsv))
        random.shuffle(colors)
        return colors

    #%%
    # =============================================================================
    #     For mask generation
    # =============================================================================

    def generate_MLmask(self):
        """ Generate binary mask with all selected cells"""
        self.MLmask = np.zeros(
            (self.MLtargetedImg.shape[0], self.MLtargetedImg.shape[1]))

        if len(self.selected_ML_Index) > 0:
            for selected_index in self.selected_ML_Index:
                self.MLmask = np.add(self.MLmask, self.Mask[:, :,
                                                            selected_index])

            self.add_rois_of_selected()

    def add_rois_of_selected(self):
        """
        Generate ROI items from ML selected mask.
        Using find_contours to get list of contour coordinates in the binary mask, and then generate polygon rois based on these coordinates.
        """
        handle_downsample_step = 2

        for selected_index in self.selected_ML_Index:

            contours = self.selected_cells_infor_dict['cell{}_verts'.format(
                str(selected_index))]
            #            contours = find_contours(self.Mask[:,:,selected_index], 0.5) # Find iso-valued contours in a 2D array for a given level value.

            for n, contour in enumerate(contours):
                contour_coord_array = contours[n]
                #Swap columns
                contour_coord_array[:,
                                    0], contour_coord_array[:,
                                                            1] = contour_coord_array[:,
                                                                                     1], contour_coord_array[:, 0].copy(
                                                                                     )

                #Down sample the coordinates otherwise it will be too dense.
                contour_coord_array_del = np.delete(
                    contour_coord_array,
                    np.arange(2, contour_coord_array.shape[0] - 3,
                              handle_downsample_step), 0)
                for _ in range(3):
                    contour_coord_array_del = np.delete(
                        contour_coord_array_del,
                        np.arange(2, contour_coord_array_del.shape[0] - 3,
                                  handle_downsample_step), 0)

                self.selected_cells_infor_dict['cell{}_ROIitem'.format(str(selected_index))] = \
                pg.PolyLineROI(positions=contour_coord_array_del, closed=True)

                # Add ROI item, and append_to_roilist
                self.selection_view.getView().addItem(
                    self.selected_cells_infor_dict['cell{}_ROIitem'.format(
                        str(selected_index))])
                self.selection_view.append_to_roilist(
                    self.selected_cells_infor_dict['cell{}_ROIitem'.format(
                        str(selected_index))])

    def run_in_thread(self, fn, *args, **kwargs):
        """
        Send target function to thread.
        Usage: lambda: self.run_in_thread(self.fn)
        
        Parameters
        ----------
        fn : function
            Target function to put in thread.

        Returns
        -------
        thread : TYPE
            Threading handle.

        """
        thread = threading.Thread(target=fn, args=args, kwargs=kwargs)
        thread.start()

        return thread

    def ResetLiveImgView(self):
        """Closes the widget nicely, making sure to clear the graphics scene and release memory."""
        self.selection_view.close()

        # Replot the imageview
        self.selection_view = DrawingWidget(self)
        self.selection_view.enable_drawing(True)
        self.selection_view.getView().setLimits(xMin = 0, xMax = 2048, yMin = 0, yMax = 2048, minXRange = 2048, \
                                                minYRange = 2048, maxXRange = 2048, maxYRange = 2048)
        self.selection_view.ui.roiBtn.hide()
        self.selection_view.ui.menuBtn.hide()
        self.selection_view.ui.normGroup.hide()
        self.selection_view.ui.roiPlot.hide()

        self.image_mask_stack.addTab(self.selection_view, 'Select')
コード例 #5
0
    def init_gui(self):
        self.setWindowTitle("Coordinate control")

        self.layout = QGridLayout()
        self.setMinimumSize(1250, 1000)
        self.setLayout(self.layout)

        self.image_mask_stack = QTabWidget()

        #---------------------------ROIs win----------------------------------
        self.selection_view = DrawingWidget(self)
        self.selection_view.setMinimumWidth(900)
        self.selection_view.enable_drawing(True)
        # self.selection_view.getView().setLimits(xMin = 0, xMax = 2048, yMin = 0, yMax = 2048, \
        #                                         minXRange = 2048, minYRange = 2048, maxXRange = 2048, maxYRange = 2048)
        self.selection_view.ui.roiBtn.hide()
        self.selection_view.ui.menuBtn.hide()
        self.selection_view.ui.normGroup.hide()
        self.selection_view.ui.roiPlot.hide()
        # self.selection_view.setImage(plt.imread('CoordinatesManager/Registration_Images/StageRegistration/Distance200_Offset0/A1.png'))

        #---------------------------Mask win----------------------------------
        self.mask_view = SquareImageView()
        self.mask_view.getView().setLimits(xMin = 0, xMax = 2048, yMin = 0, yMax = 2048, \
                                           minXRange = 2048, minYRange = 2048, maxXRange = 2048, maxYRange = 2048)
        self.mask_view.ui.roiBtn.hide()
        self.mask_view.ui.menuBtn.hide()
        self.mask_view.ui.normGroup.hide()
        self.mask_view.ui.roiPlot.hide()
        self.mask_view.ui.histogram.hide()

        #-------------------------MAsk RCNN-----------------------------------
        MLmaskviewBox = QWidget()
        MLmaskviewBoxLayout = QGridLayout()

        self.Matdisplay_Figure = Figure()
        self.Matdisplay_Canvas = FigureCanvas(self.Matdisplay_Figure)
        # self.Matdisplay_Canvas.setFixedWidth(900)
        # self.Matdisplay_Canvas.setFixedHeight(900)
        self.Matdisplay_Canvas.mpl_connect('button_press_event', self._onclick)

        self.Matdisplay_toolbar = NavigationToolbar(self.Matdisplay_Canvas,
                                                    self)

        MLmaskviewBoxLayout.addWidget(self.Matdisplay_toolbar, 0, 0)
        MLmaskviewBoxLayout.addWidget(self.Matdisplay_Canvas, 1, 0)

        MLmaskviewBox.setLayout(MLmaskviewBoxLayout)

        self.image_mask_stack.addTab(self.selection_view, 'Select')
        self.image_mask_stack.addTab(self.mask_view, 'Mask')
        self.image_mask_stack.addTab(MLmaskviewBox, 'Mask-RCNN')

        self.layout.addWidget(self.image_mask_stack, 0, 0, 4, 7)

        # ---------------------- Mask generation Container  --------------

        self.maskGeneratorContainer = roundQGroupBox()
        self.maskGeneratorContainer.setFixedSize(320, 220)
        self.maskGeneratorContainer.setTitle("Mask generator")
        self.maskGeneratorContainerLayout = QGridLayout()

        self.maskGeneratorLayout = QGridLayout()
        self.maskGeneratorContainer.setLayout(
            self.maskGeneratorContainerLayout)

        # self.loadMaskFromFileButton = QPushButton('Load mask')
        # self.loadMaskFromFileButton.clicked.connect(self.load_mask_from_file)

        self.addRoiButton = QPushButton("Add ROI")
        self.createMaskButton = QPushButton("Add mask")
        self.deleteMaskButton = QPushButton("Delete mask")
        self.removeSelectionButton = cleanButton()
        self.removeSelectionButton.setFixedHeight(25)
        self.removeSelectionButton.setToolTip("Remove rois and output signals")
        self.addRoiButton.clicked.connect(self.add_polygon_roi)

        self.createMaskButton.clicked.connect(self.create_mask)
        self.deleteMaskButton.clicked.connect(self.delete_mask)
        self.removeSelectionButton.clicked.connect(self.remove_selection)

        self.maskGeneratorContainerLayout.addWidget(self.addRoiButton, 0, 0)
        self.maskGeneratorContainerLayout.addWidget(self.createMaskButton, 2,
                                                    0)
        self.maskGeneratorContainerLayout.addWidget(self.deleteMaskButton, 2,
                                                    2)
        self.maskGeneratorContainerLayout.addWidget(self.removeSelectionButton,
                                                    2, 3)
        # self.maskGeneratorContainerLayout.addWidget(self.loadMaskFromFileButton, 2, 1)

        self.clearRoiButton = QPushButton("Clear ROI")
        self.clearRoiButton.clicked.connect(
            lambda: self.selection_view.clear_rois())
        self.maskGeneratorContainerLayout.addWidget(self.clearRoiButton, 0, 1)

        self.maskGeneratorContainerLayout.addWidget(QLabel("Mask index:"), 1,
                                                    0)
        self.mask_index_spinbox = QSpinBox()
        self.mask_index_spinbox.setMinimum(1)
        self.mask_index_spinbox.setValue(1)
        self.maskGeneratorContainerLayout.addWidget(self.mask_index_spinbox, 1,
                                                    1)

        self.previous_mask_button = QPushButton()
        self.previous_mask_button.setStyleSheet(
            "QPushButton {color:white;background-color: #FFCCE5;}"
            "QPushButton:hover:!pressed {color:white;background-color: #CCFFFF;}"
        )
        self.previous_mask_button.setToolTip(
            "Click arrow to enable WASD keyboard control")
        self.previous_mask_button.setFixedWidth(60)
        self.previous_mask_button.setIcon(QIcon('./Icons/LeftArrow.png'))
        self.previous_mask_button.clicked.connect(
            lambda: self.show_mask_with_index(-1))
        self.maskGeneratorContainerLayout.addWidget(self.previous_mask_button,
                                                    1, 2)

        self.next_mask_button = QPushButton()
        self.next_mask_button.setStyleSheet(
            "QPushButton {color:white;background-color: #FFCCE5;}"
            "QPushButton:hover:!pressed {color:white;background-color: #CCFFFF;}"
        )
        self.next_mask_button.setToolTip(
            "Click arrow to enable WASD keyboard control")
        self.next_mask_button.setFixedWidth(60)
        self.next_mask_button.setIcon(QIcon('./Icons/RightArrow.png'))
        self.next_mask_button.clicked.connect(
            lambda: self.show_mask_with_index(1))
        self.maskGeneratorContainerLayout.addWidget(self.next_mask_button, 1,
                                                    3)

        self.selectionOptionsContainer = roundQGroupBox()
        self.selectionOptionsContainer.setTitle('Options')
        self.selectionOptionsLayout = QGridLayout()
        self.fillContourButton = QCheckBox()
        self.invertMaskButton = QCheckBox()
        self.thicknessSpinBox = QSpinBox()
        self.thicknessSpinBox.setRange(1, 25)
        self.selectionOptionsLayout.addWidget(QLabel('Fill contour:'), 0, 0)
        self.selectionOptionsLayout.addWidget(self.fillContourButton, 0, 1)
        self.selectionOptionsLayout.addWidget(QLabel('Invert mask:'), 1, 0)
        self.selectionOptionsLayout.addWidget(self.invertMaskButton, 1, 1)
        self.selectionOptionsLayout.addWidget(QLabel('Thickness:'), 2, 0)
        self.selectionOptionsLayout.addWidget(self.thicknessSpinBox, 2, 1)

        lasers = ['640', '532', '488']
        self.transform_for_laser_menu = QListWidget()
        self.transform_for_laser_menu.addItems(lasers)
        self.transform_for_laser_menu.setFixedHeight(48)
        self.transform_for_laser_menu.setFixedWidth(65)
        self.transform_for_laser_menu.setCurrentRow(0)

        self.selectionOptionsLayout.addWidget(QLabel('To be used with laser:'),
                                              0, 2)
        self.selectionOptionsLayout.addWidget(self.transform_for_laser_menu, 1,
                                              2)

        self.selectionOptionsContainer.setLayout(self.selectionOptionsLayout)

        self.maskGeneratorContainerLayout.addWidget(
            self.selectionOptionsContainer, 3, 0, 2, 3)

        #----------------------------Mask-RCNN--------------------------------
        self.MLOptionsContainer = roundQGroupBox()
        self.MLOptionsContainer.setTitle('Mask-RCNN')
        self.MLOptionsContainerLayout = QGridLayout()

        self.init_ML_button = QPushButton('Init. ML', self)
        self.MLOptionsContainerLayout.addWidget(self.init_ML_button, 0, 0)
        self.init_ML_button.clicked.connect(
            lambda: self.run_in_thread(self.init_ML))

        self.run_ML_button = QPushButton('Analysis', self)
        self.MLOptionsContainerLayout.addWidget(self.run_ML_button, 1, 0)
        self.run_ML_button.clicked.connect(self.run_ML_onImg_and_display)

        self.generate_MLmask_button = QPushButton('To ROIs', self)
        self.MLOptionsContainerLayout.addWidget(self.generate_MLmask_button, 2,
                                                0)
        self.generate_MLmask_button.clicked.connect(
            lambda: self.run_in_thread(self.generate_MLmask))

        self.MLOptionsContainer.setLayout(self.MLOptionsContainerLayout)

        self.maskGeneratorContainerLayout.addWidget(self.MLOptionsContainer, 3,
                                                    3, 2, 1)

        self.layout.addWidget(self.maskGeneratorContainer, 0, 8, 1, 3)

        self.DMDWidget = DMDWidget.DMDWidget()
        self.layout.addWidget(self.DMDWidget, 1, 8, 1, 3)
        """--------------------------------------------------------------------
        # Singal sent out from DMDWidget to ask for mask generated here.
        # And then the generated roi list is sent back to function:receive_mask_coordinates in DMDWidget.
        #  --------------------------------------------------------------------
        """
        self.DMDWidget.sig_request_mask_coordinates.connect(
            lambda: self.cast_mask_coordinates('dmd'))
        self.sig_cast_mask_coordinates_to_dmd.connect(
            self.DMDWidget.receive_mask_coordinates)

        self.DMDWidget.sig_start_registration.connect(
            lambda: self.sig_start_registration.emit())
        self.DMDWidget.sig_finished_registration.connect(
            lambda: self.sig_finished_registration.emit())

        #---------------------------Galvo control-----------------------------
        self.GalvoWidget = GalvoWidget.GalvoWidget()
        self.GalvoWidget.setFixedWidth(200)
        self.GalvoWidget.setFixedHeight(180)
        self.layout.addWidget(self.GalvoWidget, 2, 8, 2, 1)

        self.GalvoWidget.sig_request_mask_coordinates.connect(
            lambda: self.cast_mask_coordinates('galvo'))
        self.sig_cast_mask_coordinates_to_galvo.connect(
            self.GalvoWidget.receive_mask_coordinates)
        self.GalvoWidget.sig_start_registration.connect(
            lambda: self.sig_start_registration.emit())
        self.GalvoWidget.sig_finished_registration.connect(
            lambda: self.sig_finished_registration.emit())

        #-------------------------Manual registration-------------------------
        self.ManualRegistrationWidget = ManualRegistration.ManualRegistrationWidget(
        )
        self.ManualRegistrationWidget.setFixedWidth(100)
        self.ManualRegistrationWidget.sig_request_camera_image.connect(
            self.cast_camera_image)
        self.sig_cast_camera_image.connect(
            self.ManualRegistrationWidget.receive_camera_image)

        self.layout.addWidget(self.ManualRegistrationWidget, 2, 9, 1, 1)

        #-------------------------Stage collect-------------------------------
        self.StageRegistrationWidget = StageRegistrationWidget.StageWidget()
        self.StageRegistrationWidget.setFixedWidth(100)
        self.layout.addWidget(self.StageRegistrationWidget, 3, 9, 1, 1)
コード例 #6
0
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        os.chdir('./')  # Set directory to current folder.
        self.setFont(QFont("Arial"))

        #        self.setMinimumSize(900, 1020)
        self.setWindowTitle("Cell Selection")
        self.layout = QGridLayout(self)

        self.roi_list_freehandl_added = []
        self.selected_ML_Index = []
        self.selected_cells_infor_dict = {}

        self.mask_color_multiplier = [1, 1, 0]
        # =============================================================================
        #         Container for image display
        # =============================================================================
        graphContainer = StylishQT.roundQGroupBox()
        graphContainerLayout = QGridLayout()

        self.Imgviewtabs = QTabWidget()

        MLmaskviewBox = QWidget()
        MLmaskviewBoxLayout = QGridLayout()

        self.Matdisplay_Figure = Figure()
        self.Matdisplay_Canvas = FigureCanvas(self.Matdisplay_Figure)
        self.Matdisplay_Canvas.setFixedWidth(500)
        self.Matdisplay_Canvas.setFixedHeight(500)
        self.Matdisplay_Canvas.mpl_connect('button_press_event', self._onclick)

        self.Matdisplay_toolbar = NavigationToolbar(self.Matdisplay_Canvas,
                                                    self)

        MLmaskviewBoxLayout.addWidget(self.Matdisplay_toolbar, 0, 0)
        MLmaskviewBoxLayout.addWidget(self.Matdisplay_Canvas, 1, 0)

        MLmaskviewBox.setLayout(MLmaskviewBoxLayout)

        self.Imgviewtabs.addTab(MLmaskviewBox, "MaskRCNN")

        # =============================================================================
        #         Mask editing tab
        # =============================================================================
        MLmaskEditBox = QWidget()
        MLmaskEditBoxLayout = QGridLayout()

        self.Mask_edit_view = DrawingWidget(self)
        self.Mask_edit_view.enable_drawing(False)  # Disable drawing first
        #        self.Mask_edit_view = pg.ImageView()
        #        self.Mask_edit_view.getView().setLimits(xMin = 0, xMax = 2048, yMin = 0, yMax = 2048, minXRange = 2048, minYRange = 2048, maxXRange = 2048, maxYRange = 2048)
        self.Mask_edit_viewItem = self.Mask_edit_view.getImageItem()

        #        self.ROIitem = pg.PolyLineROI([[0,0], [80,0], [80,80], [0,80]], closed=True)
        self.Mask_edit_view_getView = self.Mask_edit_view.getView()
        #        self.Mask_edit_view_getView.addItem(self.ROIitem)

        self.Mask_edit_view.ui.roiBtn.hide()
        self.Mask_edit_view.ui.menuBtn.hide()
        self.Mask_edit_view.ui.normGroup.hide()
        self.Mask_edit_view.ui.roiPlot.hide()

        MLmaskEditBoxLayout.addWidget(self.Mask_edit_view, 0, 0)

        MLmaskEditBox.setLayout(MLmaskEditBoxLayout)

        self.Imgviewtabs.addTab(MLmaskEditBox, "Mask edit")

        graphContainerLayout.addWidget(self.Imgviewtabs, 0, 0)
        graphContainer.setLayout(graphContainerLayout)

        # =============================================================================
        #         Operation container
        # =============================================================================
        operationContainer = StylishQT.roundQGroupBox()
        operationContainerLayout = QGridLayout()

        self.init_ML_button = QPushButton('Initialize ML', self)
        operationContainerLayout.addWidget(self.init_ML_button, 0, 0)
        self.init_ML_button.clicked.connect(self.init_ML)

        #---------------------Load image from file-----------------------------
        self.textbox_loadimg = QLineEdit(self)
        operationContainerLayout.addWidget(self.textbox_loadimg, 1, 0)

        self.button_import_img_browse = QPushButton('Browse', self)
        operationContainerLayout.addWidget(self.button_import_img_browse, 1, 1)
        self.button_import_img_browse.clicked.connect(self.get_img_file_tif)

        self.run_ML_button = QPushButton('Analysis', self)
        operationContainerLayout.addWidget(self.run_ML_button, 2, 0)
        self.run_ML_button.clicked.connect(self.run_ML_onImg_and_display)

        self.generate_MLmask_button = QPushButton('Mask', self)
        operationContainerLayout.addWidget(self.generate_MLmask_button, 2, 1)
        self.generate_MLmask_button.clicked.connect(self.generate_MLmask)

        self.update_MLmask_button = QPushButton('Update mask', self)
        operationContainerLayout.addWidget(self.update_MLmask_button, 3, 0)
        self.update_MLmask_button.clicked.connect(self.update_mask)

        self.enable_modify_MLmask_button = QPushButton('Enable free-hand',
                                                       self)
        self.enable_modify_MLmask_button.setCheckable(True)
        operationContainerLayout.addWidget(self.enable_modify_MLmask_button, 4,
                                           0)
        self.enable_modify_MLmask_button.clicked.connect(self.enable_free_hand)

        #        self.modify_MLmask_button = QPushButton('Add patch', self)
        #        operationContainerLayout.addWidget(self.modify_MLmask_button, 4, 1)
        #        self.modify_MLmask_button.clicked.connect(self.addedROIitem_to_Mask)

        self.clear_roi_button = QPushButton('Clear ROIs', self)
        operationContainerLayout.addWidget(self.clear_roi_button, 5, 0)
        self.clear_roi_button.clicked.connect(self.clear_edit_roi)

        #        self.maskLaserComboBox = QComboBox()
        #        self.maskLaserComboBox.addItems(['640', '532', '488'])
        #        operationContainerLayout.addWidget(self.maskLaserComboBox, 6, 0)
        #
        #        self.generate_transformed_mask_button = QPushButton('Transform mask', self)
        #        operationContainerLayout.addWidget(self.generate_transformed_mask_button, 6, 1)
        #        self.generate_transformed_mask_button.clicked.connect(self.generate_transformed_mask)

        self.emit_transformed_mask_button = QPushButton('Emit mask', self)
        operationContainerLayout.addWidget(self.emit_transformed_mask_button,
                                           7, 1)
        self.emit_transformed_mask_button.clicked.connect(
            self.emit_mask_contour)

        operationContainer.setLayout(operationContainerLayout)

        # =============================================================================
        #         Mask para container
        # =============================================================================
        MaskparaContainer = StylishQT.roundQGroupBox()
        MaskparaContainerContainerLayout = QGridLayout()

        #----------------------------------------------------------------------
        self.fillContourButton = QCheckBox()
        self.invertMaskButton = QCheckBox()
        self.thicknessSpinBox = QSpinBox()
        self.thicknessSpinBox.setRange(1, 25)
        MaskparaContainerContainerLayout.addWidget(QLabel('Fill contour:'), 0,
                                                   0)
        MaskparaContainerContainerLayout.addWidget(self.fillContourButton, 0,
                                                   1)
        MaskparaContainerContainerLayout.addWidget(QLabel('Invert mask:'), 1,
                                                   0)
        MaskparaContainerContainerLayout.addWidget(self.invertMaskButton, 1, 1)
        MaskparaContainerContainerLayout.addWidget(QLabel('Thickness:'), 2, 0)
        MaskparaContainerContainerLayout.addWidget(self.thicknessSpinBox, 2, 1)

        MaskparaContainer.setLayout(MaskparaContainerContainerLayout)
        # =============================================================================
        #         Device operation container
        # =============================================================================
        deviceOperationContainer = StylishQT.roundQGroupBox()
        deviceOperationContainerLayout = QGridLayout()

        #----------------------------------------------------------------------
        self.CamExposureBox = QDoubleSpinBox(self)
        self.CamExposureBox.setDecimals(6)
        self.CamExposureBox.setMinimum(0)
        self.CamExposureBox.setMaximum(100)
        self.CamExposureBox.setValue(0.001501)
        self.CamExposureBox.setSingleStep(0.001)
        deviceOperationContainerLayout.addWidget(self.CamExposureBox, 0, 1)
        deviceOperationContainerLayout.addWidget(QLabel("Exposure time:"), 0,
                                                 0)

        cam_snap_button = QPushButton('Cam snap', self)
        deviceOperationContainerLayout.addWidget(cam_snap_button, 0, 2)
        cam_snap_button.clicked.connect(self.cam_snap)

        cam_snap_button = QPushButton('Cam snap', self)
        deviceOperationContainerLayout.addWidget(cam_snap_button, 0, 2)
        cam_snap_button.clicked.connect(self.cam_snap)

        deviceOperationContainer.setLayout(deviceOperationContainerLayout)

        self.layout.addWidget(graphContainer, 0, 0, 3, 1)
        self.layout.addWidget(operationContainer, 0, 1)
        self.layout.addWidget(MaskparaContainer, 1, 1)
        self.layout.addWidget(deviceOperationContainer, 2, 1)
        self.setLayout(self.layout)
コード例 #7
0
class MainGUI(QWidget):

    # signal_DMDmask is cictionary with laser specification as key and binary mask as content.
    signal_DMDmask = pyqtSignal(dict)
    signal_DMDcontour = pyqtSignal(list)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        os.chdir('./')  # Set directory to current folder.
        self.setFont(QFont("Arial"))

        #        self.setMinimumSize(900, 1020)
        self.setWindowTitle("Cell Selection")
        self.layout = QGridLayout(self)

        self.roi_list_freehandl_added = []
        self.selected_ML_Index = []
        self.selected_cells_infor_dict = {}

        self.mask_color_multiplier = [1, 1, 0]
        # =============================================================================
        #         Container for image display
        # =============================================================================
        graphContainer = StylishQT.roundQGroupBox()
        graphContainerLayout = QGridLayout()

        self.Imgviewtabs = QTabWidget()

        MLmaskviewBox = QWidget()
        MLmaskviewBoxLayout = QGridLayout()

        self.Matdisplay_Figure = Figure()
        self.Matdisplay_Canvas = FigureCanvas(self.Matdisplay_Figure)
        self.Matdisplay_Canvas.setFixedWidth(500)
        self.Matdisplay_Canvas.setFixedHeight(500)
        self.Matdisplay_Canvas.mpl_connect('button_press_event', self._onclick)

        self.Matdisplay_toolbar = NavigationToolbar(self.Matdisplay_Canvas,
                                                    self)

        MLmaskviewBoxLayout.addWidget(self.Matdisplay_toolbar, 0, 0)
        MLmaskviewBoxLayout.addWidget(self.Matdisplay_Canvas, 1, 0)

        MLmaskviewBox.setLayout(MLmaskviewBoxLayout)

        self.Imgviewtabs.addTab(MLmaskviewBox, "MaskRCNN")

        # =============================================================================
        #         Mask editing tab
        # =============================================================================
        MLmaskEditBox = QWidget()
        MLmaskEditBoxLayout = QGridLayout()

        self.Mask_edit_view = DrawingWidget(self)
        self.Mask_edit_view.enable_drawing(False)  # Disable drawing first
        #        self.Mask_edit_view = pg.ImageView()
        #        self.Mask_edit_view.getView().setLimits(xMin = 0, xMax = 2048, yMin = 0, yMax = 2048, minXRange = 2048, minYRange = 2048, maxXRange = 2048, maxYRange = 2048)
        self.Mask_edit_viewItem = self.Mask_edit_view.getImageItem()

        #        self.ROIitem = pg.PolyLineROI([[0,0], [80,0], [80,80], [0,80]], closed=True)
        self.Mask_edit_view_getView = self.Mask_edit_view.getView()
        #        self.Mask_edit_view_getView.addItem(self.ROIitem)

        self.Mask_edit_view.ui.roiBtn.hide()
        self.Mask_edit_view.ui.menuBtn.hide()
        self.Mask_edit_view.ui.normGroup.hide()
        self.Mask_edit_view.ui.roiPlot.hide()

        MLmaskEditBoxLayout.addWidget(self.Mask_edit_view, 0, 0)

        MLmaskEditBox.setLayout(MLmaskEditBoxLayout)

        self.Imgviewtabs.addTab(MLmaskEditBox, "Mask edit")

        graphContainerLayout.addWidget(self.Imgviewtabs, 0, 0)
        graphContainer.setLayout(graphContainerLayout)

        # =============================================================================
        #         Operation container
        # =============================================================================
        operationContainer = StylishQT.roundQGroupBox()
        operationContainerLayout = QGridLayout()

        self.init_ML_button = QPushButton('Initialize ML', self)
        operationContainerLayout.addWidget(self.init_ML_button, 0, 0)
        self.init_ML_button.clicked.connect(self.init_ML)

        #---------------------Load image from file-----------------------------
        self.textbox_loadimg = QLineEdit(self)
        operationContainerLayout.addWidget(self.textbox_loadimg, 1, 0)

        self.button_import_img_browse = QPushButton('Browse', self)
        operationContainerLayout.addWidget(self.button_import_img_browse, 1, 1)
        self.button_import_img_browse.clicked.connect(self.get_img_file_tif)

        self.run_ML_button = QPushButton('Analysis', self)
        operationContainerLayout.addWidget(self.run_ML_button, 2, 0)
        self.run_ML_button.clicked.connect(self.run_ML_onImg_and_display)

        self.generate_MLmask_button = QPushButton('Mask', self)
        operationContainerLayout.addWidget(self.generate_MLmask_button, 2, 1)
        self.generate_MLmask_button.clicked.connect(self.generate_MLmask)

        self.update_MLmask_button = QPushButton('Update mask', self)
        operationContainerLayout.addWidget(self.update_MLmask_button, 3, 0)
        self.update_MLmask_button.clicked.connect(self.update_mask)

        self.enable_modify_MLmask_button = QPushButton('Enable free-hand',
                                                       self)
        self.enable_modify_MLmask_button.setCheckable(True)
        operationContainerLayout.addWidget(self.enable_modify_MLmask_button, 4,
                                           0)
        self.enable_modify_MLmask_button.clicked.connect(self.enable_free_hand)

        #        self.modify_MLmask_button = QPushButton('Add patch', self)
        #        operationContainerLayout.addWidget(self.modify_MLmask_button, 4, 1)
        #        self.modify_MLmask_button.clicked.connect(self.addedROIitem_to_Mask)

        self.clear_roi_button = QPushButton('Clear ROIs', self)
        operationContainerLayout.addWidget(self.clear_roi_button, 5, 0)
        self.clear_roi_button.clicked.connect(self.clear_edit_roi)

        #        self.maskLaserComboBox = QComboBox()
        #        self.maskLaserComboBox.addItems(['640', '532', '488'])
        #        operationContainerLayout.addWidget(self.maskLaserComboBox, 6, 0)
        #
        #        self.generate_transformed_mask_button = QPushButton('Transform mask', self)
        #        operationContainerLayout.addWidget(self.generate_transformed_mask_button, 6, 1)
        #        self.generate_transformed_mask_button.clicked.connect(self.generate_transformed_mask)

        self.emit_transformed_mask_button = QPushButton('Emit mask', self)
        operationContainerLayout.addWidget(self.emit_transformed_mask_button,
                                           7, 1)
        self.emit_transformed_mask_button.clicked.connect(
            self.emit_mask_contour)

        operationContainer.setLayout(operationContainerLayout)

        # =============================================================================
        #         Mask para container
        # =============================================================================
        MaskparaContainer = StylishQT.roundQGroupBox()
        MaskparaContainerContainerLayout = QGridLayout()

        #----------------------------------------------------------------------
        self.fillContourButton = QCheckBox()
        self.invertMaskButton = QCheckBox()
        self.thicknessSpinBox = QSpinBox()
        self.thicknessSpinBox.setRange(1, 25)
        MaskparaContainerContainerLayout.addWidget(QLabel('Fill contour:'), 0,
                                                   0)
        MaskparaContainerContainerLayout.addWidget(self.fillContourButton, 0,
                                                   1)
        MaskparaContainerContainerLayout.addWidget(QLabel('Invert mask:'), 1,
                                                   0)
        MaskparaContainerContainerLayout.addWidget(self.invertMaskButton, 1, 1)
        MaskparaContainerContainerLayout.addWidget(QLabel('Thickness:'), 2, 0)
        MaskparaContainerContainerLayout.addWidget(self.thicknessSpinBox, 2, 1)

        MaskparaContainer.setLayout(MaskparaContainerContainerLayout)
        # =============================================================================
        #         Device operation container
        # =============================================================================
        deviceOperationContainer = StylishQT.roundQGroupBox()
        deviceOperationContainerLayout = QGridLayout()

        #----------------------------------------------------------------------
        self.CamExposureBox = QDoubleSpinBox(self)
        self.CamExposureBox.setDecimals(6)
        self.CamExposureBox.setMinimum(0)
        self.CamExposureBox.setMaximum(100)
        self.CamExposureBox.setValue(0.001501)
        self.CamExposureBox.setSingleStep(0.001)
        deviceOperationContainerLayout.addWidget(self.CamExposureBox, 0, 1)
        deviceOperationContainerLayout.addWidget(QLabel("Exposure time:"), 0,
                                                 0)

        cam_snap_button = QPushButton('Cam snap', self)
        deviceOperationContainerLayout.addWidget(cam_snap_button, 0, 2)
        cam_snap_button.clicked.connect(self.cam_snap)

        cam_snap_button = QPushButton('Cam snap', self)
        deviceOperationContainerLayout.addWidget(cam_snap_button, 0, 2)
        cam_snap_button.clicked.connect(self.cam_snap)

        deviceOperationContainer.setLayout(deviceOperationContainerLayout)

        self.layout.addWidget(graphContainer, 0, 0, 3, 1)
        self.layout.addWidget(operationContainer, 0, 1)
        self.layout.addWidget(MaskparaContainer, 1, 1)
        self.layout.addWidget(deviceOperationContainer, 2, 1)
        self.setLayout(self.layout)

    #%%
    # =============================================================================
    #     MaskRCNN detection part
    # =============================================================================
#    @run_in_thread

    def init_ML(self):
        # Initialize the detector instance and load the model.
        self.ProcessML = ProcessImageML()

    def get_img_file_tif(self):
        self.img_tif_filePath, _ = QtWidgets.QFileDialog.getOpenFileName(
            self, 'Single File',
            'M:/tnw/ist/do/projects/Neurophotonics/Brinkslab/Data', "(*.tif)")
        self.textbox_loadimg.setText(self.img_tif_filePath)

        if self.img_tif_filePath != None:
            self.Rawimage = imread(self.img_tif_filePath)

            self.MLtargetedImg_raw = self.Rawimage.copy()

            self.MLtargetedImg = self.convert_for_MaskRCNN(
                self.MLtargetedImg_raw)

            self.show_raw_image(self.MLtargetedImg)

            self.addedROIitemMask = np.zeros(
                (self.MLtargetedImg.shape[0], self.MLtargetedImg.shape[1]))
            self.MLmask = np.zeros(
                (self.MLtargetedImg.shape[0], self.MLtargetedImg.shape[1]))

    def show_raw_image(self, image):
        # display a single image
        try:
            self.Matdisplay_Figure.clear()
        except:
            pass
        ax1 = self.Matdisplay_Figure.add_subplot(111)
        ax1.set_xticks([])
        ax1.set_yticks([])
        ax1.imshow(image)

        self.Matdisplay_Figure.tight_layout()
        self.Matdisplay_Canvas.draw()

        RGB_image = gray2rgb(image)
        self.Mask_edit_viewItem.setImage(RGB_image)

    def convert_for_MaskRCNN(self, input_img):
        """Convert the image size and bit-depth to make it suitable for MaskRCNN detection."""
        if input_img.shape[0] > 1024 or input_img.shape[1] > 1024:
            resized_img = resize(input_img, [1024, 1024],
                                 preserve_range=True).astype(input_img.dtype)

        minval = np.min(resized_img)
        maxval = np.max(resized_img)

        return ((resized_img - minval) / (maxval - minval) * 255).astype(
            np.uint8)

    def run_ML_onImg_and_display(self):
        """Run MaskRCNN on input image"""
        self.Matdisplay_Figure.clear()
        ax1 = self.Matdisplay_Figure.add_subplot(111)

        # Depends on show_mask or not, the returned figure will be input raw image with mask or not.
        self.MLresults, self.Matdisplay_Figure_axis, self.unmasked_fig = self.ProcessML.DetectionOnImage(
            self.MLtargetedImg, axis=ax1, show_mask=False, show_bbox=False)
        self.Mask = self.MLresults['masks']
        self.Label = self.MLresults['class_ids']
        self.Score = self.MLresults['scores']
        self.Bbox = self.MLresults['rois']

        self.SelectedCellIndex = 0
        self.NumCells = int(len(self.Label))
        self.selected_ML_Index = []
        self.selected_cells_infor_dict = {}

        self.Matdisplay_Figure_axis.imshow(self.unmasked_fig.astype(np.uint8))

        self.Matdisplay_Figure.tight_layout()
        self.Matdisplay_Canvas.draw()

    #%%
    # =============================================================================
    #     Configure click event to add clicked cell mask
    # =============================================================================

    def _onclick(self, event):
        """Highlights the cell selected in the figure by the user when clicked on"""
        if self.NumCells > 0:
            ShapeMask = np.shape(self.Mask)
            # get coorinates at selected location in image coordinates
            if event.xdata == None or event.ydata == None:
                return
            xcoor = min(max(int(event.xdata), 0), ShapeMask[1])
            ycoor = min(max(int(event.ydata), 0), ShapeMask[0])

            # search for the mask coresponding to the selected cell
            for EachCell in range(self.NumCells):
                if self.Mask[ycoor, xcoor, EachCell]:
                    self.SelectedCellIndex = EachCell
                    break

            # highlight selected cell
            if self.SelectedCellIndex not in self.selected_ML_Index:
                # Get the selected cell's contour coordinates and mask patch
                self.contour_verts, self.Cell_patch = self.get_cell_polygon(
                    self.Mask[:, :, self.SelectedCellIndex])

                self.Matdisplay_Figure_axis.add_patch(self.Cell_patch)
                self.Matdisplay_Canvas.draw()

                self.selected_ML_Index.append(self.SelectedCellIndex)
                self.selected_cells_infor_dict['cell{}_verts'.format(
                    str(self.SelectedCellIndex))] = self.contour_verts
            else:
                # If click on the same cell
                self.Cell_patch.remove()
                self.Matdisplay_Canvas.draw()
                self.selected_ML_Index.remove(self.SelectedCellIndex)
                self.selected_cells_infor_dict.pop('cell{}_verts'.format(
                    str(self.SelectedCellIndex)))

    def get_cell_polygon(self, mask):
        # Mask Polygon
        # Pad to ensure proper polygons for masks that touch image edges.
        padded_mask = np.zeros((mask.shape[0] + 2, mask.shape[1] + 2),
                               dtype=np.uint8)
        padded_mask[1:-1, 1:-1] = mask
        contours = find_contours(padded_mask, 0.5)
        for verts in contours:
            # Subtract the padding and flip (y, x) to (x, y)
            verts = np.fliplr(verts) - 1
            contour_polygon = mpatches.Polygon(
                verts, facecolor=self.random_colors(1)[0])

        return contours, contour_polygon

    def random_colors(self, N, bright=True):
        """
        Generate random colors.
        To get visually distinct colors, generate them in HSV space then
        convert to RGB.
        """
        brightness = 1.0 if bright else 0.7
        hsv = [(i / N, 1, brightness) for i in range(N)]
        colors = list(map(lambda c: colorsys.hsv_to_rgb(*c), hsv))
        random.shuffle(colors)
        return colors

    #%%
    # =============================================================================
    #     For mask generation
    # =============================================================================

    def generate_MLmask(self):
        """ Generate binary mask with all selected cells"""
        self.MLmask = np.zeros(
            (self.MLtargetedImg.shape[0], self.MLtargetedImg.shape[1]))

        if len(self.selected_ML_Index) > 0:
            for selected_index in self.selected_ML_Index:
                self.MLmask = np.add(self.MLmask, self.Mask[:, :,
                                                            selected_index])

            self.intergrate_into_final_mask()

            self.add_rois_of_selected()

        else:
            self.intergrate_into_final_mask()
#            self.Mask_edit_viewItem.setImage(gray2rgb(self.MLtargetedImg))

    def add_rois_of_selected(self):
        """
        Using find_contours to get list of contour coordinates in the binary mask, and then generate polygon rois based on these coordinates.
        """

        for selected_index in self.selected_ML_Index:

            contours = self.selected_cells_infor_dict['cell{}_verts'.format(
                str(selected_index))]
            #            contours = find_contours(self.Mask[:,:,selected_index], 0.5) # Find iso-valued contours in a 2D array for a given level value.

            for n, contour in enumerate(contours):
                contour_coord_array = contours[n]
                #Swap columns
                contour_coord_array[:,
                                    0], contour_coord_array[:,
                                                            1] = contour_coord_array[:,
                                                                                     1], contour_coord_array[:, 0].copy(
                                                                                     )

                #Down sample the coordinates otherwise it will be too dense.
                contour_coord_array_del = np.delete(
                    contour_coord_array,
                    np.arange(2, contour_coord_array.shape[0] - 3, 2), 0)

                self.selected_cells_infor_dict['cell{}_ROIitem'.format(str(selected_index))] = \
                pg.PolyLineROI(positions=contour_coord_array_del, closed=True)

                self.Mask_edit_view.getView().addItem(
                    self.selected_cells_infor_dict['cell{}_ROIitem'.format(
                        str(selected_index))])

    def update_mask(self):
        """
        Regenerate the masks for MaskRCNN and free-hand added (in case they are changed), and show in imageview.
        
        !!!ISSUE: getLocalHandlePositions: moving handles changes the position read out, dragging roi as a whole doesn't.
        """

        # Binary mask from ML detection
        if len(self.selected_ML_Index) > 0:
            # Delete items in dictionary that are not roi items
            roi_dict = self.selected_cells_infor_dict.copy()
            del_key_list = []
            for key in roi_dict:
                print(key)
                if 'ROIitem' not in key:
                    del_key_list.append(key)
            for key in del_key_list:
                del roi_dict[key]

            self.MLmask = ProcessImage.ROIitem2Mask(
                roi_dict,
                mask_resolution=(self.MLtargetedImg.shape[0],
                                 self.MLtargetedImg.shape[1]))
        # Binary mask of added rois
        self.addedROIitemMask = ProcessImage.ROIitem2Mask(
            self.roi_list_freehandl_added,
            mask_resolution=(self.MLtargetedImg.shape[0],
                             self.MLtargetedImg.shape[1]))

        self.intergrate_into_final_mask()

#        if type(self.roi_list_freehandl_added) is list:
#            for ROIitem in self.roi_list_freehandl_added:
#
#                ROIitem.sigHoverEvent.connect(lambda: self.show_roi_detail(ROIitem))
#
#        plt.figure()
#        plt.imshow(self.addedROIitemMask)
#        plt.show()
# =============================================================================
#     For free-hand rois
# =============================================================================

    def enable_free_hand(self):
        if self.enable_modify_MLmask_button.isChecked():
            self.Mask_edit_view.enable_drawing(True)
        else:
            self.Mask_edit_view.enable_drawing(False)

    def add_freehand_roi(self, roi):
        # For drawwidget
        self.roi_list_freehandl_added.append(roi)

    def clear_edit_roi(self):
        """
        Clean up all the free-hand rois.
        """

        for roi in self.roi_list_freehandl_added:
            self.Mask_edit_view.getView().removeItem(roi)

        self.roi_list_freehandl_added = []

        if len(self.selected_cells_infor_dict) > 0:
            # Remove all selected masks
            for roiItemkey in self.selected_cells_infor_dict:
                if 'ROIitem' in roiItemkey:
                    self.Mask_edit_view.getView().removeItem(
                        self.selected_cells_infor_dict[roiItemkey])

        self.selected_cells_infor_dict = {}
        self.MLmask = np.zeros(
            (self.MLtargetedImg.shape[0], self.MLtargetedImg.shape[1]))
        self.intergrate_into_final_mask()

    def intergrate_into_final_mask(self):
        # Binary mask of added rois
        self.addedROIitemMask = ProcessImage.ROIitem2Mask(
            self.roi_list_freehandl_added,
            mask_resolution=(self.MLtargetedImg.shape[0],
                             self.MLtargetedImg.shape[1]))
        #Display the RGB mask, ML mask plus free-hand added.
        self.Mask_edit_viewItem.setImage(gray2rgb(self.addedROIitemMask) * self.mask_color_multiplier + \
                                         gray2rgb(self.MLmask) * self.mask_color_multiplier + gray2rgb(self.MLtargetedImg))

        self.final_mask = self.MLmask + self.addedROIitemMask

        # In case the input image is 2048*2048, and it is resized to fit in MaskRCNN, need to convert back to original size for DMD tranformation.
        if self.final_mask.shape[0] != self.Rawimage.shape[
                0] or self.final_mask.shape[1] != self.Rawimage.shape[1]:
            self.final_mask = resize(
                self.final_mask,
                [self.Rawimage.shape[0], self.Rawimage.shape[1]],
                preserve_range=True).astype(self.final_mask.dtype)
#        self.final_mask = np.where(self.final_mask <= 1, self.final_mask, int(1))

        plt.figure()
        plt.imshow(self.final_mask)
        plt.show()

    # =============================================================================
    # For DMD transformation and mask generation
    # =============================================================================
    def generate_transformed_mask(self):
        self.read_transformations_from_file()
        #        self.transform_to_DMD_mask(laser = self.maskLaserComboBox.currentText(), dict_transformations = self.dict_transformations)
        target_laser = self.maskLaserComboBox.currentText()
        self.final_DMD_mask = self.finalmask_to_DMD_mask(
            laser=target_laser, dict_transformations=self.dict_transformations)

        plt.figure()
        plt.imshow(self.final_DMD_mask)
        plt.show()

    def emit_mask_contour(self):
        """Use find_contours to get a list of (n,2)-ndarrays consisting of n (row, column) coordinates along the contour,
           and then feed the list of signal:[list_of_rois, flag_fill_contour, contour_thickness, flag_invert_mode] to the 
           receive_mask_coordinates function in DMDWidget.
        """
        contours = find_contours(self.final_mask, 0.5)

        sig = [
            contours,
            self.fillContourButton.isChecked(),
            self.thicknessSpinBox.value(),
            self.invertMaskButton.isChecked()
        ]

        self.signal_DMDcontour.emit(sig)

    def emit_mask(self):
        target_laser = self.maskLaserComboBox.currentText()
        final_DMD_mask_dict = {}
        final_DMD_mask_dict['camera-dmd-' + target_laser] = self.final_DMD_mask

        self.signal_DMDmask.emit(final_DMD_mask_dict)

    def read_transformations_from_file(self):
        try:
            with open(
                    r'M:\tnw\ist\do\projects\Neurophotonics\Brinkslab\People\Xin Meng\Code\Python_test\DMDManager\Registration\transformation.txt',
                    'r') as json_file:
                self.dict_transformations = json.load(json_file)
        except:
            print(
                'No transformation could be loaded from previous registration run.'
            )
            return

#    def transform_to_DMD_mask(self, laser, dict_transformations, flag_fill_contour = True, contour_thickness = 1, flag_invert_mode = False, mask_resolution = (1024, 768)):
#        """
#        Get roi vertices from all roi items and perform the transformation, and then create the mask for DMD.
#        """
#
#        #list of roi vertices each being (n,2) numpy array for added rois
#        if len(self.roi_list_freehandl_added) > 0:
#            self.addedROIitem_vertices = ProcessImage.ROIitem2Vertices(self.roi_list_freehandl_added)
#            #addedROIitem_vertices needs to be seperated to be inidividual (n,2) np.array
#                self.ROIitems_mask_transformed = ProcessImage.vertices_to_DMD_mask(self.addedROIitem_vertices, laser, dict_transformations, flag_fill_contour = True, contour_thickness = 1,\
#                                                                          flag_invert_mode = False, mask_resolution = (1024, 768))
#
#        #Dictionary with (n,2) numpy array for clicked cells
#        if len(self.selected_cells_infor_dict) > 0:
#            #Convert dictionary to np.array
#            for roiItemkey in self.selected_cells_infor_dict:
#                #Each one is 'contours' from find_contour
#                if '_verts' in roiItemkey:
#                    self.selected_cells_infor_dict[roiItemkey]
#
#            self.MLitems_mask_transformed = ProcessImage.vertices_to_DMD_mask(self.selected_cells_infor_dict, laser, dict_transformations, flag_fill_contour = True, contour_thickness = 1,\
#                                                                      flag_invert_mode = False, mask_resolution = (1024, 768))
#
#        if len(self.roi_list_freehandl_added) > 0:
#            self.final_DMD_mask = self.ROIitems_mask_transformed + self.MLitems_mask_transformed
#            self.final_DMD_mask[self.final_DMD_mask>1] = 1
#        else:
#            self.final_DMD_mask = self.MLitems_mask_transformed
#
#        return self.final_DMD_mask

    def finalmask_to_DMD_mask(self,
                              laser,
                              dict_transformations,
                              flag_fill_contour=True,
                              contour_thickness=1,
                              flag_invert_mode=False,
                              mask_resolution=(1024, 768)):
        """
        Same goal as transform_to_DMD_mask, with input being the final binary mask and using find_contour to get all vertices and perform transformation,
        and then coordinates to mask.
        """

        self.final_DMD_mask = ProcessImage.binarymask_to_DMD_mask(self.final_mask, laser, dict_transformations, flag_fill_contour = True, \
                                                                  contour_thickness = 1, flag_invert_mode = False, mask_resolution = (1024, 768))

        return self.final_DMD_mask

    def closeEvent(self, event):
        QtWidgets.QApplication.quit()
        event.accept()


#    def apply_mask(self, image, mask, color, alpha=0.5):
#        """Apply the given mask to the image.
#        """
#        for c in range(3):
#            image[:, :, c] = np.where(mask == 1,
#                                      image[:, :, c] *
#                                      (1 - alpha) + alpha * color[c] * 255,
#                                      image[:, :, c])
#        return image
#%%
#    @run_in_thread

    def cam_snap(self):
        """Get a image from camera"""
        self.cam = CamActuator()
        self.cam.initializeCamera()

        exposure_time = self.CamExposureBox.value()
        self.Rawimage = self.cam.SnapImage(exposure_time)
        self.cam.Exit()
        print('Snap finished')

        self.MLtargetedImg_raw = self.Rawimage.copy()

        self.MLtargetedImg = self.convert_for_MaskRCNN(self.MLtargetedImg_raw)

        self.show_raw_image(self.MLtargetedImg)

        self.addedROIitemMask = np.zeros(
            (self.MLtargetedImg.shape[0], self.MLtargetedImg.shape[1]))
        self.MLmask = np.zeros(
            (self.MLtargetedImg.shape[0], self.MLtargetedImg.shape[1]))