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)
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')
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()
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()
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)
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
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