Пример #1
0
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
        # 获取屏幕尺寸相关信息
        self.ag = QApplication.desktop().availableGeometry()
        self.maxWidth = self.ag.width()
        self.maxHeight = self.ag.height()

        self.real = QApplication.desktop().geometry()

        self.windowPreState = None

        self.initWidth = 1280
        self.initHeight = 760
        # 全局存储当前屏幕参数
        ctx.put(Key.WINDOW_INIT_SIZE, [self.initWidth, self.initHeight])
        ctx.put(Key.SCREEN_AVAIL_SIZE, [self.maxWidth, self.maxHeight])
        ctx.put(Key.SCREEN_REAL_SIZE, [self.real.width(), self.real.height()])

        # 头部标题栏
        self.head = Pane(self)
        # 条码输入框
        self.barcode = EditText()
        # 流程展示控件
        self.resultBox = QLabel()
        # 显示最终结果控件
        self.displayBox = TextView()
        # 摄像头开启控件, 在这里只新建对象,不要将其添加到窗口中
        # 因为图层遮挡,到后面得不到鼠标事件
        self.cameraIcon = ImageView()
Пример #2
0
    def __init__(self, data, parent=None, liveplot=None):
        # Init Feature
        Feature.__init__(self,
                         'Cell Selection',
                         data,
                         parent,
                         liveplot,
                         display_name_label=False)

        self.data_manager = data
        self.data_manager.cell_selection = self

        self.setMinimumSize(350, 450)

        self.allowEditROI = True
        self.disabled_roi_handles = []
        self.preview_mode = True
        self.show_user_roi = False
        self.ellipse_mode = True
        self.update_on_ellipse_mode_change = True

        # data
        self.input = {'source': None, 'roi_ellipse_mode': None}
        self.output = {'cell': None, 'cell mean': None, 'roi': None}

        # view / plot
        self.imv = ImageView()
        self.imv.setMinimumHeight(450)
        self.layout.addWidget(self.imv)
        self.imv.view.mouseClickEvent = lambda ev: self.imvViewMouseClickEvent(
            self.imv.view, ev)
        self.imv.view.raiseContextMenu = lambda ev: self.imvViewRaiseContextMenu(
            self.imv.view, ev)
        self.imv.view.getContextMenus = lambda ev=None: self.imvViewGetContextMenus(
            self.imv.view, ev)

        self.imv.view.preview_mode = self.imv.view.menu.addAction(
            'live preview mode')
        self.imv.view.preview_mode.setCheckable(True)
        self.imv.view.preview_mode.setChecked(self.preview_mode)
        self.imv.view.preview_mode.triggered.connect(self.switchPreviewMode)

        self.imv.view.ellipse_mode = self.imv.view.menu.addAction(
            'ellipse mode')
        self.imv.view.ellipse_mode.setCheckable(True)
        self.imv.view.ellipse_mode.setChecked(self.ellipse_mode)
        self.connectEllipseMode()

        # methods
        self.addMethod('ROI', cs_roi_params, self.calculateROI)
        self.initMethodUI()
        self.initParametersUI()

        self.show()
        """
        the image must be displayed once such that the roicurve is created and can be shown
        even if the user loads a non-TIF source before he loads a TIF source.
        """
        self.imv.setImage(np.zeros((1, 10, 10)), xvals=np.arange(10))
        self.imv.clear()
Пример #3
0
    def createHead(self):
        self.head.resize(self.initWidth, MainWindow.HEAD_HEIGHT)
        self.head.move(0, 0)

        innerLayout = QHBoxLayout()
        innerLayout.layout().setContentsMargins(0, 0, 0, 0)

        self.head.setLayout(innerLayout)

        adjust = TextView("校准")
        adjust.setObjectName("adjust")
        adjust.setFixedSize(MainWindow.RIGHT_LABEL_WIDTH,
                            MainWindow.HEAD_HEIGHT)
        adjust.setAlignment(Qt.AlignCenter)
        adjust.setMousePressCallback(self.clickedEvent)

        # 右边
        # 隐藏窗口控件
        dis = ImageView()
        dis.setFixedSize(MainWindow.RIGHT_LABEL_WIDTH, MainWindow.HEAD_HEIGHT)
        dis.setObjectName("dis")
        dis.setCallback(self.clickedEvent)

        # 最大最小化窗口控件
        maxi = ImageView()
        maxi.setFixedSize(MainWindow.RIGHT_LABEL_WIDTH, MainWindow.HEAD_HEIGHT)
        maxi.setObjectName("maxi")
        maxi.setCallback(self.clickedEvent)

        # 关闭窗口控件
        close = ImageView()
        close.setFixedSize(MainWindow.RIGHT_LABEL_WIDTH,
                           MainWindow.HEAD_HEIGHT)
        close.setObjectName("close")
        close.setCallback(self.clickedEvent)
        close.setDoubleClick(self.doubleClickEvent)

        innerLayout.addStretch(0)

        innerLayout.addWidget(adjust)
        innerLayout.addWidget(dis)
        innerLayout.addWidget(maxi)
        innerLayout.addWidget(close)
Пример #4
0
    def createHead(self):
        head = QWidget(self)
        head.setObjectName("head")
        head.resize(self.w, self.headHeight)
        head.move(0, 0)
        head.setContentsMargins(0, 0, 0, 0)

        headInnerBox = QHBoxLayout()
        headInnerBox.setContentsMargins(0, 0, 0, 0)
        head.setLayout(headInnerBox)

        leftSpace = QLabel()
        leftSpace.resize(10, self.headHeight)
        headInnerBox.addWidget(leftSpace)

        title = TextView()
        title.setObjectName("title")
        title.setText("校准框(请将机台对准框)")
        headInnerBox.addWidget(title)

        # 隐藏窗口控件
        dis = ImageView()
        dis.setFixedSize(CalibrationActivity.__IMAGE_WIDTH, self.headHeight)
        dis.setObjectName("dis")
        dis.setCallback(self.clickedEvent)

        # 关闭窗口控件
        close = ImageView()
        close.setFixedSize(CalibrationActivity.__IMAGE_WIDTH, self.headHeight)
        close.setObjectName("close")
        close.setCallback(self.clickedEvent)

        headInnerBox.addStretch(0)
        headInnerBox.addWidget(dis)
        headInnerBox.addWidget(close)
Пример #5
0
    def createHead(self):
        self.head.resize(self.initWidth, MainWindow.HEAD_HEIGHT)
        self.head.move(0, 0)

        innerLayout = QHBoxLayout()
        innerLayout.layout().setContentsMargins(0, 0, 0, 0)

        # 间隔
        leftSpace = QLabel("")
        leftSpace.setFixedSize(0, 10)
        innerLayout.addWidget(leftSpace)

        # 左边图标
        icon = QLabel()
        icon.setFixedSize(25, 25)
        icon.setObjectName("icon")

        # 项目名称
        name = QLabel("AI")
        name.setObjectName("projectName")

        # 版本号
        version = QLabel("v1.2021.01.09")
        version.setObjectName("version")

        innerLayout.addWidget(icon)
        innerLayout.addWidget(name)
        innerLayout.addWidget(version)
        innerLayout.addStretch(1)

        innerLayout.setSpacing(10)
        innerLayout.setAlignment(Qt.AlignHCenter)

        self.head.setLayout(innerLayout)

        # 右边
        # 隐藏窗口控件
        dis = ImageView()
        dis.setFixedSize(MainWindow.RIGHT_LABEL_WIDTH, MainWindow.HEAD_HEIGHT)
        dis.setObjectName("dis")
        dis.setCallback(self.clickedEvent)

        # 最大最小化窗口控件
        maxi = ImageView()
        maxi.setFixedSize(MainWindow.RIGHT_LABEL_WIDTH, MainWindow.HEAD_HEIGHT)
        maxi.setObjectName("maxi")
        maxi.setCallback(self.clickedEvent)

        # 关闭窗口控件
        close = ImageView()
        close.setFixedSize(MainWindow.RIGHT_LABEL_WIDTH,
                           MainWindow.HEAD_HEIGHT)
        close.setObjectName("close")
        close.setCallback(self.clickedEvent)

        innerLayout.addStretch(0)

        innerLayout.addWidget(dis)
        innerLayout.addWidget(maxi)
        innerLayout.addWidget(close)
Пример #6
0
class MainWindow(QWidget):
    # 头部的高度
    HEAD_HEIGHT = 40
    # 头部下面的线条高度
    LINE_HEIGHT = 1
    RIGHT_LABEL_WIDTH = 60
    # 默认的背景颜色
    BG_COLOR = "#0C172D"
    # 摄像头图片容器的尺寸
    CAMERA_ICON_SIZE = QSize(50, 50)
    # 边界间隔
    PADDING = 10

    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
        # 获取屏幕尺寸相关信息
        self.ag = QApplication.desktop().availableGeometry()
        self.maxWidth = self.ag.width()
        self.maxHeight = self.ag.height()

        self.real = QApplication.desktop().geometry()

        self.windowPreState = None

        self.initWidth = 1280
        self.initHeight = 760
        # 全局存储当前屏幕参数
        ctx.put(Key.WINDOW_INIT_SIZE, [self.initWidth, self.initHeight])
        ctx.put(Key.SCREEN_AVAIL_SIZE, [self.maxWidth, self.maxHeight])
        ctx.put(Key.SCREEN_REAL_SIZE, [self.real.width(), self.real.height()])

        # 头部标题栏
        self.head = Pane(self)
        # 条码输入框
        self.barcode = EditText()
        # 流程展示控件
        self.resultBox = QLabel()
        # 显示最终结果控件
        self.displayBox = TextView()
        # 摄像头开启控件, 在这里只新建对象,不要将其添加到窗口中
        # 因为图层遮挡,到后面得不到鼠标事件
        self.cameraIcon = ImageView()

    def initStyle(self):
        self.setObjectName("window")
        self.resize(self.initWidth, self.initHeight)
        self.setWindowTitle(Global.project_name)
        self.setWindowFlags(Qt.FramelessWindowHint)
        # self.setStyleSheet(style)

    def display(self):
        self.initStyle()
        self.createHead()
        self.createLine()
        self.createBody()
        self.show()

    def createHead(self):
        self.head.resize(self.initWidth, MainWindow.HEAD_HEIGHT)
        self.head.move(0, 0)

        innerLayout = QHBoxLayout()
        innerLayout.layout().setContentsMargins(0, 0, 0, 0)

        # 间隔
        leftSpace = QLabel("")
        leftSpace.setFixedSize(0, 10)
        innerLayout.addWidget(leftSpace)

        # 左边图标
        icon = QLabel()
        icon.setFixedSize(25, 25)
        icon.setObjectName("icon")

        # 项目名称
        name = QLabel("AI")
        name.setObjectName("projectName")

        # 版本号
        version = QLabel("v1.2021.01.09")
        version.setObjectName("version")

        innerLayout.addWidget(icon)
        innerLayout.addWidget(name)
        innerLayout.addWidget(version)
        innerLayout.addStretch(1)

        innerLayout.setSpacing(10)
        innerLayout.setAlignment(Qt.AlignHCenter)

        self.head.setLayout(innerLayout)

        # 右边
        # 隐藏窗口控件
        dis = ImageView()
        dis.setFixedSize(MainWindow.RIGHT_LABEL_WIDTH, MainWindow.HEAD_HEIGHT)
        dis.setObjectName("dis")
        dis.setCallback(self.clickedEvent)

        # 最大最小化窗口控件
        maxi = ImageView()
        maxi.setFixedSize(MainWindow.RIGHT_LABEL_WIDTH, MainWindow.HEAD_HEIGHT)
        maxi.setObjectName("maxi")
        maxi.setCallback(self.clickedEvent)

        # 关闭窗口控件
        close = ImageView()
        close.setFixedSize(MainWindow.RIGHT_LABEL_WIDTH,
                           MainWindow.HEAD_HEIGHT)
        close.setObjectName("close")
        close.setCallback(self.clickedEvent)

        innerLayout.addStretch(0)

        innerLayout.addWidget(dis)
        innerLayout.addWidget(maxi)
        innerLayout.addWidget(close)

    def createLine(self):
        line = QWidget(self)
        line.resize(self.initWidth, MainWindow.LINE_HEIGHT)
        line.move(0, MainWindow.HEAD_HEIGHT)
        line.setObjectName("line")

    def createBody(self):
        body = QWidget(self)
        body.resize(
            self.initWidth,
            self.initHeight - MainWindow.HEAD_HEIGHT - MainWindow.LINE_HEIGHT)
        body.move(0, MainWindow.HEAD_HEIGHT + MainWindow.LINE_HEIGHT)
        # body.setStyleSheet("background-color: #DA81F5;")

        # 左边盒子宽度
        leftBoxWidth = 400

        # 盒子高度
        boxHeight = 700
        # padding
        padding = 10
        # 条码输入框高度
        barcodeHeight = 30
        # 流程信息展示区高度
        displayBoxHeight = 450

        bannerHeight = 100

        # 右边区域宽度 = 窗口宽度 - 左边盒子宽度 - 左边盒子距离窗口左边的间隔 - 右边盒子和左边盒子的间隔 - 右边和距离窗口右边的间隔
        rightBoxWidth = self.initWidth - leftBoxWidth - padding - padding - padding

        # ############左边区域#################
        leftBox = QWidget(body)
        leftBox.resize(leftBoxWidth, boxHeight)
        leftBox.move(padding, padding)
        leftBox.setObjectName("leftBox")
        # leftBox.setStyleSheet("background-color: #CCECDA;")

        # 内部垂直布局
        leftBoxInnerBox = QVBoxLayout()
        leftBoxInnerBox.setSpacing(10)
        leftBox.setLayout(leftBoxInnerBox)

        # 条码输入框
        self.barcode.setParent(leftBox)
        self.barcode.setObjectName("barcode")
        self.barcode.setMaximumSize(leftBoxWidth, barcodeHeight)
        # self.barcode.setCallback(self.on_edit_change)
        leftBoxInnerBox.addWidget(self.barcode)

        # 流程展示区
        self.displayBox.setParent(leftBox)
        self.displayBox.resize(leftBoxWidth, displayBoxHeight)
        # self.displayBox.setMaximumHeight(displayBoxHeight)
        # self.displayBox.setMinimumHeight(displayBoxHeight)
        self.displayBox.setObjectName("displayBox")
        leftBoxInnerBox.addWidget(self.displayBox)
        self.displayBox.setAlignment(Qt.AlignTop)
        # effect = QGraphicsDropShadowEffect(self)
        # effect.setBlurRadius(12)
        # effect.setOffset(5, -5)
        # effect.setColor(Qt.red)
        # displayBox.setGraphicsEffect(effect)
        self.displayBox.setText("1.获取到条码.\n2.开始识别...\n3.识别结果: OK.")
        self.displayBox.append("4.结束!")
        for i in range(30):
            self.displayBox.append("{}.动作!".format(i))

        # 显示最终结果的地方
        self.resultBox.setParent(leftBox)
        self.resultBox.setObjectName("resultBox")
        self.resultBox.resize(
            leftBoxWidth, boxHeight - displayBoxHeight - barcodeHeight - 20)
        self.resultBox.setMaximumSize(
            leftBoxWidth, boxHeight - displayBoxHeight - barcodeHeight - 20)
        self.resultBox.setMinimumHeight(boxHeight - displayBoxHeight -
                                        barcodeHeight - 20)
        self.resultBox.setText("OK")
        self.resultBox.setAlignment(Qt.AlignCenter)
        self.resultBox.setPalette(QPalette(QColor(255, 0, 0, 1)))
        leftBoxInnerBox.addWidget(self.resultBox)

        # ############右边区域#################
        rightBox = QWidget(body)
        rightBox.resize(rightBoxWidth, boxHeight)
        rightBox.move(leftBoxWidth + padding + padding, padding)
        rightBox.setObjectName("rightBox")
        # rightBox.setStyleSheet("background-color: #E5E9BF;")

        # 左边区域内部垂直布局
        rightInnerBox = QVBoxLayout()
        rightInnerBox.setAlignment(Qt.AlignCenter)
        rightInnerBox.setSpacing(padding)
        rightBox.setLayout(rightInnerBox)

        # 横幅
        banner = QLabel("Kamiyong Welcome You!")
        banner.setObjectName("banner")
        banner.setMaximumSize(rightBoxWidth - 20, bannerHeight)
        banner.setMinimumSize(rightBoxWidth - 20, bannerHeight)
        rightInnerBox.addWidget(banner)

        image = QLabel()
        image.setObjectName("image")
        image.setMinimumSize(
            rightBoxWidth - 20,
            boxHeight - bannerHeight - padding - padding - padding)
        rightInnerBox.addWidget(image)

        # 摄像头图标, 在这里添加到窗口中
        # 这样改控件就在所有的图层最上面,就不会被其他控件遮挡而导致事件失效的问题
        self.cameraIcon.setParent(self)
        self.cameraIcon.setCallback(self.clickedEvent)
        self.cameraIcon.setObjectName("cameraIcon")
        self.cameraIcon.setFixedSize(MainWindow.CAMERA_ICON_SIZE.width(),
                                     MainWindow.CAMERA_ICON_SIZE.height())
        self.cameraIcon.move(
            self.initWidth - MainWindow.CAMERA_ICON_SIZE.width() -
            MainWindow.PADDING, MainWindow.HEAD_HEIGHT +
            MainWindow.LINE_HEIGHT + MainWindow.PADDING)

    def resizeEvent(self, event):
        """
        窗口尺寸变化事件
        :param event: {@link QEvent}
        :return: no return
        """
        # print("MainWindow Size[w=", self.width(), ", h=", self.height(), "]")
        self.head.change(self.width(), MainWindow.HEAD_HEIGHT)

    def getBarcodeEditText(self):
        """
        获取到条码输入框实例
        :return: {@link QEditText}
        """
        return self.barcode

    def getDisplayBox(self):
        """
        获取流程展示控件
        :return: {@link QLabel}
        """
        return self.displayBox

    def getResultBox(self):
        """
        获取结果显示控件
        :return: {@link QLabel}
        """
        return self.resultBox

    def clickedEvent(self, obj: QWidget):
        name = obj.objectName()
        if name == "dis":  # 最小化窗口
            print("dis is clicked.")
            self.setWindowState(Qt.WindowMinimized)
        elif name == "maxi":  # 最大化窗口点击事件
            print("maxi is clicked.")
        elif name == "close":  # 关闭窗口点击事件
            print("close is clicked.")
            self.close()
        elif name == "cameraIcon":
            print("cameraIcon is clicked.")
Пример #7
0
class CellSelection(Feature):
    def __init__(self, data, parent=None, liveplot=None):
        # Init Feature
        Feature.__init__(self,
                         'Cell Selection',
                         data,
                         parent,
                         liveplot,
                         display_name_label=False)

        self.data_manager = data
        self.data_manager.cell_selection = self

        self.setMinimumSize(350, 450)

        self.allowEditROI = True
        self.disabled_roi_handles = []
        self.preview_mode = True
        self.show_user_roi = False
        self.ellipse_mode = True
        self.update_on_ellipse_mode_change = True

        # data
        self.input = {'source': None, 'roi_ellipse_mode': None}
        self.output = {'cell': None, 'cell mean': None, 'roi': None}

        # view / plot
        self.imv = ImageView()
        self.imv.setMinimumHeight(450)
        self.layout.addWidget(self.imv)
        self.imv.view.mouseClickEvent = lambda ev: self.imvViewMouseClickEvent(
            self.imv.view, ev)
        self.imv.view.raiseContextMenu = lambda ev: self.imvViewRaiseContextMenu(
            self.imv.view, ev)
        self.imv.view.getContextMenus = lambda ev=None: self.imvViewGetContextMenus(
            self.imv.view, ev)

        self.imv.view.preview_mode = self.imv.view.menu.addAction(
            'live preview mode')
        self.imv.view.preview_mode.setCheckable(True)
        self.imv.view.preview_mode.setChecked(self.preview_mode)
        self.imv.view.preview_mode.triggered.connect(self.switchPreviewMode)

        self.imv.view.ellipse_mode = self.imv.view.menu.addAction(
            'ellipse mode')
        self.imv.view.ellipse_mode.setCheckable(True)
        self.imv.view.ellipse_mode.setChecked(self.ellipse_mode)
        self.connectEllipseMode()

        # methods
        self.addMethod('ROI', cs_roi_params, self.calculateROI)
        self.initMethodUI()
        self.initParametersUI()

        self.show()
        """
        the image must be displayed once such that the roicurve is created and can be shown
        even if the user loads a non-TIF source before he loads a TIF source.
        """
        self.imv.setImage(np.zeros((1, 10, 10)), xvals=np.arange(10))
        self.imv.clear()

    def show(self):
        Feature.show(self)
        self.refreshROIVisibleState()
        self.imv.getRoiPlot().enableAutoRange(axis=pg.ViewBox.XYAxes,
                                              enable=True)

    def refreshROIVisibleState(self):
        roi = self.methods['ROI'].getParametersGUI('roi')
        rect_roi = self.methods['ROI'].getParametersGUI('rect_roi')
        if not self.show_user_roi:
            if roi is not None:
                roi.hide()
            if rect_roi is not None:
                rect_roi.hide()
        elif self.ellipse_mode:
            if rect_roi is not None:
                rect_roi.hide()
        else:
            if roi is not None:
                roi.hide()

    def updateParametersUI(self):
        Feature.updateParametersUI(self)
        self.refreshROIVisibleState()

    def switchPreviewMode(self, checked):
        self.preview_mode = checked
        self.disconnectUserROISignals()
        self.connectUserROISignals()

    def connectEllipseMode(self):
        self.imv.view.ellipse_mode.triggered.connect(self.switchEllipseMode)

    def disconnectEllipseMode(self):
        try:
            self.imv.view.ellipse_mode.triggered.disconnect()
        except:
            pass

    def switchEllipseMode(self, checked):
        self.ellipse_mode = checked
        if self.ellipse_mode:
            show = 'roi'
            hide = 'rect_roi'
        else:
            show = 'rect_roi'
            hide = 'roi'
        self.methods['ROI'].getParametersGUI(show).show()
        self.methods['ROI'].getParametersGUI(hide).hide()
        if self.update_on_ellipse_mode_change:
            if not self.ellipse_mode:
                # if we just changed to rectangle mode: set angle to 0, pos and size and update graphics afterwards,
                # such that the pos and size are set correctly (rounded). but prevent calculation, because
                # setObjectAttributes does it
                pos, size, _ = self.methods['ROI'].parameters['roi']
                rect_roi = self.methods['ROI'].getParametersGUI('rect_roi')
                self.disconnectUserROISignals()
                rect_roi.setPos(pos)
                rect_roi.setSize(size)
                rect_roi.setAngle(0)
                self.connectUserROISignals()
                self.updateROI(prevent_calculation=True)
            self.data.setObjectAttributes(self.data.object_selection,
                                          {'ellipse_mode': self.ellipse_mode})

    def imvViewGetContextMenus(self, view, ev=None):
        return view.menu

    def imvViewRaiseContextMenu(self, view, ev):
        # return if we are not in user mode
        if not self.show_user_roi:
            return
        menu = view.getContextMenus()

        pos = ev.screenPos()
        menu.popup(QtCore.QPoint(pos.x(), pos.y()))
        return True

    def imvViewMouseClickEvent(self, view, ev):
        if ev.button() == QtCore.Qt.RightButton:
            if view.raiseContextMenu(ev):
                ev.accept()

    def initParametersUI(self):
        pos, size, angle = self.methods['ROI'].parameters['roi']
        pen = pg.mkPen(color=colors.alternative)
        roi = self.methods['ROI'].initROI(
            self.imv,
            pos,
            size,
            angle,
            pen,
            updateFunc=self.updateROIOnlyProcessed,
            releaseFunc=self.updateROIAll)
        roi.setZValue(20)
        pos = (math.floor(pos[0]), math.floor(pos[1]))
        size = (math.ceil(size[0]), math.ceil(size[1]))
        rect_roi = self.methods['ROI'].initRectROI(
            self.imv,
            pos,
            size,
            pen,
            updateFunc=self.updateROIOnlyProcessed,
            releaseFunc=self.updateROIAll)
        rect_roi.setZValue(20)
        rect_roi.hide()
        self.updateParametersUI()

    def inputConfiguration(self):
        source = self.input['source']
        if source is not None:
            if source.filetype == 'tif':
                if not np.array_equal(self.imv.image, source.getData()):
                    self.imv.setImage(source.getData(),
                                      xvals=source.frameRange())
                    self.imv.showPlot()
                    if not (source.start <= self.imv.timeLine.value() <=
                            source.end):
                        self.imv.timeLine.setValue(source.start)
                self.show_user_roi = True
            else:
                self.imv.clear()
                self.imv.showPlot()
                self.imv.roiCurve.setData(source.frameRange(),
                                          source.getData())
                self.imv.timeLine.hide()
                self.show_user_roi = False
                self.refreshROIVisibleState()
                self.imv.getRoiPlot().enableAutoRange(axis=pg.ViewBox.XYAxes,
                                                      enable=True)
            ellipse_mode = self.input['roi_ellipse_mode']
            if ellipse_mode is not None:
                # set attribute s.t. we do not update. the reason behind that is that inputConfiguration should never update.
                self.update_on_ellipse_mode_change = False
                self.disconnectEllipseMode()
                self.imv.view.ellipse_mode.setChecked(ellipse_mode)
                self.switchEllipseMode(ellipse_mode)
                self.connectEllipseMode()
                self.update_on_ellipse_mode_change = True
        else:
            self.imv.hidePlot()
            self.imv.clear()
            self.show_user_roi = False
            self.getUserROI().hide()

    def updateROIAll(self):
        self.updateROI(only_processed=False)

    def updateROIOnlyProcessed(self):
        self.updateROI(only_processed=True)

    def updateROI(self, only_processed=False, prevent_calculation=False):
        if self.ellipse_mode:
            ellipse_roi = self.methods['ROI'].getParametersGUI('roi')
            self.methods['ROI'].parameters['roi'] = (ellipse_roi.pos(),
                                                     ellipse_roi.size(),
                                                     ellipse_roi.angle())
        else:
            rect_roi = self.methods['ROI'].getParametersGUI('rect_roi')
            pos = rect_roi.pos()
            size = rect_roi.size()
            pos = (round(pos[0]), round(pos[1]))
            size = (round(size[0]), round(size[1]))
            self.methods['ROI'].parameters['roi'] = (pos, size, 0)

        if not prevent_calculation:
            self.update(
                stop_after_processing=only_processed and self.preview_mode)

    def calculateROI(self, source, roi_ellipse_mode, roi):
        if source.filetype == 'tif':

            img = self.imv.getProcessedImage()

            if roi_ellipse_mode:
                ellipse_roi = self.methods['ROI'].getParametersGUI('roi')
                pos, size, angle = self.methods['ROI'].parameters['roi']
                self.disconnectUserROISignals()
                ellipse_roi.setPos(pos)
                ellipse_roi.setSize(size)
                ellipse_roi.setAngle(angle)
                self.connectUserROISignals()
                cell = ellipse_roi.getArrayRegion(img.view(np.ndarray),
                                                  self.imv.imageItem,
                                                  axes=(1, 2))
            else:
                rect_roi = self.methods['ROI'].getParametersGUI('rect_roi')
                pos, size, _ = self.methods['ROI'].parameters['roi']
                self.disconnectUserROISignals()
                rect_roi.setPos(pos)
                rect_roi.setSize(size)
                rect_roi.setAngle(0)
                self.connectUserROISignals()
                _slice = rect_roi.getArraySlice(img.view(np.ndarray),
                                                self.imv.imageItem,
                                                axes=(1, 2))
                cell = img[_slice[0]]

            # Get ROI mean data
            cell_mean = cell.mean(axis=(1, 2))

            # read roi params out of saved params
            pos, size, angle = self.methods['ROI'].parameters['roi']

            return {
                'cell': cell,
                'cell mean': cell_mean,
                'roi': (cell_mean, pos, size, angle)
            }
        else:
            return {'cell': None, 'cell mean': None, 'roi': None}

    def editROI(self, roi_index):
        if self.allowEditROI and self.input['source'].filetype == 'tif':
            method = self.getMethod()
            pos, size, angle = method.parameters['roi']
            cell_mean = self.output['cell mean']
            cell = self.output['cell']
            edit_data = {
                'cell_mean': cell_mean,
                'cell': cell,
                'pos': pos,
                'angle': angle,
                'size': size
            }
            self.data_manager.setObjectAttributes(
                roi_index,
                edit_data,
                prevent_object_manager_refresh=True,
                prevent_roiview_refresh=True)

    def updateLivePlot(self):
        pass

    def getUserROI(self):
        param_name = 'roi' if self.ellipse_mode else 'rect_roi'
        return self.methods['ROI'].getParametersGUI(param_name)

    def disconnectUserROISignals(self):
        roi_view = self.getUserROI()
        try:
            roi_view.sigRegionChanged.disconnect()
        except:
            pass
        roi_view.sigRegionChangeFinished.disconnect()

    def connectUserROISignals(self):
        roi_view = self.getUserROI()
        if self.preview_mode:
            roi_view.sigRegionChanged.connect(self.updateROIOnlyProcessed)
        roi_view.sigRegionChangeFinished.connect(self.updateROIAll)
Пример #8
0
class MovementCorrectionDialog(QtWidgets.QDialog):
    """
    Dialog that shows the Movement Correction Feature.

    Dialog consists of:
    - the feature view (two ComboBoxes that control the ImageView content)
    - a control area (save as file, save and cancel button)
    - two ImageViews that show the correction and a comparison
    """
    def __init__(self, parent, data_manager):
        QtWidgets.QDialog.__init__(self,
                                   parent,
                                   flags=QtCore.Qt.WindowTitleHint
                                   | QtCore.Qt.WindowCloseButtonHint)

        self.setModal(True)
        self.setWindowTitle('Movement Correction')

        self.data_manager = data_manager
        self.last_confirmed_parameter = None

        layout = QtWidgets.QGridLayout()
        self.setLayout(layout)

        self.feature_view = QtWidgets.QWidget(self)
        self.feature_view.setMinimumWidth(290)

        self.controls = QtWidgets.QWidget(self)
        controls_layout = QtWidgets.QVBoxLayout()
        self.controls.setLayout(controls_layout)
        save_tif_btn = QtWidgets.QPushButton('Save Correction as File', self)
        save_tif_btn.clicked.connect(self.saveAsFile)
        save_btn = QtWidgets.QPushButton('Save Correction in NOSA', self)
        save_btn.clicked.connect(self.save)
        cancel_btn = QtWidgets.QPushButton('Cancel', self)
        cancel_btn.clicked.connect(self.cancel)
        controls_layout.addWidget(save_tif_btn)
        controls_layout.addWidget(save_btn)
        controls_layout.addWidget(cancel_btn)

        layout.addWidget(self.feature_view, 0, 0)
        layout.addWidget(self.controls, 0, 1)
        corrected_label = QtWidgets.QLabel('Corrected')
        corrected_label.setAlignment(QtCore.Qt.AlignHCenter)
        corrected_font = corrected_label.font()
        corrected_font.setPointSize(corrected_font.pointSize() + 8)
        corrected_label.setFont(corrected_font)
        layout.addWidget(corrected_label, 1, 0)
        compare_label = QtWidgets.QLabel('Compare')
        compare_label.setAlignment(QtCore.Qt.AlignHCenter)
        compare_font = compare_label.font()
        compare_font.setPointSize(compare_font.pointSize() + 8)
        compare_label.setFont(compare_font)
        layout.addWidget(compare_label, 1, 1)
        self.corrected_sublabel = QtWidgets.QLabel('')
        self.corrected_sublabel.setAlignment(QtCore.Qt.AlignHCenter)
        layout.addWidget(self.corrected_sublabel, 2, 0)
        self.compare_sublabel = QtWidgets.QLabel('')
        self.compare_sublabel.setAlignment(QtCore.Qt.AlignHCenter)
        layout.addWidget(self.compare_sublabel, 2, 1)

    def timeChanged(self, ind, time, plot):
        """
        Called when the index of an ImageView has changed.

        Sets the index of the other ImageView to the same.
        """
        if self.liveplot.getImageItem(
        ).image is None or self.compare_plot.getImageItem().image is None:
            return
        if plot == self.liveplot:
            self.compare_plot.setCurrentIndex(ind)
        else:
            self.liveplot.setCurrentIndex(ind)

    def show(self):
        """
        Closes (rejects) the Dialog (self) and returns if there is no source selected.

        If there is a source selected, the correct MovementCorrection Feature is shown, others are
        hidden. The ImageViews are created and connected with the Feature. The input of the Feature
        is set and Feature is updated such that the ImageViews are set.
        """
        QtWidgets.QDialog.show(self)

        if self.data_manager.source_selection is None:
            self.done(QtWidgets.QDialog.Rejected)
            return

        for i in range(len(self.data_manager.sources)):
            mc_ = self.data_manager.movement_corrections[i]
            if i == self.data_manager.source_selection:
                if mc_ is None:
                    self.done(QtWidgets.QDialog.Rejected)
                    return
                self.mc = mc_
                # self.mc.show() is called later! settings must be done first.
            else:
                if mc_ is not None:
                    mc_.hide()

        src = self.data_manager.sources[self.data_manager.source_selection]

        self.liveplot = ImageView(self)
        removeExportFromContextMenu(self.liveplot.scene.contextMenu)
        self.liveplot.setMinimumSize(300, 300)
        self.compare_plot = ImageView(self)
        removeExportFromContextMenu(self.compare_plot.scene.contextMenu)
        self.compare_plot.setMinimumSize(300, 300)
        self.liveplot.sigTimeChanged.connect(
            lambda ind, time, plot=self.liveplot: self.timeChanged(
                ind, time, plot))
        self.compare_plot.sigTimeChanged.connect(
            lambda ind, time, plot=self.compare_plot: self.timeChanged(
                ind, time, plot))
        self.layout().addWidget(self.liveplot, 3, 0)
        self.layout().addWidget(self.compare_plot, 3, 1)

        self.mc.liveplot = self.liveplot
        self.mc.compare_plot = self.compare_plot
        self.mc.correction_label = self.corrected_sublabel
        self.mc.compare_label = self.compare_sublabel

        self.mc.input['source'] = src
        self.mc.inputConfiguration()
        # we dont want to calculate the current correction (has not been changed)
        correction_ind = 0
        correction_string = self.mc.methods[
            'Movement Correction'].getParameters()['correction']
        for index, (option) in enumerate(self.mc.options):
            if correction_string == option[0]:
                correction_ind = index
                break
        if correction_ind != 0:
            self.mc.calculated[correction_ind] = src.getData()
        self.mc.show()
        self.mc.update(updateDependend=False)

        # save the parameter the mc has
        self.last_confirmed_parameter = correction_string

    def done(self, r):
        """
        Closes both ImageViews nicely.

        Clears the calculated list and the feature output.
        """
        self.compare_plot.close()
        self.liveplot.close()
        self.layout().removeWidget(self.compare_plot)
        self.layout().removeWidget(self.liveplot)

        self.mc.calculated = [None for _ in self.mc.calculated]
        self.mc.clearData()
        self.mc = None

        QtWidgets.QDialog.done(self, r)

    def save(self):
        """
        Does nothing if self is not visible.

        If self is visible, the corrected data of the currently selected source is set to the output of the 
        MovementCorrection Feature. The Dialog (self) is closed (accepted).
        All Pipelines for the source will be refreshed.
        """
        if self.isVisible():
            selected_source = self.data_manager.sources[
                self.data_manager.source_selection]
            selected_source.setCorrectedData(self.mc.output['source'])
            self.done(QtWidgets.QDialog.Accepted)
            object_indices_for_this_source = [
                i for i, o in enumerate(self.data_manager.objects)
                if o.source is selected_source
            ]
            for index in object_indices_for_this_source:
                # refresh pipeline for all objects belonging to the source. only make cc when refreshing the last pipeline.
                self.data_manager.refreshPipeline(
                    object_index=index,
                    start_with_feature=self.data_manager.cell_selection,
                    ignore_cross_correlation=index !=
                    max(object_indices_for_this_source))

    def cancel(self):
        """
        Does nothing if self is not visible.

        If self is visible, resets the parameter of the mc and closes (rejects) the Dialog (self).
        """
        if self.isVisible():
            self.mc.methods['Movement Correction'].parameters[
                'correction'] = self.last_confirmed_parameter
            self.done(QtWidgets.QDialog.Rejected)

    def saveAsFile(self):
        """
        Saves the corrected image sequence as a TIF. User has to choose a directory
        where to save the file.

        Does nothing if there is no correction.
        """
        if self.mc is None or not self.isVisible():
            return

        corrected = self.mc.output['source']

        if corrected is None:
            return

        filename, ok = QtWidgets.QFileDialog.getSaveFileName(
            self, 'Save Corrected as File', directory='', filter='(*.tiff)')
        if ok and filename.endswith('.tiff'):
            self.data_manager.progressDialog()
            self.data_manager.progress_dialog.setMinimum(0)
            self.data_manager.progress_dialog.setMaximum(0)

            def saveFileWork():
                tifffile.imwrite(filename, corrected, dtype=np.float32)

            def saveFileCallback():
                self.data_manager.progress_dialog.setMaximum(1)
                self.data_manager.progress_dialog.setValue(1)

            save_file_worker = Worker(work=saveFileWork,
                                      callback=saveFileCallback)

            QtCore.QThreadPool.globalInstance().start(save_file_worker)
Пример #9
0
    def show(self):
        """
        Closes (rejects) the Dialog (self) and returns if there is no source selected.

        If there is a source selected, the correct MovementCorrection Feature is shown, others are
        hidden. The ImageViews are created and connected with the Feature. The input of the Feature
        is set and Feature is updated such that the ImageViews are set.
        """
        QtWidgets.QDialog.show(self)

        if self.data_manager.source_selection is None:
            self.done(QtWidgets.QDialog.Rejected)
            return

        for i in range(len(self.data_manager.sources)):
            mc_ = self.data_manager.movement_corrections[i]
            if i == self.data_manager.source_selection:
                if mc_ is None:
                    self.done(QtWidgets.QDialog.Rejected)
                    return
                self.mc = mc_
                # self.mc.show() is called later! settings must be done first.
            else:
                if mc_ is not None:
                    mc_.hide()

        src = self.data_manager.sources[self.data_manager.source_selection]

        self.liveplot = ImageView(self)
        removeExportFromContextMenu(self.liveplot.scene.contextMenu)
        self.liveplot.setMinimumSize(300, 300)
        self.compare_plot = ImageView(self)
        removeExportFromContextMenu(self.compare_plot.scene.contextMenu)
        self.compare_plot.setMinimumSize(300, 300)
        self.liveplot.sigTimeChanged.connect(
            lambda ind, time, plot=self.liveplot: self.timeChanged(
                ind, time, plot))
        self.compare_plot.sigTimeChanged.connect(
            lambda ind, time, plot=self.compare_plot: self.timeChanged(
                ind, time, plot))
        self.layout().addWidget(self.liveplot, 3, 0)
        self.layout().addWidget(self.compare_plot, 3, 1)

        self.mc.liveplot = self.liveplot
        self.mc.compare_plot = self.compare_plot
        self.mc.correction_label = self.corrected_sublabel
        self.mc.compare_label = self.compare_sublabel

        self.mc.input['source'] = src
        self.mc.inputConfiguration()
        # we dont want to calculate the current correction (has not been changed)
        correction_ind = 0
        correction_string = self.mc.methods[
            'Movement Correction'].getParameters()['correction']
        for index, (option) in enumerate(self.mc.options):
            if correction_string == option[0]:
                correction_ind = index
                break
        if correction_ind != 0:
            self.mc.calculated[correction_ind] = src.getData()
        self.mc.show()
        self.mc.update(updateDependend=False)

        # save the parameter the mc has
        self.last_confirmed_parameter = correction_string