Beispiel #1
0
class AreaEditWidget(TransparentWidget):

    # add a signal that emits the area selected
    areaSelected = Signal(QRect)
    areaRemoved = Signal(QPoint)

    def __init__(self, parent=None):
        super().__init__(opacity=0.25)
        # select area
        self.rubberband = QRubberBand(QRubberBand.Rectangle, self)
        # coords of mouse click
        self.origin = QPoint()

    def mousePressEvent(self, event):
        # left click starts the rubber band
        if event.button() == Qt.LeftButton:
            self.origin = QPoint(event.pos())
            self.rubberband.setGeometry(QRect(self.origin, QSize()))
            self.rubberband.show()
        # right click on a selected area to remove it
        if event.button() == Qt.RightButton:
            self.areaRemoved.emit(event.pos())

    def mouseMoveEvent(self, event):
        if not self.origin.isNull():
            self.rubberband.setGeometry(
                QRect(self.origin, event.pos()).normalized())

    def mouseReleaseEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.rubberband.hide()
            area_selected = self.rubberband.geometry()
            self.areaSelected.emit(area_selected)
Beispiel #2
0
class myQVideoWidget(QVideoWidget):
    def __init__(self):
        super(myQVideoWidget, self).__init__()
        self.select_flag = False
        self.rubberband = QRubberBand(QRubberBand.Line, self)
        self.x0 = 0
        self.y0 = 0
        self.x1 = 0
        self.y1 = 0

    def select_on(self):
        self.x0 = 0
        self.y0 = 0
        self.x1 = 0
        self.y1 = 0
        self.select_flag = True

    def select_off(self):
        self.x0 = 0
        self.y0 = 0
        self.x1 = 0
        self.y1 = 0
        self.rubberband.hide()
        self.select_flag = False

    def mousePressEvent(self, event):
        if self.select_flag:
            self.origin = event.pos()
            self.x0 = event.x()
            self.y0 = event.y()
            self.rubberband.setGeometry(QRect(self.origin, QSize()))
            self.rubberband.show()

    def mouseMoveEvent(self, event):
        if self.select_flag:
            self.rubberband.setGeometry(QRect(self.origin, event.pos()))

    def mouseReleaseEvent(self, event):
        if self.select_flag:
            self.x1 = event.x()
            self.y1 = event.y()
            self.cut_window(self.x0, self.y0, abs(self.x1 - self.x0),
                            abs(self.y1 - self.y0))
            #self.rubberband.hide()

    def cut_window(self, x0, y0, wide, high):
        pqscreen = QGuiApplication.primaryScreen()
        pixmap2 = pqscreen.grabWindow(self.winId(), x0, y0, wide, high)
        pixmap2.save('pridict.png')
Beispiel #3
0
class Scrot(QWidget):

    scrotFinished = Signal(QPixmap)

    def __init__(self, parent: QWidget = None):
        super(Scrot, self).__init__(parent=parent)
        self.rubberBand: QRubberBand = None
        self.origin: QPoint = QPoint()
        self.screen = QApplication.primaryScreen()
        self.setWindowOpacity(0.1)

    def mousePressEvent(self, event: QMouseEvent):
        self.origin = event.pos()
        if self.rubberBand is None:
            self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
        self.rubberBand.setGeometry(QRect(self.origin, QSize()))
        self.rubberBand.show()

    def mouseMoveEvent(self, event: QMouseEvent):
        if self.rubberBand is not None:
            self.rubberBand.setGeometry(
                QRect(self.origin, event.pos()).normalized())

    def mouseReleaseEvent(self, event: QMouseEvent):
        if self.rubberBand is not None:
            self.rubberBand.hide()
            self.close()
            time.sleep(0.6)
            rect = (min(self.origin.x(),
                        event.x()), min(self.origin.y(), event.y()),
                    abs(event.x() - self.origin.x()),
                    abs(event.y() - self.origin.y()))
            screenShot = self.screen.grabWindow(QApplication.desktop().winId(),
                                                *rect)
            self.scrotFinished.emit(screenShot)

    def run(self):
        self.showFullScreen()
Beispiel #4
0
class PlotImage(FigureCanvas):
    def __init__(self, model, parent, main_window):

        self.figure = Figure(dpi=main_window.logicalDpiX())
        super().__init__(self.figure)

        FigureCanvas.setSizePolicy(self, QSizePolicy.Expanding,
                                   QSizePolicy.Expanding)

        FigureCanvas.updateGeometry(self)
        self.model = model
        self.main_window = main_window
        self.parent = parent

        self.rubber_band = QRubberBand(QRubberBand.Rectangle, self)
        self.band_origin = QtCore.QPoint()
        self.x_plot_origin = None
        self.y_plot_origin = None

        self.colorbar = None
        self.data_indicator = None
        self.tally_data_indicator = None
        self.image = None

        self.menu = QMenu(self)

    def enterEvent(self, event):
        self.setCursor(QtCore.Qt.CrossCursor)
        self.main_window.coord_label.show()

    def leaveEvent(self, event):
        self.main_window.coord_label.hide()
        self.main_window.statusBar().showMessage("")

    def mousePressEvent(self, event):
        self.main_window.coord_label.hide()
        position = event.pos()
        # Set rubber band absolute and relative position
        self.band_origin = position
        self.x_plot_origin, self.y_plot_origin = self.getPlotCoords(position)

        # Create rubber band
        self.rubber_band.setGeometry(
            QtCore.QRect(self.band_origin, QtCore.QSize()))

    def getPlotCoords(self, pos):
        x, y = self.mouseEventCoords(pos)

        # get the normalized axis coordinates from the event display units
        transform = self.ax.transAxes.inverted()
        xPlotCoord, yPlotCoord = transform.transform((x, y))
        # flip the y-axis (its zero is in the upper left)

        # scale axes using the plot extents
        xPlotCoord = self.ax.dataLim.x0 + xPlotCoord * self.ax.dataLim.width
        yPlotCoord = self.ax.dataLim.y0 + yPlotCoord * self.ax.dataLim.height

        # set coordinate label if pointer is in the axes
        if self.parent.underMouse():
            self.main_window.coord_label.show()
            self.main_window.showCoords(xPlotCoord, yPlotCoord)
        else:
            self.main_window.coord_label.hide()

        return (xPlotCoord, yPlotCoord)

    def _resize(self):
        z = self.main_window.zoom / 100.0
        # manage scroll bars
        if z <= 1.0:
            self.parent.verticalScrollBar().hide()
            self.parent.horizontalScrollBar().hide()
            self.parent.cornerWidget().hide()
            self.parent.verticalScrollBar().setEnabled(False)
            self.parent.horizontalScrollBar().setEnabled(False)
        else:
            self.parent.verticalScrollBar().show()
            self.parent.horizontalScrollBar().show()
            self.parent.cornerWidget().show()
            self.parent.verticalScrollBar().setEnabled(True)
            self.parent.horizontalScrollBar().setEnabled(True)

        # resize plot
        self.resize(self.parent.width() * z, self.parent.height() * z)

    def getDataIndices(self, event):
        cv = self.model.currentView

        x, y = self.mouseEventCoords(event.pos())

        # get origin in axes coordinates
        x0, y0 = self.ax.transAxes.transform((0.0, 0.0))

        # get the extents of the axes box in axes coordinates
        bbox = self.ax.get_window_extent().transformed(
            self.figure.dpi_scale_trans.inverted())
        # get dimensions and scale using dpi
        width, height = bbox.width, bbox.height
        width *= self.figure.dpi
        height *= self.figure.dpi

        # use factor to get proper x,y position in pixels
        factor = (width / cv.h_res, height / cv.v_res)
        xPos = int((x - x0 + 0.01) / factor[0])
        # flip y-axis
        yPos = cv.v_res - int((y - y0 + 0.01) / factor[1])

        return xPos, yPos

    def getTallyIndices(self, event):

        xPos, yPos = self.getPlotCoords(event.pos())

        ext = self.model.tally_extents

        x0 = ext[0]
        y0 = ext[2]

        v_res, h_res = self.model.tally_data.shape

        dx = (ext[1] - ext[0]) / h_res
        dy = (ext[3] - ext[2]) / v_res

        i = int((xPos - x0) // dx)
        j = v_res - int((yPos - y0) // dy) - 1

        return i, j

    def getTallyInfo(self, event):
        cv = self.model.currentView

        xPos, yPos = self.getTallyIndices(event)

        if self.model.tally_data is None:
            return -1, None

        if not cv.selectedTally or not cv.tallyDataVisible:
            return -1, None

        # don't look up mesh filter data (for now)
        tally = self.model.statepoint.tallies[cv.selectedTally]

        # check that the position is in the axes view
        v_res, h_res = self.model.tally_data.shape
        if 0 <= yPos < v_res and 0 <= xPos < h_res:
            value = self.model.tally_data[yPos][xPos]
        else:
            value = None

        return cv.selectedTally, value

    def getIDinfo(self, event):

        xPos, yPos = self.getDataIndices(event)

        # check that the position is in the axes view
        if 0 <= yPos < self.model.currentView.v_res \
           and 0 <= xPos and xPos < self.model.currentView.h_res:
            id = self.model.ids[yPos][xPos]
            temp = "{:g}".format(self.model.properties[yPos][xPos][0])
            density = "{:g}".format(self.model.properties[yPos][xPos][1])
        else:
            id = _NOT_FOUND
            density = str(_NOT_FOUND)
            temp = str(_NOT_FOUND)

        if self.model.currentView.colorby == 'cell':
            domain = self.model.activeView.cells
            domain_kind = 'Cell'
        elif self.model.currentView.colorby == 'temperature':
            domain = self.model.activeView.materials
            domain_kind = 'Temperature'
        elif self.model.currentView.colorby == 'density':
            domain = self.model.activeView.materials
            domain_kind = 'Density'
        else:
            domain = self.model.activeView.materials
            domain_kind = 'Material'

        properties = {'density': density, 'temperature': temp}

        return id, properties, domain, domain_kind

    def mouseDoubleClickEvent(self, event):
        xCenter, yCenter = self.getPlotCoords(event.pos())
        self.main_window.editPlotOrigin(xCenter, yCenter, apply=True)

    def mouseMoveEvent(self, event):
        cv = self.model.currentView
        # Show Cursor position relative to plot in status bar
        xPlotPos, yPlotPos = self.getPlotCoords(event.pos())

        # Show Cell/Material ID, Name in status bar
        id, properties, domain, domain_kind = self.getIDinfo(event)

        domainInfo = ""
        tallyInfo = ""

        if self.parent.underMouse():

            if domain_kind.lower() in _MODEL_PROPERTIES:
                line_val = float(properties[domain_kind.lower()])
                line_val = max(line_val, 0.0)
                self.updateDataIndicatorValue(line_val)
                domain_kind = 'Material'

            temperature = properties['temperature']
            density = properties['density']

            if id == _VOID_REGION:
                domainInfo = ("VOID")
            elif id == _OVERLAP:
                domainInfo = ("OVERLAP")
            elif id != _NOT_FOUND and domain[id].name:
                domainInfo = ("{} {}: \"{}\"\t Density: {} g/cc\t"
                              "Temperature: {} K".format(
                                  domain_kind, id, domain[id].name, density,
                                  temperature))
            elif id != _NOT_FOUND:
                domainInfo = ("{} {}\t Density: {} g/cc\t"
                              "Temperature: {} K".format(
                                  domain_kind, id, density, temperature))
            else:
                domainInfo = ""

            if self.model.tally_data is not None:
                tid, value = self.getTallyInfo(event)
                if value is not None and value != np.nan:
                    self.updateTallyDataIndicatorValue(value)
                    tallyInfo = "Tally {} {}: {:.5E}".format(
                        tid, cv.tallyValue, value)
                else:
                    self.updateTallyDataIndicatorValue(0.0)
        else:
            self.updateTallyDataIndicatorValue(0.0)
            self.updateDataIndicatorValue(0.0)

        if domainInfo:
            self.main_window.statusBar().showMessage(" " + domainInfo +
                                                     "      " + tallyInfo)
        else:
            self.main_window.statusBar().showMessage(" " + tallyInfo)

        # Update rubber band and values if mouse button held down
        if event.buttons() == QtCore.Qt.LeftButton:
            self.rubber_band.setGeometry(
                QtCore.QRect(self.band_origin, event.pos()).normalized())

            # Show rubber band if both dimensions > 10 pixels
            if self.rubber_band.width() > 10 and self.rubber_band.height(
            ) > 10:
                self.rubber_band.show()
            else:
                self.rubber_band.hide()

            # Update plot X Origin
            xCenter = (self.x_plot_origin + xPlotPos) / 2
            yCenter = (self.y_plot_origin + yPlotPos) / 2
            self.main_window.editPlotOrigin(xCenter, yCenter)

            modifiers = event.modifiers()

            # Zoom out if Shift held
            if modifiers == QtCore.Qt.ShiftModifier:
                cv = self.model.currentView
                bandwidth = abs(self.band_origin.x() - event.pos().x())
                width = cv.width * (cv.h_res / max(bandwidth, .001))
                bandheight = abs(self.band_origin.y() - event.pos().y())
                height = cv.height * (cv.v_res / max(bandheight, .001))
            # Zoom in
            else:
                width = max(abs(self.x_plot_origin - xPlotPos), 0.1)
                height = max(abs(self.y_plot_origin - yPlotPos), 0.1)

            self.main_window.editWidth(width)
            self.main_window.editHeight(height)

    def mouseReleaseEvent(self, event):

        if self.rubber_band.isVisible():
            self.rubber_band.hide()
            self.main_window.applyChanges()
        else:
            self.main_window.revertDockControls()

    def wheelEvent(self, event):

        if event.delta() and event.modifiers() == QtCore.Qt.ShiftModifier:
            numDegrees = event.delta() / 8

            if 24 < self.main_window.zoom + numDegrees < 5001:
                self.main_window.editZoom(self.main_window.zoom + numDegrees)

    def contextMenuEvent(self, event):

        self.menu.clear()

        self.main_window.undoAction.setText('&Undo ({})'.format(
            len(self.model.previousViews)))
        self.main_window.redoAction.setText('&Redo ({})'.format(
            len(self.model.subsequentViews)))

        id, properties, domain, domain_kind = self.getIDinfo(event)

        cv = self.model.currentView

        # always provide undo option
        self.menu.addSeparator()
        self.menu.addAction(self.main_window.undoAction)
        self.menu.addAction(self.main_window.redoAction)
        self.menu.addSeparator()

        if int(id) not in (_NOT_FOUND, _OVERLAP) and \
           cv.colorby not in _MODEL_PROPERTIES:

            # Domain ID
            if domain[id].name:
                domainID = self.menu.addAction("{} {}: \"{}\"".format(
                    domain_kind, id, domain[id].name))
            else:
                domainID = self.menu.addAction("{} {}".format(domain_kind, id))

            self.menu.addSeparator()

            colorAction = self.menu.addAction(
                'Edit {} Color...'.format(domain_kind))
            colorAction.setDisabled(cv.highlighting)
            colorAction.setToolTip('Edit {} color'.format(domain_kind))
            colorAction.setStatusTip('Edit {} color'.format(domain_kind))
            domain_color_connector = partial(self.main_window.editDomainColor,
                                             domain_kind, id)
            colorAction.triggered.connect(domain_color_connector)

            maskAction = self.menu.addAction('Mask {}'.format(domain_kind))
            maskAction.setCheckable(True)
            maskAction.setChecked(domain[id].masked)
            maskAction.setDisabled(not cv.masking)
            maskAction.setToolTip('Toggle {} mask'.format(domain_kind))
            maskAction.setStatusTip('Toggle {} mask'.format(domain_kind))
            mask_connector = partial(self.main_window.toggleDomainMask,
                                     kind=domain_kind,
                                     id=id)
            maskAction.toggled.connect(mask_connector)

            highlightAction = self.menu.addAction(
                'Highlight {}'.format(domain_kind))
            highlightAction.setCheckable(True)
            highlightAction.setChecked(domain[id].highlight)
            highlightAction.setDisabled(not cv.highlighting)
            highlightAction.setToolTip(
                'Toggle {} highlight'.format(domain_kind))
            highlightAction.setStatusTip(
                'Toggle {} highlight'.format(domain_kind))
            highlight_connector = partial(
                self.main_window.toggleDomainHighlight,
                kind=domain_kind,
                id=id)
            highlightAction.toggled.connect(highlight_connector)

        else:
            self.menu.addAction(self.main_window.undoAction)
            self.menu.addAction(self.main_window.redoAction)

            if cv.colorby not in _MODEL_PROPERTIES:
                self.menu.addSeparator()
                if int(id) == _NOT_FOUND:
                    bgColorAction = self.menu.addAction(
                        'Edit Background Color...')
                    bgColorAction.setToolTip('Edit background color')
                    bgColorAction.setStatusTip('Edit plot background color')
                    connector = partial(self.main_window.editBackgroundColor,
                                        apply=True)
                    bgColorAction.triggered.connect(connector)
                elif int(id) == _OVERLAP:
                    olapColorAction = self.menu.addAction(
                        'Edit Overlap Color...')
                    olapColorAction.setToolTip('Edit overlap color')
                    olapColorAction.setStatusTip('Edit plot overlap color')
                    connector = partial(self.main_window.editOverlapColor,
                                        apply=True)
                    olapColorAction.triggered.connect(connector)

        self.menu.addSeparator()
        self.menu.addAction(self.main_window.saveImageAction)
        self.menu.addAction(self.main_window.saveViewAction)
        self.menu.addAction(self.main_window.openAction)
        self.menu.addSeparator()
        self.menu.addMenu(self.main_window.basisMenu)
        self.menu.addMenu(self.main_window.colorbyMenu)
        self.menu.addSeparator()
        if domain_kind.lower() not in ('density', 'temperature'):
            self.menu.addAction(self.main_window.maskingAction)
            self.menu.addAction(self.main_window.highlightingAct)
            self.menu.addAction(self.main_window.overlapAct)
            self.menu.addSeparator()
        self.menu.addAction(self.main_window.dockAction)

        self.main_window.maskingAction.setChecked(cv.masking)
        self.main_window.highlightingAct.setChecked(cv.highlighting)
        self.main_window.overlapAct.setChecked(cv.color_overlaps)

        if self.main_window.dock.isVisible():
            self.main_window.dockAction.setText('Hide &Dock')
        else:
            self.main_window.dockAction.setText('Show &Dock')

        self.menu.exec_(event.globalPos())

    def generatePixmap(self, update=False):
        self.model.generatePlot()
        if update:
            self.updatePixmap()

    def updatePixmap(self):

        # clear out figure
        self.figure.clear()

        cv = self.model.currentView
        # set figure bg color to match window
        window_bg = self.parent.palette().color(QtGui.QPalette.Background)
        self.figure.patch.set_facecolor(rgb_normalize(window_bg.getRgb()))

        # set data extents for automatic reporting of pointer location
        # in model units
        data_bounds = [
            cv.origin[self.main_window.xBasis] - cv.width / 2.,
            cv.origin[self.main_window.xBasis] + cv.width / 2.,
            cv.origin[self.main_window.yBasis] - cv.height / 2.,
            cv.origin[self.main_window.yBasis] + cv.height / 2.
        ]

        # make sure we have a domain image to load
        if not hasattr(self.model, 'image'):
            self.model.generatePlot()

        ### DRAW DOMAIN IMAGE ###

        # still generate the domain image if the geometric
        # plot isn't visible so mouse-over info can still
        # be shown
        alpha = cv.domainAlpha if cv.domainVisible else 0.0
        if cv.colorby in ('material', 'cell'):
            self.image = self.figure.subplots().imshow(self.model.image,
                                                       extent=data_bounds,
                                                       alpha=alpha)
        else:
            cmap = cv.colormaps[cv.colorby]
            if cv.colorby == 'temperature':
                idx = 0
                cmap_label = "Temperature (K)"
            else:
                idx = 1
                cmap_label = "Density (g/cc)"

            norm = SymLogNorm(1E-10) if cv.color_scale_log[
                cv.colorby] else None

            data = self.model.properties[:, :, idx]
            self.image = self.figure.subplots().imshow(data,
                                                       cmap=cmap,
                                                       norm=norm,
                                                       extent=data_bounds,
                                                       alpha=cv.domainAlpha)

            # add colorbar
            self.colorbar = self.figure.colorbar(self.image, anchor=(1.0, 0.0))
            self.colorbar.set_label(cmap_label, rotation=-90, labelpad=15)
            # draw line on colorbar
            dl = self.colorbar.ax.dataLim.get_points()
            self.data_indicator = mlines.Line2D(dl[:][0], [0.0, 0.0],
                                                linewidth=3.,
                                                color='blue',
                                                clip_on=True)
            self.colorbar.ax.add_line(self.data_indicator)
            self.colorbar.ax.margins(0.0, 0.0)
            self.updateDataIndicatorVisibility()
            self.updateColorMinMax(cv.colorby)

        self.ax = self.figure.axes[0]
        self.ax.margins(0.0, 0.0)

        # set axis labels
        axis_label_str = "{} (cm)"
        self.ax.set_xlabel(axis_label_str.format(cv.basis[0]))
        self.ax.set_ylabel(axis_label_str.format(cv.basis[1]))

        # generate tally image
        image_data, extents, data_min, data_max, units = self.model.create_tally_image(
        )

        ### DRAW TALLY IMAGE ###

        # draw tally image
        if image_data is not None:

            if not cv.tallyDataUserMinMax:
                cv.tallyDataMin = data_min
                cv.tallyDataMax = data_max
            else:
                data_min = cv.tallyDataMin
                data_max = cv.tallyDataMax

            # always mask out negative values
            image_mask = image_data < 0.0

            if cv.clipTallyData:
                image_mask |= image_data < data_min
                image_mask |= image_data > data_max

            if cv.tallyMaskZeroValues:
                image_mask |= image_data == 0.0

            # mask out invalid values
            image_data = np.ma.masked_where(image_mask, image_data)

            if extents is None:
                extents = data_bounds

            self.model.tally_data = image_data
            self.model.tally_extents = extents if extents is not None else data_bounds

            norm = SymLogNorm(1E-30) if cv.tallyDataLogScale else None

            if cv.tallyContours:
                # parse the levels line
                levels = self.parseContoursLine(cv.tallyContourLevels)
                self.tally_image = self.ax.contour(image_data,
                                                   origin='image',
                                                   levels=levels,
                                                   alpha=cv.tallyDataAlpha,
                                                   cmap=cv.tallyDataColormap,
                                                   norm=norm,
                                                   extent=extents)

            else:
                self.tally_image = self.ax.imshow(image_data,
                                                  alpha=cv.tallyDataAlpha,
                                                  cmap=cv.tallyDataColormap,
                                                  norm=norm,
                                                  extent=extents)
            # add colorbar
            self.tally_colorbar = self.figure.colorbar(self.tally_image,
                                                       anchor=(1.0, 0.0))

            if cv.tallyContours:
                fmt = "%.2E"
                self.ax.clabel(self.tally_image,
                               self.tally_image.levels,
                               inline=True,
                               fmt=fmt)

            # draw line on colorbar
            self.tally_data_indicator = mlines.Line2D([0.0, 1.0], [0.0, 0.0],
                                                      linewidth=3.,
                                                      color='blue',
                                                      clip_on=True)
            self.tally_colorbar.ax.add_line(self.tally_data_indicator)
            self.tally_colorbar.ax.margins(0.0, 0.0)

            self.tally_data_indicator.set_visible(cv.tallyDataIndicator)

            self.main_window.updateTallyMinMax()

            self.tally_colorbar.mappable.set_clim(data_min, data_max)
            self.tally_colorbar.set_label(units, rotation=-90, labelpad=15)

        # annotate outlines
        self.add_outlines()

        # always make sure the data bounds are set correctly
        self.ax.set_xbound(data_bounds[0], data_bounds[1])
        self.ax.set_ybound(data_bounds[2], data_bounds[3])
        self.ax.dataLim.x0 = data_bounds[0]
        self.ax.dataLim.x1 = data_bounds[1]
        self.ax.dataLim.y0 = data_bounds[2]
        self.ax.dataLim.y1 = data_bounds[3]

        self.draw()
        return "Done"

    def add_outlines(self):
        cv = self.model.currentView
        # draw outlines as isocontours
        if cv.outlines:
            # set data extents for automatic reporting of pointer location
            data_bounds = [
                cv.origin[self.main_window.xBasis] - cv.width / 2.,
                cv.origin[self.main_window.xBasis] + cv.width / 2.,
                cv.origin[self.main_window.yBasis] - cv.height / 2.,
                cv.origin[self.main_window.yBasis] + cv.height / 2.
            ]
            levels = np.unique(self.model.ids)
            self.contours = self.ax.contour(self.model.ids,
                                            origin='upper',
                                            colors='k',
                                            linestyles='solid',
                                            levels=levels,
                                            extent=data_bounds)

    @staticmethod
    def parseContoursLine(line):
        # if there are any commas in the line, treat as level values
        line = line.strip()
        if ',' in line:
            return [float(val) for val in line.split(",") if val != '']
        else:
            return int(line)

    def updateColorbarScale(self):
        self.updatePixmap()

    def updateTallyDataIndicatorValue(self, y_val):
        cv = self.model.currentView

        if not cv.tallyDataVisible or not cv.tallyDataIndicator:
            return

        if self.tally_data_indicator is not None:
            data = self.tally_data_indicator.get_data()
            # use norm to get axis value if log scale
            if cv.tallyDataLogScale:
                y_val = self.tally_image.norm(y_val)
            self.tally_data_indicator.set_data([data[0], [y_val, y_val]])
            dl_color = invert_rgb(self.tally_image.get_cmap()(y_val), True)
            self.tally_data_indicator.set_c(dl_color)
            self.draw()

    def updateDataIndicatorValue(self, y_val):
        cv = self.model.currentView

        if cv.colorby not in _MODEL_PROPERTIES or \
           not cv.data_indicator_enabled[cv.colorby]:
            return

        if self.data_indicator:
            data = self.data_indicator.get_data()
            # use norm to get axis value if log scale
            if cv.color_scale_log[cv.colorby]:
                y_val = self.image.norm(y_val)
            self.data_indicator.set_data([data[0], [y_val, y_val]])
            dl_color = invert_rgb(self.image.get_cmap()(y_val), True)
            self.data_indicator.set_c(dl_color)
            self.draw()

    def updateDataIndicatorVisibility(self):
        cv = self.model.currentView
        if self.data_indicator and cv.colorby in _MODEL_PROPERTIES:
            val = cv.data_indicator_enabled[cv.colorby]
            self.data_indicator.set_visible(val)
            self.draw()

    def updateColorMap(self, colormap_name, property_type):
        if self.colorbar and property_type == self.model.activeView.colorby:
            self.image.set_cmap(colormap_name)
            self.colorbar.draw_all()
            self.draw()

    def updateColorMinMax(self, property_type):
        av = self.model.activeView
        if self.colorbar and property_type == av.colorby:
            clim = av.getColorLimits(property_type)
            self.colorbar.mappable.set_clim(*clim)
            self.data_indicator.set_data(clim[:2], (0.0, 0.0))
            self.colorbar.draw_all()
            self.draw()
Beispiel #5
0
class MainGui(QWidget):
    def __init__(self):
        super(MainGui, self).__init__()
        self.config = ('-l eng --oem 1 --psm 3')
        pytesseract.pytesseract.tesseract_cmd = r"C:\Users\test\AppData\Local\Tesseract-OCR\tesseract.exe"
        self.screenshot_path = take_screenshot()
        self.widget_image = QImage(self.screenshot_path)
        palette = QPalette()
        palette.setBrush(QPalette.Window, QBrush(self.widget_image))
        self.setPalette(palette)
        self.edit_box = QTextEdit()
        self.v_box = QVBoxLayout()
        self.edit_box.hide()
        self.v_box.addWidget(self.edit_box)
        self.setLayout(self.v_box)
        # self.set_window_properties()

    def set_window_properties(self):
        self.setWindowFlags(Qt.CustomizeWindowHint)

    def mousePressEvent(self, eventQMouseEvent):
        self.originQPoint = eventQMouseEvent.pos()
        self.currentQRubberBand = QRubberBand(QRubberBand.Rectangle, self)
        self.currentQRubberBand.setGeometry(QRect(self.originQPoint, QSize()))
        self.edit_box.hide()
        self.currentQRubberBand.show()

    def mouseMoveEvent(self, eventQMouseEvent):
        self.currentQRubberBand.setGeometry(QRect(self.originQPoint, eventQMouseEvent.pos()).normalized())

    def mouseReleaseEvent(self, eventQMouseEvent):
        self.currentQRubberBand.hide()
        selected_area = self.currentQRubberBand.geometry()
        self.currentQRubberBand.deleteLater()
        crop_save_path = self.crop_selected_area(selected_area)
        self.set_edit_box_ui(crop_save_path, selected_area)

    def crop_selected_area(self, selected_area):
        crop_image = QPixmap(self.widget_image).copy(selected_area)
        save_name = "selected_shot.jpg"
        crop_save_path = os.path.join("temp", save_name)
        crop_image.save(crop_save_path)
        return crop_save_path

    def set_edit_box_ui(self, crop_save_path: str, selected_area: QRect):
        s2 = os.path.join(os.getcwd(), crop_save_path).replace("\\", "/")
        self.edit_box. setStyleSheet(f'background-image: url({s2});border: 0px;font: 11pt "Calibri"')
        self.edit_box.setReadOnly(True)
        self.edit_box.show()
        self.edit_box.setGeometry(selected_area)
        self.set_text(crop_save_path)

    def set_text(self, file):
        text = self.get_text(file)
        self.edit_box.setText(text)
        self.edit_box.setFocus()
        self.edit_box.selectAll()

    def closeEvent(self, event: QCloseEvent):
        os.remove(self.screenshot_path)

    def get_text(self, file):
        im = cv2.imread(file, 0)
        return pytesseract.image_to_string(im, config=self.config)
class colorChooser(QGraphicsPixmapItem):
    """
    Color wheel wrapper : it is a 2D slider-like
    providing color selection from the wheel and
    rubber band selection from a grid
    of activeNode objects moving over the wheel.
    """
    def __init__(self, cModel, QImg, target=None, size=0, border=0):
        """
        @param cModel: color model
        @type cModel: cmConverter
        @param QImg: color wheel
        @type QImg: vImage
        @param target: image to sample
        @type target: QImage
        @param size: color wheel diameter
        @type size: integer
        @param border: border size
        @type border: int
        """
        self.QImg = QImg  # not a back link !!!
        self.border = border
        if size == 0:
            self.size = min(QImg.width(), QImg.heigth()) - 2 * border
        else:
            self.size = size
        self.origin = 0
        # calculate target histogram
        self.targetHist = None
        if target is not None:
            # convert to current color space
            hsxImg = cModel.rgb2cmVec(QImageBuffer(target)[:, :, :3][:, :, ::-1])
            # get polar coordinates relative to the color wheel
            xyarray = self.QImg.GetPointVec(hsxImg).astype(int)
            maxVal = self.QImg.width()
            STEP = 10
            # build 2D histogram for xyarray
            H, xedges, yedges = np.histogram2d(xyarray[:, :, 0].ravel(), xyarray[:,:,1].ravel(),
                                               bins=[np.arange(0, maxVal+STEP, STEP), np.arange(0, maxVal + STEP, STEP)],
                                               normed=True)
            w,h = QImg.width(), QImg.height()
            b = QImage(w, h, QImage.Format_ARGB32)
            b.fill(0)
            buf = QImageBuffer(b)
            # set the transparency of each pixel
            # proportionally to the height of its bin
            # get bin indices (u, v)
            u = xyarray[:,:,0] // STEP
            v = xyarray[:,:,1] // STEP
            # get heights of bins
            tmp = H[u,v]
            norma = np.amax(H)
            # color white
            buf[xyarray[:,:,1], xyarray[:,:,0],...] = 255
            # alpha channel
            buf[xyarray[:, :, 1], xyarray[:, :, 0], 3] = 90 + 128.0 * tmp / norma
            self.targetHist = b
            self.showTargetHist = False
        super().__init__(self.QImg.rPixmap)
        self.setPixmap(self.QImg.rPixmap)
        self.setOffset(QPointF(-border, -border))
        self.onMouseRelease = lambda p, x, y, z: 0
        self.rubberBand = None

    def setPixmap(self, pxmap):
        """
        Paints the histogram on a copy of pxmap
        and displays the copy.
        @param pxmap:
        @type pxmap: QPixmap
        """
        if self.targetHist is not None and self.showTargetHist:
            pxmap1 = QPixmap(pxmap)
            qp = QPainter(pxmap1)
            qp.drawImage(0, 0, self.targetHist)
            qp.end()
            pxmap = pxmap1
        super().setPixmap(pxmap)

    def updatePixmap(self):
        """
        Convenience method
        """
        self.setPixmap(self.QImg.rPixmap)

    def mousePressEvent(self, e):
        if e.button() == Qt.RightButton:
            return
        self.origin = e.screenPos()
        if self.rubberBand is None:
            self.rubberBand = QRubberBand(QRubberBand.Rectangle, parent=None)
        self.rubberBand.setGeometry(QRect(self.origin, QSize()))
        self.rubberBand.show()

    def mouseMoveEvent(self, e):
        self.rubberBand.setGeometry(QRect(self.origin, e.screenPos()).normalized())

    def mouseReleaseEvent(self, e):
        # rubberBand selection
        if e.button() == Qt.RightButton:
            return
        self.rubberBand.hide()
        grid = self.scene().grid
        screenOrigin = e.screenPos() - e.pos().toPoint()
        rubberRect = QRect(self.origin, e.screenPos()).normalized()
        for i in range(grid.size):
            for j in range(grid.size):
                if rubberRect.contains((grid.gridNodes[i][j].pos() + screenOrigin).toPoint()):
                    grid.gridNodes[i][j].setSelected(True)
                else:
                    if type(grid.gridNodes[i][j].parentItem()) is nodeGroup:
                        grid.gridNodes[i][j].parentItem().setSelected(False)
                    grid.gridNodes[i][j].setSelected(False)
        # pick color from self.QImg
        p = e.pos().toPoint()
        c = QColor(self.QImg.pixel(p - self.offset().toPoint()))
        r, g, b, _ = c.getRgb()
        self.onMouseRelease(p, r, g, b)
Beispiel #7
0
class PlotImage(FigureCanvas):
    def __init__(self, model, parent, main):

        super(FigureCanvas, self).__init__(Figure())

        FigureCanvas.setSizePolicy(self, QSizePolicy.Expanding,
                                   QSizePolicy.Expanding)

        FigureCanvas.updateGeometry(self)

        self.model = model
        self.mw = main
        self.parent = parent

        self.rubber_band = QRubberBand(QRubberBand.Rectangle, self)
        self.band_origin = QtCore.QPoint()
        self.x_plot_origin = None
        self.y_plot_origin = None

        self.menu = QMenu(self)

    def enterEvent(self, event):
        self.setCursor(QtCore.Qt.CrossCursor)
        self.mw.coord_label.show()

    def leaveEvent(self, event):
        self.mw.coord_label.hide()
        self.mw.statusBar().showMessage("")

    def mousePressEvent(self, event):
        self.mw.coord_label.hide()

        # Set rubber band absolute and relative position
        self.band_origin = event.pos()
        self.x_plot_origin, self.y_plot_origin = self.getPlotCoords(
            event.pos())

        # Create rubber band
        self.rubber_band.setGeometry(
            QtCore.QRect(self.band_origin, QtCore.QSize()))

        FigureCanvas.mousePressEvent(self, event)

    def getPlotCoords(self, pos):

        cv = self.model.currentView

        # get the normalized axis coordinates from the event display units
        xPlotCoord, yPlotCoord = self.ax.transAxes.inverted().transform(
            (pos.x(), pos.y()))
        # flip the y-axis (its zero is in the upper left)
        yPlotCoord = 1 - yPlotCoord

        # scale axes using the plot extents
        xPlotCoord = self.ax.dataLim.x0 + xPlotCoord * self.ax.dataLim.width
        yPlotCoord = self.ax.dataLim.y0 + yPlotCoord * self.ax.dataLim.height

        # set coordinate label if pointer is in the axes
        if self.ax.contains_point((pos.x(), pos.y())):
            self.mw.coord_label.show()
            self.mw.showCoords(xPlotCoord, yPlotCoord)
        else:
            self.mw.coord_label.hide()

        return (xPlotCoord, yPlotCoord)

    def getIDinfo(self, event):

        cv = self.model.currentView

        # get origin in axes coordinates
        x0, y0 = self.ax.transAxes.transform((0., 0.))

        # get the extents of the axes box in axes coordinates
        bbox = self.ax.get_window_extent().transformed(
            self.figure.dpi_scale_trans.inverted())
        # get dimensions and scale using dpi
        width, height = bbox.width, bbox.height
        width *= self.figure.dpi
        height *= self.figure.dpi

        # use factor to get proper x,y position in pixels
        factor = (width / cv.h_res, height / cv.v_res)
        xPos = int((event.pos().x() - x0 + 0.05) / factor[0])
        yPos = int((event.pos().y() - y0 + 0.05) / factor[1])

        # check that the position is in the axes view
        if yPos < self.model.currentView.v_res \
            and xPos < self.model.currentView.h_res:
            id = f"{self.model.ids[yPos][xPos]}"
            temp = f"{self.model.props[yPos][xPos][0]:g}"
            density = f"{self.model.props[yPos][xPos][1]:g}"
        else:
            id = '-1'
            density = '-1'
            temp = '-1'

        if self.model.currentView.colorby == 'cell':
            domain = self.model.activeView.cells
            domain_kind = 'Cell'
        else:
            domain = self.model.activeView.materials
            domain_kind = 'Material'

        properties = {'density': density, 'temperature': temp}

        return id, properties, domain, domain_kind

    def mouseDoubleClickEvent(self, event):

        xCenter, yCenter = self.getPlotCoords(event.pos())
        self.mw.editPlotOrigin(xCenter, yCenter, apply=True)

        FigureCanvas.mouseDoubleClickEvent(self, event)

    def mouseMoveEvent(self, event):

        # Show Cursor position relative to plot in status bar
        xPlotPos, yPlotPos = self.getPlotCoords(event.pos())

        # Show Cell/Material ID, Name in status bar
        id, properties, domain, domain_kind = self.getIDinfo(event)
        if self.ax.contains_point((event.pos().x(), event.pos().y())):

            if id != str(_NOT_FOUND_) and domain[id].name:
                domainInfo = (f"{domain_kind} {id}: \"{domain[id].name}\"\t "
                              f"Density: {properties['density']} g/cm3\t"
                              f"Temperature: {properties['temperature']} K")
            elif id != str(_NOT_FOUND_):
                domainInfo = (f"{domain_kind} {id}\t"
                              f"Density: {properties['density']} g/cm3\t"
                              f"Temperature: {properties['temperature']} K")

            else:
                domainInfo = ""
        else:
            domainInfo = ""

        self.mw.statusBar().showMessage(f" {domainInfo}")

        # Update rubber band and values if mouse button held down
        if event.buttons() == QtCore.Qt.LeftButton:
            self.rubber_band.setGeometry(
                QtCore.QRect(self.band_origin, event.pos()).normalized())

            # Show rubber band if both dimensions > 10 pixels
            if self.rubber_band.width() > 10 and self.rubber_band.height(
            ) > 10:
                self.rubber_band.show()
            else:
                self.rubber_band.hide()

            # Update plot X Origin
            xCenter = (self.x_plot_origin + xPlotPos) / 2
            yCenter = (self.y_plot_origin + yPlotPos) / 2
            self.mw.editPlotOrigin(xCenter, yCenter)

            modifiers = event.modifiers()

            # Zoom out if Shift held
            if modifiers == QtCore.Qt.ShiftModifier:
                cv = self.model.currentView
                bandwidth = abs(self.band_origin.x() - event.pos().x())
                width = cv.width * (cv.h_res / max(bandwidth, .001))
                bandheight = abs(self.band_origin.y() - event.pos().y())
                height = cv.height * (cv.v_res / max(bandheight, .001))
            else:  # Zoom in
                width = max(abs(self.x_plot_origin - xPlotPos), 0.1)
                height = max(abs(self.y_plot_origin - yPlotPos), 0.1)

            self.mw.editWidth(width)
            self.mw.editHeight(height)

    def mouseReleaseEvent(self, event):

        if self.rubber_band.isVisible():
            self.rubber_band.hide()
            self.mw.applyChanges()
        else:
            self.mw.revertDockControls()

    def wheelEvent(self, event):

        if event.delta() and event.modifiers() == QtCore.Qt.ShiftModifier:
            numDegrees = event.delta() / 8

            if 24 < self.mw.zoom + numDegrees < 5001:
                self.mw.editZoom(self.mw.zoom + numDegrees)

    def contextMenuEvent(self, event):

        self.menu.clear()

        self.mw.undoAction.setText(f'&Undo ({len(self.model.previousViews)})')
        self.mw.redoAction.setText(
            f'&Redo ({len(self.model.subsequentViews)})')

        id, properties, domain, domain_kind = self.getIDinfo(event)

        if id != '-1':

            # Domain ID
            domainID = self.menu.addAction(f"{domain_kind} {id}")
            domainID.setDisabled(True)

            # Domain Name (if any)
            if domain[id].name:
                domainName = self.menu.addAction(domain[id].name)
                domainName.setDisabled(True)

            self.menu.addSeparator()
            self.menu.addAction(self.mw.undoAction)
            self.menu.addAction(self.mw.redoAction)
            self.menu.addSeparator()

            colorAction = self.menu.addAction(f'Edit {domain_kind} Color...')
            colorAction.setDisabled(self.model.currentView.highlighting)
            colorAction.setToolTip(f'Edit {domain_kind} color')
            colorAction.setStatusTip(f'Edit {domain_kind} color')
            colorAction.triggered.connect(
                lambda: self.mw.editDomainColor(domain_kind, id))

            maskAction = self.menu.addAction(f'Mask {domain_kind}')
            maskAction.setCheckable(True)
            maskAction.setChecked(domain[id].masked)
            maskAction.setDisabled(not self.model.currentView.masking)
            maskAction.setToolTip(f'Toggle {domain_kind} mask')
            maskAction.setStatusTip(f'Toggle {domain_kind} mask')
            maskAction.triggered[bool].connect(
                lambda bool=bool: self.mw.toggleDomainMask(
                    bool, domain_kind, id))

            highlightAction = self.menu.addAction(f'Highlight {domain_kind}')
            highlightAction.setCheckable(True)
            highlightAction.setChecked(domain[id].highlighted)
            highlightAction.setDisabled(
                not self.model.currentView.highlighting)
            highlightAction.setToolTip(f'Toggle {domain_kind} highlight')
            highlightAction.setStatusTip(f'Toggle {domain_kind} highlight')
            highlightAction.triggered[bool].connect(
                lambda bool=bool: self.mw.toggleDomainHighlight(
                    bool, domain_kind, id))

        else:
            self.menu.addAction(self.mw.undoAction)
            self.menu.addAction(self.mw.redoAction)
            self.menu.addSeparator()
            bgColorAction = self.menu.addAction('Edit Background Color...')
            bgColorAction.setToolTip('Edit background color')
            bgColorAction.setStatusTip('Edit plot background color')
            bgColorAction.triggered.connect(
                lambda: self.mw.editBackgroundColor(apply=True))

        self.menu.addSeparator()
        self.menu.addAction(self.mw.saveImageAction)
        self.menu.addAction(self.mw.saveViewAction)
        self.menu.addAction(self.mw.openAction)
        self.menu.addSeparator()
        self.menu.addMenu(self.mw.basisMenu)
        self.menu.addMenu(self.mw.colorbyMenu)
        self.menu.addSeparator()
        self.menu.addAction(self.mw.maskingAction)
        self.menu.addAction(self.mw.highlightingAct)
        self.menu.addSeparator()
        self.menu.addAction(self.mw.dockAction)

        self.mw.maskingAction.setChecked(self.model.currentView.masking)
        self.mw.highlightingAct.setChecked(self.model.currentView.highlighting)

        if self.mw.dock.isVisible():
            self.mw.dockAction.setText('Hide &Dock')
        else:
            self.mw.dockAction.setText('Show &Dock')

        self.menu.exec_(event.globalPos())

    def setPixmap(self, w, h):

        # clear out figure
        self.figure.clear()

        cv = self.model.currentView
        # set figure bg color to match window
        window_background = self.parent.palette().color(
            QtGui.QPalette.Background)
        self.figure.patch.set_facecolor(
            rgb_normalize(window_background.getRgb()))
        # set figure width
        self.figure.set_figwidth(0.99 * w / self.figure.get_dpi())
        self.figure.set_figheight(0.99 * h / self.figure.get_dpi())
        # set data extents for automatic reporting of pointer location
        data_bounds = [
            cv.origin[self.mw.xBasis] - cv.width / 2.,
            cv.origin[self.mw.xBasis] + cv.width / 2.,
            cv.origin[self.mw.yBasis] - cv.height / 2.,
            cv.origin[self.mw.yBasis] + cv.height / 2.
        ]

        # make sure we have an image to load
        if not hasattr(self.model, 'image'):
            self.model.generatePlot()
        c = self.figure.subplots().imshow(self.model.image,
                                          extent=data_bounds,
                                          alpha=cv.plotAlpha)
        self.ax = self.figure.axes[0]
        self.ax.margins(0.0, 0.0)
        self.figure.set_tight_layout({'pad': 1.0})
        # set axis labels
        axis_label_str = "{} (cm)"
        self.ax.set_xlabel(axis_label_str.format(cv.basis[0]))
        self.ax.set_ylabel(axis_label_str.format(cv.basis[1]))
        self.draw()
class PlotImage(QLabel):
    def __init__(self, model, FM, parent=None):
        super(PlotImage, self).__init__(parent)

        self.model = model
        self.FM = FM
        self.mw = parent

        self.setAlignment(QtCore.Qt.AlignCenter)
        self.setMouseTracking(True)

        self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
        self.bandOrigin = QtCore.QPoint()
        self.xPlotOrigin = None
        self.yPlotOrigin = None

        self.menu = QMenu(self)

    def enterEvent(self, event):
        self.setCursor(QtCore.Qt.CrossCursor)
        self.mw.coordLabel.show()

    def leaveEvent(self, event):
        self.mw.coordLabel.hide()
        self.mw.statusBar().showMessage('')

    def mousePressEvent(self, event):

        # Set rubber band absolute and relative position
        self.bandOrigin = event.pos()
        self.xPlotOrigin, self.yPlotOrigin = self.getPlotCoords(event.pos())

        # Create rubber band
        self.rubberBand.setGeometry(
            QtCore.QRect(self.bandOrigin, QtCore.QSize()))

        QLabel.mousePressEvent(self, event)

    def mouseDoubleClickEvent(self, event):

        xCenter, yCenter = self.getPlotCoords(event.pos())
        self.mw.editPlotOrigin(xCenter, yCenter, apply=True)

        QLabel.mouseDoubleClickEvent(self, event)

    def mouseMoveEvent(self, event):

        # Show Cursor position relative to plot in status bar
        xPlotPos, yPlotPos = self.getPlotCoords(event.pos())

        # Show Cell/Material ID, Name in status bar
        id, domain, domain_kind = self.getIDinfo(event)
        if id != '-1' and domain[id].name:
            domainInfo = f"{domain_kind} {id}: {domain[id].name}"
        elif id != '-1':
            domainInfo = f"{domain_kind} {id}"
        else:
            domainInfo = ""
        self.mw.statusBar().showMessage(f" {domainInfo}")

        # Update rubber band and values if mouse button held down
        if event.buttons() == QtCore.Qt.LeftButton:
            self.rubberBand.setGeometry(
                QtCore.QRect(self.bandOrigin, event.pos()).normalized())

            # Show rubber band if both dimensions > 10 pixels
            if self.rubberBand.width() > 10 and self.rubberBand.height() > 10:
                self.rubberBand.show()
            else:
                self.rubberBand.hide()

            # Update plot X Origin
            xCenter = (self.xPlotOrigin + xPlotPos) / 2
            yCenter = (self.yPlotOrigin + yPlotPos) / 2
            self.mw.editPlotOrigin(xCenter, yCenter)

            modifiers = event.modifiers()

            # Zoom out if Shift held
            if modifiers == QtCore.Qt.ShiftModifier:
                cv = self.model.currentView
                bandwidth = abs(self.bandOrigin.x() - event.pos().x())
                width = cv.width * (cv.hRes / max(bandwidth, .001))
                bandheight = abs(self.bandOrigin.y() - event.pos().y())
                height = cv.height * (cv.vRes / max(bandheight, .001))
            else:  # Zoom in
                width = max(abs(self.xPlotOrigin - xPlotPos), 0.1)
                height = max(abs(self.yPlotOrigin - yPlotPos), 0.1)

            self.mw.editWidth(width)
            self.mw.editHeight(height)

    def mouseReleaseEvent(self, event):

        if self.rubberBand.isVisible():
            self.rubberBand.hide()
            self.mw.applyChanges()
        else:
            self.mw.revertDockControls()

    def wheelEvent(self, event):

        if event.delta() and event.modifiers() == QtCore.Qt.ShiftModifier:
            numDegrees = event.delta() / 8

            if 24 < self.mw.zoom + numDegrees < 5001:
                self.mw.editZoom(self.mw.zoom + numDegrees)

    def contextMenuEvent(self, event):

        self.menu.clear()

        self.mw.undoAction.setText(f'&Undo ({len(self.model.previousViews)})')
        self.mw.redoAction.setText(
            f'&Redo ({len(self.model.subsequentViews)})')

        id, domain, domain_kind = self.getIDinfo(event)

        if id != '-1':

            # Domain ID
            domainID = self.menu.addAction(f"{domain_kind} {id}")
            domainID.setDisabled(True)

            # Domain Name (if any)
            if domain[id].name:
                domainName = self.menu.addAction(domain[id].name)
                domainName.setDisabled(True)

            self.menu.addSeparator()
            self.menu.addAction(self.mw.undoAction)
            self.menu.addAction(self.mw.redoAction)
            self.menu.addSeparator()

            colorAction = self.menu.addAction(f'Edit {domain_kind} Color...')
            colorAction.setDisabled(self.model.currentView.highlighting)
            colorAction.setToolTip(f'Edit {domain_kind} color')
            colorAction.setStatusTip(f'Edit {domain_kind} color')
            colorAction.triggered.connect(
                lambda: self.mw.editDomainColor(domain_kind, id))

            maskAction = self.menu.addAction(f'Mask {domain_kind}')
            maskAction.setCheckable(True)
            maskAction.setChecked(domain[id].masked)
            maskAction.setDisabled(not self.model.currentView.masking)
            maskAction.setToolTip(f'Toggle {domain_kind} mask')
            maskAction.setStatusTip(f'Toggle {domain_kind} mask')
            maskAction.triggered[bool].connect(
                lambda bool=bool: self.mw.toggleDomainMask(
                    bool, domain_kind, id))

            highlightAction = self.menu.addAction(f'Highlight {domain_kind}')
            highlightAction.setCheckable(True)
            highlightAction.setChecked(domain[id].highlighted)
            highlightAction.setDisabled(
                not self.model.currentView.highlighting)
            highlightAction.setToolTip(f'Toggle {domain_kind} highlight')
            highlightAction.setStatusTip(f'Toggle {domain_kind} highlight')
            highlightAction.triggered[bool].connect(
                lambda bool=bool: self.mw.toggleDomainHighlight(
                    bool, domain_kind, id))

        else:
            self.menu.addAction(self.mw.undoAction)
            self.menu.addAction(self.mw.redoAction)
            self.menu.addSeparator()
            bgColorAction = self.menu.addAction('Edit Background Color...')
            bgColorAction.setToolTip('Edit background color')
            bgColorAction.setStatusTip('Edit plot background color')
            bgColorAction.triggered.connect(
                lambda: self.mw.editBackgroundColor(apply=True))

        self.menu.addSeparator()
        self.menu.addAction(self.mw.saveImageAction)
        self.menu.addAction(self.mw.saveViewAction)
        self.menu.addAction(self.mw.openAction)
        self.menu.addSeparator()
        self.menu.addMenu(self.mw.basisMenu)
        self.menu.addMenu(self.mw.colorbyMenu)
        self.menu.addSeparator()
        self.menu.addAction(self.mw.maskingAction)
        self.menu.addAction(self.mw.highlightingAct)
        self.menu.addSeparator()
        self.menu.addAction(self.mw.dockAction)

        self.mw.maskingAction.setChecked(self.model.currentView.masking)
        self.mw.highlightingAct.setChecked(self.model.currentView.highlighting)

        if self.mw.dock.isVisible():
            self.mw.dockAction.setText('Hide &Dock')
        else:
            self.mw.dockAction.setText('Show &Dock')

        self.menu.exec_(event.globalPos())

    def getPlotCoords(self, pos):

        cv = self.model.currentView

        factor = (self.width() / cv.hRes, self.height() / cv.vRes)

        # Cursor position in pixels relative to center of plot image
        xPos = (pos.x() + 0.5) / factor[0] - cv.hRes / 2
        yPos = (-pos.y() - 0.5) / factor[1] + cv.vRes / 2

        # Curson position in plot coordinates
        xPlotCoord = (xPos / self.mw.scale[0]) + cv.origin[self.mw.xBasis]
        yPlotCoord = (yPos / self.mw.scale[1]) + cv.origin[self.mw.yBasis]

        self.mw.showCoords(xPlotCoord, yPlotCoord)

        return (xPlotCoord, yPlotCoord)

    def getIDinfo(self, event):

        cv = self.model.currentView
        factor = (self.width() / cv.hRes, self.height() / cv.vRes)
        xPos = int((event.pos().x() + .05) / factor[0])
        yPos = int((event.pos().y() + .05) / factor[1])

        if yPos < self.model.currentView.vRes \
            and xPos < self.model.currentView.hRes:

            id = f"{self.model.ids[yPos][xPos]}"
        else:
            id = '-1'

        if self.model.currentView.colorby == 'cell':
            domain = self.model.activeView.cells
            domain_kind = 'Cell'
        else:
            domain = self.model.activeView.materials
            domain_kind = 'Material'

        return id, domain, domain_kind
Beispiel #9
0
class Dicom_Browser(QWidget):
    draw_state: bool = False
    erase_state: bool = False
    point_pick: bool = False
    nj_points = []
    nj_points_ready = Signal()
    series_id: str
    mask: np.array

    def __init__(self):
        super().__init__()
        self.initUI()
        self.rubberBand: QRubberBand = QRubberBand(QRubberBand.Line,
                                                   self.image_label)

    def initUI(self):
        self.image = DicomImage()
        self.pixmap = QPixmap()

        self.image_label = QLabel()
        self.image_label.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
        self.image_label.setSizePolicy(QSizePolicy.Preferred,
                                       QSizePolicy.Preferred)
        self.image_label.setPixmap(self.pixmap)

        self.tags_view = Dicom_Tags_Widget([''])
        self.tools = Dicom_ImageToolsWidget()

        self.tabs_widget = self.__inti_tab_widget__(
            [self.tags_view, self.tools])
        self.tabs_widget.setMaximumWidth(600)

        image_layout = QVBoxLayout()
        image_layout.setContentsMargins(0, 0, 0, 0)
        image_layout.addWidget(self.image_label)

        image_group = QGroupBox()
        image_group.setStyleSheet("margin:0; padding: 0; border: 0;")
        image_group.setContentsMargins(0, 0, 0, 0)
        image_group.setLayout(image_layout)

        splitter = QSplitter()
        splitter.addWidget(image_group)
        splitter.addWidget(self.tabs_widget)

        layout = QHBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(splitter)

        self.tools.pen_selected.connect(self.pen_select)
        self.tools.erase_btn.clicked.connect(self.erase_btn_click)
        self.tools.slider.valueChanged.connect(self.slider_changed)
        self.tools.processing_btn.clicked.connect(self.send_nn_segmentation)
        self.tools.load_mask_btn.clicked.connect(self.load_nifti_mask_click)
        self.tools.save_mask_btn.clicked.connect(self.save_nifti_mask_click)
        self.tools.nj_segment_btn.clicked.connect(self.nj_segment_click)
        self.nj_points_ready.connect(self.nj_segment)

    def set_image(self):
        self.pixmap = QPixmap.fromImage(self.image.get_slice_as_QImage())
        self.image_label.setPixmap(self.pixmap)
        self.set_tags()

    def update_mask(self):
        self.mask = np.zeros([
            self.image.get_shape()[0],
            self.image.get_shape()[1],
            self.image.get_slice_amount()
        ], np.int)
        self.draw_mask()

    def load_series(self, path):
        if isinstance(path, list):
            if len(path) == 1:
                path = path[0]
            else:
                path = os.path.dirname(path[0]) + '/'

        self.image.load_dicom(path)
        self.set_image()
        if self.image.is_series():
            self.set_slider_maximum()
            self.tools.slider.setDisabled(False)
        else:
            self.tools.slider.setDisabled(True)
        self.set_tags()
        self.update_tags()
        self.update_mask()

    def set_tags(self):
        result = []
        for elem in self.image.slice().iterall():
            result.append([str(elem.tag), elem.name, str(elem.value)])

        return result

    def update_tags(self):
        self.tags_view.model.update(self.set_tags())
        self.tags_view.model.layoutChanged.emit()

    # MOUSE EVENTS

    def wheelEvent(self, event):

        if self.image_label.underMouse():
            delta = event.delta()
            if delta > 0:
                self.image.next_slice()
            elif delta < 0:
                self.image.pre_slice()

            self.set_image()
            self.tools.slider.setSliderPosition(self.image.get_slice_index())
            self.update_tags()
            self.draw_mask()
            self.update()

    def mousePressEvent(self, e):
        if self.image_label.underMouse():
            if self.draw_state:
                self.pos = self.point_on_image(e)
                self.set_mask_pixels(self.pos)
                self.draw_mask_point(self.pos)
                self.update()
            elif self.erase_state:
                self.pos = self.point_on_image(e)
                self.set_mask_pixels(self.pos, 0)
                self.set_image()
                self.draw_mask()
                self.update()
            elif self.point_pick:
                point = [
                    self.point_on_image(e).x(),
                    self.point_on_image(e).x(),
                    self.image.get_slice_index()
                ]
                self.nj_points.append(point)
                if len(self.nj_points) == 2:
                    self.point_pick = False
                    QApplication.restoreOverrideCursor()
                    self.nj_points_ready.emit()
            else:
                self.origin = e.pos()
                if not self.rubberBand:
                    self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
                self.rubberBand.setGeometry(QRect(self.origin, QSize()))
                self.rubberBand.show()

    def mouseMoveEvent(self, e):
        if self.image_label.underMouse():
            if self.draw_state:
                self.pos = self.point_on_image(e)
                self.set_mask_pixels(self.pos)
                # self.mask[int(self.pos.y())][int(self.pos.x())][self.image.get_slice_index()] = 255
                self.draw_mask_point(self.pos)
                self.update()
            elif self.erase_state:
                self.pos = self.point_on_image(e)
                self.set_mask_pixels(self.pos, 0)
                # self.mask[int(self.pos.y())][int(self.pos.x())][self.image.get_slice_index()] = 0
                self.set_image()
                self.draw_mask()
                self.update()
            else:
                self.rubberBand.setGeometry(
                    QRect(self.origin, e.pos()).normalized())

    def mouseReleaseEvent(self, event):
        if self.image_label.underMouse():
            if self.draw_state:
                return
            self.rubberBand.hide()

    def keyPressEvent(self, event):
        # Re-direct ESC key to closeEvent
        if event.key() == Qt.Key_Escape:
            if self.point_pick:
                self.point_pick = not self.point_pick
                QApplication.restoreOverrideCursor()

    # IMAGE SLIDER

    def set_slider_maximum(self):
        self.tools.set_slider_maximum(self.image.get_slice_amount() - 1)

    def slider_changed(self):
        self.image.set_slice_index(self.tools.slider.value())
        self.set_image()
        self.update_tags()
        self.draw_mask()
        self.update()

    def pen_select(self):
        self.draw_state = self.tools.pen_btn.isChecked()

    def __init_slider(self) -> QSlider:
        slider = QSlider()
        slider.setOrientation(Qt.Horizontal)
        slider.setMaximumWidth(self.image_label.width())
        slider.setMinimum(0)
        slider.setMaximum(self.image.get_slice_amount())
        slider.setTickInterval(1)
        slider.setSliderPosition(1)
        slider.valueChanged.connect(self.slider_changed)
        if not self.image.is_series():
            slider.setHidden(True)

        return slider

    def __inti_tab_widget__(self, widgets: list) -> object:
        tabs_widget = QTabWidget()
        tabs_widget.setTabPosition(QTabWidget.South)
        tabs_widget.setMinimumWidth(50)
        for wdg in widgets:
            tabs_widget.addTab(wdg, wdg.tab_name)

        return tabs_widget

    # MASKING
    def send_nn_segmentation(self):
        # Dicom_BrowserCtrl.save_mask(self, self.mask, 'res/H-DenseUNet-master_v1/livermask/0.nii')
        ctrl = Dicom_BrowserCtrl()
        head, tail = os.path.split(os.path.split(self.image.dicom_dir)[0])
        ctrl.image_to_nn(tail, self.mask,
                         self.image.get_shape()[0],
                         self.image.get_shape()[1])

    def set_mask(self):
        img = self.__arr_to_QImage(self.mask[:, :,
                                             self.image.get_slice_index()].T())
        self.mask_pixmap = QPixmap.fromImage(img)
        self.mask_label.setPixmap(self.mask_pixmap)

    def draw_mask(self):
        try:
            if not np.array_equal(
                    self.mask[:, :, self.image.get_slice_index()],
                    np.zeros(
                        [self.image.get_shape()[0],
                         self.image.get_shape()[1]])):
                it = np.nditer(self.mask[:, :,
                                         self.image.get_slice_index()],
                               flags=['multi_index'])
                for pixel in it:
                    if pixel != 0:
                        point = QPoint(it.multi_index[1], it.multi_index[0])
                        self.draw_mask_point(point, 1)
        except Exception:
            self.update_mask()

    def set_mask_pixels(self, center_point: QPoint, value=255):
        it = np.nditer(self.mask[:, :, self.image.get_slice_index()],
                       flags=['multi_index'])
        size = int(self.tools.get_size() / 2) - 1
        x = center_point.x()
        y = center_point.y()
        for pixel in it:
            if x - size <= it.multi_index[
                    1] <= x + size and y + size >= it.multi_index[
                        0] >= y - size:
                self.mask[it.multi_index[0]][it.multi_index[1]][
                    self.image.get_slice_index()] = value

    def draw_mask_point(self, point, pen_size: int = None):
        if pen_size is None:
            pen_size = self.tools.get_size()
        painter = QPainter(self.image_label.pixmap())
        painter.setPen(
            QPen(self.tools.mask_color, pen_size, Qt.SolidLine, Qt.SquareCap,
                 Qt.RoundJoin))
        painter.drawPoint(point)

    def erase_btn_click(self):
        self.erase_state = not self.erase_state
        self.tools.erase_btn.setChecked(self.erase_state)
        if self.draw_state:
            self.draw_state = not self.draw_state
            self.tools.pen_btn.setChecked(self.draw_state)

    def load_nifti_mask_click(self):
        ctrl = Dicom_BrowserCtrl()
        self.mask = ctrl.load_nitfit_mask()
        self.draw_mask()
        self.update()

    def save_nifti_mask_click(self):
        Dicom_BrowserCtrl.save_mask(self, self.mask)

    def nj_segment_click(self):
        QApplication.setOverrideCursor(QCursor(Qt.CrossCursor))
        self.point_pick = True

    def nj_segment(self):
        ctrl = Dicom_BrowserCtrl()
        ctrl.nj_segment(self.image.dicom_dir, self.nj_points)
        self.nj_points = []
        self.mask = ctrl.load_nitfit_mask('data/.tmp.nii')
        self.draw_mask()
        self.update()

    def point_on_image(self, e):
        x_offset, y_offset = self.__image_offset()
        pos = QPoint(e.x() - x_offset, e.y() - y_offset)

        return pos

    def __image_offset(self):
        x_offset = (self.image_label.width() - self.pixmap.width()) / 2
        y_offset = (self.image_label.height() - self.pixmap.height()) / 2
        return x_offset, y_offset

    def __arr_to_QImage(self, arr_img):
        img = PIL.Image.fromarray(arr_img)
        img = img.convert("L")
        result = ImageQt(img)

        return result