class SampleImageWidget(QWidget): def __init__(self, parent=None): super(SampleImageWidget, self).__init__(parent) self.graphicsScene = QGraphicsScene(self) self.graphicsView = SampleGraphicsView(self.graphicsScene) def setSampleImage(self, pathToFile): self.graphicsView.hide() #clear scene self.graphicsScene.clear() #load file tmpImage = QImage(pathToFile) self.originalHeight = tmpImage.height() self.originalWidth = tmpImage.width() tmpPixmap = QPixmap(1) tmpPixmap.convertFromImage(tmpImage.scaledToWidth(300)) self.scaledHeight = tmpPixmap.height() self.scaledWidth = tmpPixmap.width() #add to scene and show self.graphicsScene.addPixmap(tmpPixmap) self.graphicsView.show()
class ImageView(QGraphicsView): def __init__(self, width=200, height=300): super().__init__() self.setFixedSize(QSize(width, height)) self.image = None self.scene = QGraphicsScene() self.setScene(self.scene) """ファイル名より取得した画像表示""" def setImage(self, imageName): self.setCvImage(cv2.imread(imageName)) """numpy配列より取得した画像表示""" def setCvImage(self, cvImage): cvImage = cv2.cvtColor(cvImage, cv2.COLOR_BGR2RGB) height, width, channel = cvImage.shape bytesPerLine = width * channel self.image = QImage(cvImage.data, width, height, bytesPerLine, QImage.Format_RGB888) item = QGraphicsPixmapItem(QPixmap.fromImage(self.image)) self.scene = QGraphicsScene() self.scene.addItem(item) self.setScene(self.scene) """ビューワクリア処理""" def clear(self): self.scene.clear()
class TextView(QGraphicsView): def __init__(self) -> None: super().__init__() self.setObjectName("TextView") self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setTransformationAnchor(self.AnchorViewCenter) self.setContentsMargins(0, 0, 0, 0) self._scene = QGraphicsScene() # need to set Scene size to View size self._scene.setSceneRect(QRectF(self.rect())) self.setScene(self._scene) def add(self, text_item: TextItem) -> None: offset = text_item.boundingRect() if profile.text.direction == "down": text_item.setPos(self.mapToScene(self.width() / 2 - offset.width() / 2, 0)) else: text_item.setPos( self.mapToScene( self.width() / 2 - offset.width() / 2, self.height() - offset.height(), ) ) self._scene.addItem(text_item) def clear(self): self._scene.clear()
class MainWidget(QGraphicsView): def __init__(self, parent): super().__init__() self.parent = parent self.scene = QGraphicsScene(self) self.setScene(self.scene) def _cv2_image_to_pixmap(self): if self.cv2_out_image == COLOR_IMAGE: cv2_image = cv2.cvtColor(self.cv2_image, cv2.COLOR_BGR2RGB) elif self.cv2_out_image == GRAY_IMAGE: cv2_image = cv2.cvtColor(self.cv2_image, cv2.COLOR_GRAY2RGB) elif self.cv2_out_image == BIN_IMAGE: cv2_image = cv2.cvtColor(self.cv2_image, cv2.COLOR_GRAY2RGB) height, width, chanels = cv2_image.shape return QPixmap.fromImage( QImage(cv2_image, width, height, width * chanels, QImage.Format_RGB888)) def setImage(self, images): self.cv2_out_image = images[OUT_IMAGE] self.cv2_image = images[self.cv2_out_image] self.update_view() def update_view(self): self.scene.clear() self.scene.setSceneRect(0, 0, self.cv2_image.shape[1], self.cv2_image.shape[0]) self.scene.addPixmap(self._cv2_image_to_pixmap()) self.fitInView(self.scene.sceneRect(), QtCore.Qt.KeepAspectRatio) def resizeEvent(self, event): self.fitInView(self.scene.sceneRect(), QtCore.Qt.KeepAspectRatio)
class Widget(QWidget): def __init__(self): super().__init__() self.scene = QGraphicsScene() self.scene.addItem(QGraphicsTextItem('loading...')) self.view = QGraphicsView() self.view.setScene(self.scene) self.nam = QNetworkAccessManager() self.nam.finished.connect(self.finish_request) url = "http://pp.vk.me/c627626/v627626428/be07/wbpWha0RqZ4.jpg" self.nam.get(QNetworkRequest(QUrl(url))) layout = QVBoxLayout() layout.addWidget(self.view) self.setLayout(layout) def finish_request(self, reply): self.scene.clear() img = QPixmap() img.loadFromData(reply.readAll()) item = QGraphicsPixmapItem(img) self.scene.addItem(item)
class MainView(QGraphicsView): min_scale = 1 max_scale = 5 def __init__(self, window=None): QGraphicsView.__init__(self) self.window = window self.scene = QGraphicsScene(self) self.setScene(self.scene) self.setMouseTracking(True) self.image = None self.screen_scale = 1 def create_image(self, image_map, palette_frame): colors = [QColor(c).rgb() for c in palette_frame.get_colors()] width, height = image_map.width, image_map.height image = QImage(width, height, QImage.Format_ARGB32) for x in range(width): for y in range(height): idx = image_map.get(x, y) image.setPixel(x, y, colors[idx]) return QImage(image) def set_image(self, image_map, palette_frame): self.image = self.create_image(image_map, palette_frame) # self.image = self.image.convertToFormat(QImage.Format_ARGB32) self.setSceneRect(0, 0, self.image.width(), self.image.height()) def clear_scene(self): self.scene.clear() def show_image(self): if self.image: self.clear_scene() self.scene.addPixmap(QPixmap.fromImage(self.image)) def mousePressEvent(self, event): scene_pos = self.mapToScene(event.pos()) pixmap = self.scene.itemAt(scene_pos) if not pixmap: return image = pixmap.pixmap().toImage() pos = int(scene_pos.x()), int(scene_pos.y()) if event.button() == Qt.LeftButton: dlg = QColorDialog() dlg.setCurrentColor(QColor(image.pixel(pos[0], pos[1]))) if dlg.exec_(): self.window.change_current_palette(pos, dlg.currentColor()) def wheelEvent(self, event): if event.delta() > 0 and self.screen_scale < self.max_scale: self.screen_scale += 1 self.scale(2, 2) elif event.delta() < 0 and self.screen_scale > self.min_scale: self.screen_scale -= 1 self.scale(0.5, 0.5)
class ImageDocument(DocumentInterface): def __init__(self, associated_view): super().__init__() self._selection = tuple() self._assoc_view = associated_view self._scene = QGraphicsScene(associated_view) self._pixmap = QPixmap() @property def contents(self): return self._scene @property def raw(self): raw_contents = RawContents(image=self._pixmap.toImage()) return raw_contents('image') @property def selection(self): return self._selection @selection.setter def selection(self, value): self._selection = tuple(value) @property def has_selection(self): # the same as an `if not ...` / etc. return bool(self._selection) @property def associated_view(self): return self._assoc_view def load_document(self, load_callback): load_callback(self._pixmap) if self._pixmap.isNull(): return False self._scene.addPixmap(self._pixmap) self._scene.setSceneRect(0, 0, self._pixmap.width(), self._pixmap.height()) return True def reset_document(self): self._scene.clear() def save_document(self, file_obj, format): raise NotImplementedError def get_selection_as_image(self): if not self.has_selection: raise ValueError("No Selection.") return self._pixmap.toImage().copy(*self._selection)
def showImageFile(self, imageFile, _QGraphicsView_obj): # 显示图片 # input: image path, QGraphicsView object pixmap = QPixmap(imageFile) scene = QGraphicsScene() pixmap = pixmap.scaled(_QGraphicsView_obj.size(), Qt.KeepAspectRatio) scene.clear() scene.addPixmap(pixmap) _QGraphicsView_obj.setScene(scene)
def paint(self, painter: QtGui.QPainter, option: QStyleOptionViewItem, index: QtCore.QModelIndex) -> None: item_size = option.rect.size() custom_decoration_w, custom_decoration_h = index.data( SlideListModel.DecorationSizeOrRatioRole) if option.decorationPosition == QStyleOptionViewItem.Left: text_x, text_y = custom_decoration_w + self.icon_and_text_spacing, 0 text_width = item_size.width( ) - custom_decoration_w - self.icon_and_text_spacing text_height = custom_decoration_h elif option.decorationPosition == QStyleOptionViewItem.Top: text_size = super().sizeHint(option, index) custom_decoration_h = custom_decoration_h - text_size.height() text_x, text_y = 0, custom_decoration_h + self.icon_and_text_spacing text_width = custom_decoration_w text_height = item_size.height( ) - custom_decoration_h - self.icon_and_text_spacing slide_view_params: SlideViewParams = index.data( SlideListModel.SlideViewParamsRole) scene_rect = QRectF(*slide_view_params.level_rect) img_key = "{}_{}_{}".format(custom_decoration_w, custom_decoration_h, slide_view_params.cache_key()) icon_pixmap = QPixmapCache.find(img_key) if icon_pixmap is None: slide_helper = SlideHelper(slide_view_params.slide_path) # print("read", img_key) scene = QGraphicsScene() # t1 = elapsed() # print("before slide_graphics", t1) slide_graphics = SlideGraphicsGroup(slide_view_params) # t2 = elapsed() # print("slide_graphics", t2 - t1) scene.clear() scene.invalidate() scene.addItem(slide_graphics) slide_graphics.update_visible_level(slide_view_params.level) scene.setSceneRect( slide_helper.get_rect_for_level(slide_view_params.level)) image = build_screenshot_image( scene, QSize(custom_decoration_w, custom_decoration_h), scene_rect) # t3 = elapsed() # print("build_screenshot_image", t3 - t2) icon_pixmap = QtGui.QPixmap.fromImage(image) QPixmapCache.insert(img_key, icon_pixmap) # t4 = elapsed() painter.fillRect(option.rect, painter.background()) painter.drawPixmap(option.rect.topLeft(), icon_pixmap) # painter.drawRect(option.rect) painter.drawRect(option.rect.topLeft().x(), option.rect.topLeft().y(), icon_pixmap.width(), icon_pixmap.height()) option.rect = option.rect.translated(text_x, text_y) option.rect.setSize(QSize(text_width, text_height)) super().paint(painter, option, index)
class GraphWidget(QtWidgets.QGraphicsView): onSelected = pyqtSignal(object) showPid = pyqtSignal(int) def __init__(self, data): super().__init__() self.data = data self.setDragMode(QGraphicsView.ScrollHandDrag) self.setMouseTracking(True) self.p = QGraphicsScene(self) self.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform | QPainter.HighQualityAntialiasing) self.setScene(self.p) self.showPid.connect(self.handle_show_pid) self.onSelected.connect(self.handle_select) def handle_show_pid(self, pid): for node in self.p.items(): if isinstance(node, Process) and node.process.process['pid'] == pid: self.onSelected.emit(node) def handle_select(self, object): for i in self.p.selectedItems(): i.setSecondFocus(False) i.setSelected(False) i.update() object.setSelected(True) def create_graph(self, filter=None): self.graph, self.hashes = self.data.create_graph(filter) self.p.clear() for type in [self.graph.shapes, self.graph.nodes, self.graph.edges]: for node in type: if isinstance(node, QGraphicsItem): self.p.addItem(node) def apply_filter(self, query): self.create_graph(filter=query) def wheelEvent(self, evt): scale = 1.2 if evt.angleDelta().y() > 0 else 0.8 self.scale(scale, scale) self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) def mousePressEvent(self, QMouseEvent): item = self.itemAt(QMouseEvent.x(), QMouseEvent.y()) while item and not isinstance(item, Base): item = item.parentItem() if item: self.onSelected.emit(item)
class CanvasModel(object): def __init__(self): self.scene = QGraphicsScene() # Canvas area self.scale_factor = 1 # Scaling factor self.current_image = None # Current image in canvas def update(self): self.scene.clear() self.scene.addItem( QGraphicsPixmapItem(QPixmap.fromImage(self.current_image))) self.scene.update()
def showImageArray(self, _bgrimg, _QGraphicsView_obj): # 显示图片 # input: image path, QGraphicsView object rgbimg = cv2.cvtColor(_bgrimg, cv2.COLOR_BGR2RGB) qimg = QImage(rgbimg.data, rgbimg.shape[1], rgbimg.shape[0], QImage.Format_RGB888) pixmap = QPixmap(qimg) scene = QGraphicsScene() pixmap = pixmap.scaled(_QGraphicsView_obj.size(), Qt.KeepAspectRatio) scene.clear() scene.addPixmap(pixmap) _QGraphicsView_obj.setScene(scene)
class ImageWidget(QGraphicsView): def __init__(self, parent): super().__init__() self.scene = QGraphicsScene(self) self.parent = parent self.setScene(self.scene) def setImage(self, cv2_image): self.cv2_image_orig = cv2_image self.transform_image() self.update_view() def update_view(self, transform=True): if transform: self.transform_image() self.scene.clear() self.scene.setSceneRect(0, 0, self.cv2_image.shape[1], self.cv2_image.shape[0]) self.scene.addPixmap(self._cv2_image_to_pixmap()) self.fitInView(self.scene.sceneRect(), QtCore.Qt.KeepAspectRatio) def _cv2_image_to_pixmap(self): if self.cv2_out_image == COLOR_IMAGE: cv2_image = cv2.cvtColor(self.cv2_image, cv2.COLOR_BGR2RGB) elif self.cv2_out_image == GRAY_IMAGE: cv2_image = cv2.cvtColor(self.cv2_image, cv2.COLOR_GRAY2RGB) elif self.cv2_out_image == BIN_IMAGE: cv2_image = cv2.cvtColor(self.cv2_image, cv2.COLOR_GRAY2RGB) self.parent.draw(cv2_image) height, width, chanels = cv2_image.shape return QPixmap.fromImage( QImage(cv2_image, width, height, width * chanels, QImage.Format_RGB888)) def transform_image(self): images = {} try: with wait_cursor(): images = self.parent.image_service.transform_image( self.cv2_image_orig, self.parent.model) self.cv2_out_image = images[OUT_IMAGE] self.cv2_image = images[self.cv2_out_image] except TransformationError as e: message = QMessageBox(QMessageBox.Warning, "Warning", str(e)) message.exec_() return images def resizeEvent(self, event): self.fitInView(self.scene.sceneRect(), QtCore.Qt.KeepAspectRatio)
class ImageView(QGraphicsView): def __init__(self, window=None): QGraphicsView.__init__(self) self.window = window self.scene = QGraphicsScene(self) self.setScene(self.scene) self.setFixedSize(240, 160) # self.fitInView(0, 0, 240, 160, Qt.KeepAspectRatio) self.image = QImage(240, 160, QImage.Format_ARGB32) self.screen_scale = 1 # self.image_counter = 0 def clear_scene(self): self.scene.clear() def show_image(self): if self.image: self.clear_scene() # bg = QImage(240, 160, QImage.Format_ARGB32) # self.scene.addPixmap(QPixmap.fromImage(bg)) self.scene.addPixmap(QPixmap.fromImage(self.image)) def new_frame(self, frame, offset): self.image = QImage(240, 160, QImage.Format_ARGB32) self.image.fill(QColor(128, 160, 128)) painter = QPainter() painter.begin(self.image) painter.drawImage(offset[0], offset[1], frame.copy()) # Draw image on top of autotiles painter.end() # self.image = f # self.image.paste(QImage(frame), offset) self.setSceneRect(0, 0, 240, 160) # self.image.save('image_%d.png' % self.image_counter) # self.image_counter += 1 self.show_image() def new_over_frame(self, frame, offset): painter = QPainter() painter.begin(self.image) painter.drawImage(offset[0], offset[1], frame.copy()) # Draw image on top of autotiles painter.end() self.show_image()
class picturezoom(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super(picturezoom, self).__init__(parent) self.setupUi(self) self.zoomscale = 1 # 图片放缩尺度 self.scene = QGraphicsScene() # 创建场景 self.item = 0 self.train_set_x_orig, self.train_set_y, test_set_x_orig, test_set_y, classes = load_dataset( ) self.pushBtn.clicked.connect(self.on_img_show_clicked) @pyqtSlot() def on_zoomin_clicked(self): self.zoomscale = self.zoomscale - 0.05 if self.zoomscale <= 0.1: self.zoomscale = 0.1 self.item.setScale(self.zoomscale) # 缩小图像 @pyqtSlot() def on_zoomout_clicked(self): self.zoomscale = self.zoomscale + 0.05 if self.zoomscale >= 1.2: self.zoomscale = 1.2 self.item.setScale(self.zoomscale) # 放大图像 @pyqtSlot() def on_img_show_clicked(self): index_str = self.line_edit.text() self.line_edit.setText(index_str) index = int(index_str) total_img_num = self.train_set_y.shape[1] if index < 0: index = 0 elif index > total_img_num: index = total_img_num img = self.train_set_x_orig[index] img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 转换图像通道 x = img.shape[1] # 获取图像大小 y = img.shape[0] frame = QImage(img, x, y, QImage.Format_RGB888) pix = QPixmap.fromImage(frame) self.item = QGraphicsPixmapItem(pix) # 创建像素图元 self.scene.removeItem(self.item) self.scene.clear() self.scene.addItem(self.item) self.picshow.setScene(self.scene) # 将场景添加至视图
class TmxViewer(QGraphicsView): def __init__(self, parent = None): super().__init__(parent) self.mScene = QGraphicsScene(self) self.mMap = None self.mRenderer = None self.setWindowTitle(self.tr("TMX Viewer")) self.setScene(self.mScene) self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) self.setDragMode(QGraphicsView.ScrollHandDrag) self.setOptimizationFlags(QGraphicsView.DontAdjustForAntialiasing | QGraphicsView.DontSavePainterState) self.setBackgroundBrush(Qt.black) self.setFrameStyle(QFrame.NoFrame) self.viewport().setAttribute(Qt.WA_StaticContents) def __del__(self): if (self.mMap): self.mMap.tilesets().clear() del self.mMap del self.mRenderer def viewMap(self, fileName): del self.mRenderer self.mRenderer = None self.mScene.clear() self.centerOn(0, 0) reader = MapReader() self.mMap = reader.readMap(fileName) if (not self.mMap): qWarning("Error:"+reader.errorString()) return False x = self.mMap.orientation() if x==Map.Orientation.Isometric: self.mRenderer = IsometricRenderer(self.mMap) elif x==Map.Orientation.Staggered: self.mRenderer = StaggeredRenderer(self.mMap) elif x==Map.Orientation.Hexagonal: self.mRenderer = HexagonalRenderer(self.mMap) else: self.mRenderer = OrthogonalRenderer(self.mMap) self.mScene.addItem(MapItem(self.mMap, self.mRenderer)) return True
def render_drop_shadow_frame(pixmap, shadow_rect, shadow_color, offset, radius, rect_fill_color): pixmap.fill(QColor(0, 0, 0, 0)) scene = QGraphicsScene() rect = QGraphicsRectItem(shadow_rect) rect.setBrush(QColor(rect_fill_color)) rect.setPen(QPen(Qt.NoPen)) scene.addItem(rect) effect = QGraphicsDropShadowEffect(color=shadow_color, blurRadius=radius, offset=offset) rect.setGraphicsEffect(effect) scene.setSceneRect(QRectF(QPointF(0, 0), QSizeF(pixmap.size()))) painter = QPainter(pixmap) scene.render(painter) painter.end() scene.clear() scene.deleteLater() return pixmap
class EasyScaleView(QGraphicsView): def __init__(self, parent=None): self.__scene = QGraphicsScene(parent) super().__init__(self.__scene) self.currentScale = 1.0 def zoom(self, mul): self.currentScale *= mul self.update_scale() def resizeEvent(self, event): super().resizeEvent(event) # if self.__item is not None: self.update_scale() def update_scale(self): for i in self.items(): self.update_item_scale(i) def update_item_scale(self, item): scale = self.width() / (item.pixmap().width() + 1) * self.currentScale item.setScale(scale) rect = item.boundingRect() rect.setSize(rect.size() * scale) self.setSceneRect(rect) def scroll(self, offset): scroll = self.verticalScrollBar() scroll.setValue(scroll.value() + offset) def display_image(self, image_path): print(image_path) self.__scene.clear() item = QGraphicsPixmapItem(QPixmap(image_path)) self.__scene.addItem(item) self.verticalScrollBar().setValue(0) self.update_scale()
class CharIdentifierInput(QDialog, Ui_CharIdentifierInput): """ Get a character A dialog for creating / getting a character The followings are the operations in the dialog -# Painting a character -# Set : analyze the character drawn which is composed from the following stages -# Transform the character to the size of the main item -# Draw a network composed from squares -# Decide which squares are occupied by the character -# Save : Saves the character -# Load : Loads the character from file -# Cancel : exit and retrun False -# OK : exit and return True Graphical structure of the dialog -# Vertical box layout -# Buttons horizontal layout -# GraphicsView which holds a -# Graphics scene which hols a -# CharItem """ def __init__(self, parent, filename: str = None): """CharIdentifierInput constructor Args: parent : The parent window or dialog filename : The character will be loaded from the file """ QDialog.__init__(self, parent) self.setupUi(self) self.setFixedSize(mainItemWidth + 2 * mainItemPadding + 40, mainItemHeight + 2 * mainItemPadding + 60) self.createGui() self.pushButton_set.clicked.connect(self.pushButton_set_clicked) self.pushButton_save.clicked.connect(self.pushButton_save_clicked) self.pushButton_load.clicked.connect(self.pushButton_load_clicked) self.pushButton_cancel.clicked.connect(self.reject) self.pushButton_OK.clicked.connect(self.accept) self.pushButton_reset.clicked.connect(self.pushButton_reset_clicked) self.pushButton_revertSet.clicked.connect( self.pushButton_revertSet_clicked) self.dirty = False self.filename = filename if filename: self.pushButton_load_clicked(filename) def createGui(self): """ Create the scene and the new item """ self.graphicsScene = QGraphicsScene() self.graphicsView.setScene(self.graphicsScene) self.itemBoundaries = QRectF(0, 0, mainItemWidth, mainItemHeight) self.itemPos = QPointF(mainItemPadding + 3, mainItemPadding) self.graphicsScene.setSceneRect(0, 0, mainItemWidth + 2 * mainItemPadding, mainItemHeight + 2 * mainItemPadding) self.newItem() def newItem(self): """ Create new main item """ self.mainItem = CharItem(self.itemBoundaries, self.itemPos) self.graphicsScene.addItem(self.mainItem) def pushButton_set_clicked(self): """ Activate the set operation of the main item """ self.mainItem.set() def pushButton_save_clicked(self): """ Slot : Activate the save operation """ # If there where no changes - return if not self.mainItem.dirty: QMessageBox.critical(None, "Character Identifier - Save", "Nothing to save") return # Get the previous filename and path path = QFileInfo( self.filename).path() if self.filename else os.path.join( dataDir, "Chapter 3 - Distance Metrics") fname = QFileDialog.getSaveFileName( self, "Character Identifier - Save", path, "Character Identifier Files (*.chr)") # If the user pressed the cancel button in the dialog - return if not fname: return if not fname[0].lower().endswith(".chr"): fname[0] += ".chr" self.filename = fname[0] try: # Open the file create the stream and activate the save method of the # main item fh = QFile(self.filename) if not fh.open(QIODevice.WriteOnly): raise IOError(fh.errorString()) stream = QDataStream(fh) self.mainItem.save(stream, self.filename) except IOError as e: QMessageBox.warning( self, "Character Identifier -- Save Error", "Failed to save {}: {}".format(self.filename, e)) finally: if fh is not None: fh.close() def pushButton_load_clicked(self, filename: str = None): """ Slot : Activate the load from file operation """ # If the character was not loaded from a file and no save was done if not self.filename: self.save() path = QFileInfo( self.filename).path() if self.filename else os.path.join( dataDir, "Chapter 3 - Distance Metrics") fname = QFileDialog.getOpenFileName( self, "Character Identifier - Open", path, "Character Identifier Files (*.chr)") if not fname: return self.filename = fname[0] fh = None else: self.filename = filename try: fh = QFile(self.filename) if not fh.open(QIODevice.ReadOnly): raise IOError(fh.errorString()) items = self.graphicsScene.items() while items: item = items.pop() self.graphicsScene.removeItem(item) del item stream = QDataStream(fh) self.mainItem = CharItem(self.itemBoundaries, self.itemPos) self.graphicsScene.addItem(self.mainItem) self.mainItem.load(stream, self.filename) self.dirty = False except IOError as e: QMessageBox.warning( self, "Page Designer -- Open Error", "Failed to open {}: {}".format(self.filename, e)) finally: if fh is not None: fh.close() def accept(self): """ Slot : OK exit """ # If the item was not set - set it if not self.mainItem.wasSetted: self.mainItem.set() # Save the item self.save() return super(CharIdentifierInput, self).accept() def save(self): """ save operation This method is activated before all the operations that cause The item to be removed from the screen """ # If the item was changed - ask for saving if self.mainItem.dirty: if QMessageBox.question( None, "Char Identifier Input", "Do You want to save changes ?", QMessageBox.StandardButtons( QMessageBox.Yes | QMessageBox.No)) == QMessageBox.Yes: self.pushButton_save_clicked() def reject(self): """ Slot : reject operation exit the dialog with true """ self.save() return super(CharIdentifierInput, self).accept() def pushButton_reset_clicked(self): """ Slot : clear the presentation """ self.save() self.graphicsScene.clear() self.graphicsView.viewport().update() self.newItem() def pushButton_revertSet_clicked(self): """ Slot : revert the setting for continue drowning """ self.mainItem.revertTransform()
class frameArbol(QGraphicsView): def __init__(self): super(frameArbol, self).__init__() # Inicializar el arbol de entornos self.arbolEntornos = None # Definir la ubicacion inicial en el cuadro de dibujo self.y = 50 # Definir el cuadro de dibujo haciendo uso de librerias externas self.panelDibujo = QGraphicsScene() # Asignar el panelDibujo como escena principal del frame del arbol self.setScene(self.panelDibujo) # Indicar en que momento se debe repintar el canvas principal def drawA(self): self.panelDibujo.clear() self.graficar() # Proceso para graficar el arbol, incluyendo sus ambientes(nodos) y sus aristas def graficar(self): raiz = self.arbolEntornos.getRaiz() self.y = 50 self.graficarArbol(raiz, 10, self.y) self.graficarAristas(raiz) # Sobrescribir el metodo mousePressEvent de la libreria QGraphicsView def mousePressEvent(self, event: eventoRaton) -> None: # Capturar las coordenadas sobre las que se realizo el evento coordenadaX = event.pos().x() coordenadaY = event.pos().y() # Ubicar el evento en la escena definida ubicacion = self.mapToScene(event.pos()) # Obtener la reiz del arbol raiz = self.arbolEntornos.getRaiz() if (raiz != None): # Se crea para poder operar el ambiente, tener acceso a el ambienteN = QRect(int(ubicacion.x()), int(ubicacion.y()), raiz.dimension, raiz.dimension) self.verificarNodo(raiz, ambienteN) # Verificar relacion panel-ambiente def verificarNodo(self, ambienteActual, ambienteBuscar): # Verificar si el ambienteActual buscado es el ambienteActual con el evento mouse if ambienteActual.dibujarN.intersects(ambienteBuscar): # Informacion del ambienteBuscar (ambienteActual)zz mensaje = QMessageBox() mensaje.setIcon(QMessageBox.Information) mensaje.setText("Ambiente: " + str(ambienteActual.contenido)) mensaje.exec_() return True else: # Realizar la busqueda en todos los ambientes (nodos) restantes for i in ambienteActual.hijos: self.verificarNodo(i, ambienteBuscar) # Graficar el arbol generado def graficarArbol(self, ambiente, posX, posY): # Crear los esquemas ara utilizar la libreria nodo1 = QPen(Qt.black) nodo2 = QPen(Qt.green) # Asignar coordenada X y Y al nuevo ambiente ambiente.x = posX ambiente.y = self.y # Crear un modelo de ambiente (nodo) ambiente.dibujarN = QRect(ambiente.x, ambiente.y, ambiente.dimension, ambiente.dimension) # Definir si el ambiente esta activo para marcarlo con color diferente a los demas if ambiente.nActivo: self.panelDibujo.addEllipse(ambiente.x, ambiente.y, ambiente.dimension, ambiente.dimension, nodo2) else: self.panelDibujo.addEllipse(ambiente.x, ambiente.y, ambiente.dimension, ambiente.dimension, nodo1) # Informacion que tendra el ambiente cadena = QGraphicsTextItem() cadena.setPlainText(str(ambiente.nombre)) cadena.setPos(QPointF(ambiente.x + 2, ambiente.y - 3)) posX += 50 # Graficar los hijos del ambiente actual for i in ambiente.hijos: self.y += 40 self.graficarArbol(i, posX, self.y) # Graficar las aristas del arbol def graficarAristas(self, ambiente): linea1 = QPen(Qt.black) puntoIni = ambiente.dimension / 2 for i in ambiente.hijos: posXInicial = ambiente.x + ambiente.dimension + 5 posYInicial = ambiente.y + ambiente.dimension - 5 posYFinal = i.y + puntoIni self.panelDibujo.addLine(ambiente.x + ambiente.dimension, posYInicial, posXInicial, posYInicial) self.panelDibujo.addLine(posXInicial, posYInicial, posXInicial, posYFinal, linea1) self.panelDibujo.addLine(posXInicial, posYFinal, i.x, posYFinal, linea1) self.graficarAristas(i)
class BrushingModel(QObject): brushSizeChanged = pyqtSignal(int) brushColorChanged = pyqtSignal(QColor) brushStrokeAvailable = pyqtSignal(QPointF, object) drawnNumberChanged = pyqtSignal(int) minBrushSize = 1 maxBrushSize = 61 defaultBrushSize = 3 defaultDrawnNumber = 1 defaultColor = Qt.white erasingColor = Qt.black erasingNumber = 100 def __init__(self, parent=None): QObject.__init__(self, parent=parent) self.sliceRect = None self.bb = QRect() # bounding box enclosing the drawing self.brushSize = self.defaultBrushSize self.drawColor = self.defaultColor self._temp_color = None self._temp_number = None self.drawnNumber = self.defaultDrawnNumber self.pos = None self.erasing = False self._hasMoved = False self.drawOnto = None # an empty scene, where we add all drawn line segments # a QGraphicsLineItem, and which we can use to then # render to an image self.scene = QGraphicsScene() def toggleErase(self): self.erasing = not (self.erasing) if self.erasing: self.setErasing() else: self.disableErasing() def setErasing(self): self.erasing = True self._temp_color = self.drawColor self._temp_number = self.drawnNumber self.setBrushColor(self.erasingColor) self.brushColorChanged.emit(self.erasingColor) self.setDrawnNumber(self.erasingNumber) def disableErasing(self): self.erasing = False self.setBrushColor(self._temp_color) self.brushColorChanged.emit(self.drawColor) self.setDrawnNumber(self._temp_number) def setBrushSize(self, size): self.brushSize = size self.brushSizeChanged.emit(self.brushSize) def setDrawnNumber(self, num): self.drawnNumber = num self.drawnNumberChanged.emit(num) def getBrushSize(self): return self.brushSize def brushSmaller(self): b = self.brushSize if b > self.minBrushSize: self.setBrushSize(b - 1) def brushBigger(self): b = self.brushSize if self.brushSize < self.maxBrushSize: self.setBrushSize(b + 1) def setBrushColor(self, color): self.drawColor = QColor(color) self.brushColorChanged.emit(self.drawColor) def beginDrawing(self, pos, sliceRect): """ pos -- QPointF-like """ self.sliceRect = sliceRect self.scene.clear() self.bb = QRect() self.pos = QPointF(pos.x(), pos.y()) self._hasMoved = False def endDrawing(self, pos): has_moved = self._hasMoved # _hasMoved will change after calling moveTo if has_moved: self.moveTo(pos) else: assert self.pos == pos self.moveTo(QPointF(pos.x() + 0.0001, pos.y() + 0.0001)) # move a little # Qt seems to use strange rules for determining which pixels to set when rendering a brush stroke to a QImage. # We seem to get better results if we do the following: # 1) Slightly offset the source window because apparently there is a small shift in the data # 2) Render the scene to an image that is MUCH larger than the scene resolution (4x by 4x) # 3) Downsample each 4x4 patch from the large image back to a single pixel in the final image, # applying some threshold to determine if the final pixel is on or off. tempi = QImage( QSize(4 * self.bb.width(), 4 * self.bb.height()), QImage.Format_ARGB32_Premultiplied ) # TODO: format tempi.fill(0) painter = QPainter(tempi) # Offset the source window. At first I thought the right offset was 0.5, because # that would seem to make sure points are rounded to pixel CENTERS, but # experimentation indicates that 0.25 is slightly better for some reason... source_rect = QRectF(QPointF(self.bb.x() + 0.25, self.bb.y() + 0.25), QSizeF(self.bb.width(), self.bb.height())) target_rect = QRectF(QPointF(0, 0), QSizeF(4 * self.bb.width(), 4 * self.bb.height())) self.scene.render(painter, target=target_rect, source=source_rect) painter.end() # Now downsample: convert each 4x4 patch into a single pixel by summing and dividing ndarr = qimage2ndarray.rgb_view(tempi)[:, :, 0].astype(int) ndarr = ndarr.reshape((ndarr.shape[0],) + (ndarr.shape[1] // 4,) + (4,)) ndarr = ndarr.sum(axis=-1) ndarr = ndarr.transpose() ndarr = ndarr.reshape((ndarr.shape[0],) + (ndarr.shape[1] // 4,) + (4,)) ndarr = ndarr.sum(axis=-1) ndarr = ndarr.transpose() ndarr //= 4 * 4 downsample_threshold = (7.0 / 16) * 255 labels = numpy.where(ndarr >= downsample_threshold, numpy.uint8(self.drawnNumber), numpy.uint8(0)) labels = labels.swapaxes(0, 1) assert labels.shape[0] == self.bb.width() assert labels.shape[1] == self.bb.height() ## ## ensure that at least one pixel is label when the brush size is 1 ## ## this happens when the user just clicked without moving ## in that case the lineitem will be so tiny, that it won't be rendered ## into a single pixel by the code above if not has_moved and self.brushSize <= 1 and numpy.count_nonzero(labels) == 0: labels[labels.shape[0] // 2, labels.shape[1] // 2] = self.drawnNumber self.brushStrokeAvailable.emit(QPointF(self.bb.x(), self.bb.y()), labels) def dumpDraw(self, pos): res = self.endDrawing(pos) self.beginDrawing(pos, self.sliceRect) return res def moveTo(self, pos): # data coordinates oldX, oldY = self.pos.x(), self.pos.y() x, y = pos.x(), pos.y() line = QGraphicsLineItem(oldX, oldY, x, y) line.setPen(QPen(QBrush(Qt.white), self.brushSize, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) self.scene.addItem(line) self._hasMoved = True # update bounding Box if not self.bb.isValid(): self.bb = QRect(QPoint(oldX, oldY), QSize(1, 1)) # grow bounding box self.bb.setLeft(min(self.bb.left(), max(0, x - self.brushSize // 2 - 1))) self.bb.setRight(max(self.bb.right(), min(self.sliceRect[0] - 1, x + self.brushSize // 2 + 1))) self.bb.setTop(min(self.bb.top(), max(0, y - self.brushSize // 2 - 1))) self.bb.setBottom(max(self.bb.bottom(), min(self.sliceRect[1] - 1, y + self.brushSize // 2 + 1))) # update/move position self.pos = pos
class MapPainter(object): def __init__(self, parent, view, displayCities, displayConnections, displayBestUnit): super().__init__() self.view = view self.displayCities = displayCities self.displayConnections = displayConnections self.displayBestUnit = displayBestUnit self.problemMap = None self.bestUnit = None self.scene = QGraphicsScene(parent) self.resizeScene() self.view.setScene(self.scene) self.view.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio) def resizeScene(self): height = self.view.size().height() width = self.view.size().width() self.scene.setSceneRect(0.0, 0.0, width, height) def setProblemMap(self, problemMap): self.problemMap = problemMap def setBestUnit(self, unit): self.bestUnit = unit def setDisplayCities(self, enabled=False): self.displayCities = bool(enabled) def setDisplayConnections(self, enabled=False): self.displayConnections = bool(enabled) def setDisplayBestUnit(self, enabled=False): self.displayBestUnit = bool(enabled) def repaint(self): if self.problemMap is None: return self.scene.clear() self.resizeScene() height = self.scene.height() width = self.scene.width() if self.displayCities: cityBrush = QBrush(QColor(0, 0, 0), Qt.SolidPattern) cityPen = QPen(cityBrush, 5.0) for city in self.problemMap.cities: x = width * city.positionX y = height * city.positionY self.scene.addEllipse(x, y, 4, 4, cityPen, cityBrush) if self.displayConnections: connectionBrush = QBrush(QColor(0, 0, 255), Qt.SolidPattern) connectionPen = QPen(connectionBrush, 1.0) for city in self.problemMap.cities: for neighbour in city.connections: x = width * city.positionX y = height * city.positionY x2 = width * self.problemMap.cities[neighbour].positionX y2 = height * self.problemMap.cities[neighbour].positionY self.scene.addLine(x, y, x2, y2, connectionPen) if self.displayBestUnit and self.bestUnit is not None: bestUnitBrush = QBrush(QColor(255, 0, 0), Qt.SolidPattern) bestUnitPen = QPen(bestUnitBrush, 2.0) for i in range(-1, len(self.bestUnit.path) - 1): currCity = self.problemMap.cities[self.bestUnit.path[i]] nextCity = self.problemMap.cities[self.bestUnit.path[i + 1]] x = width * currCity.positionX y = height * currCity.positionY x2 = width * nextCity.positionX y2 = height * nextCity.positionY self.scene.addLine(x, y, x2, y2, bestUnitPen) self.view.fitInView(self.scene.sceneRect())
class MapPainter(object): def __init__(self, parent, view, displayCities, displayConnections, displayBestUnit): super().__init__() self.view = view self.displayCities = displayCities self.displayConnections = displayConnections self.displayBestUnit = displayBestUnit self.problemMap = None self.bestUnit = None self.scene = QGraphicsScene(parent) self.resizeScene() self.view.setScene(self.scene) self.view.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio) def resizeScene(self): height = self.view.size().height() width = self.view.size().width() self.scene.setSceneRect(0.0, 0.0, width, height) def setProblemMap(self, problemMap): self.problemMap = problemMap def setBestUnit(self, unit): self.bestUnit = unit def setDisplayCities(self, enabled = False): self.displayCities = bool(enabled) def setDisplayConnections(self, enabled = False): self.displayConnections = bool(enabled) def setDisplayBestUnit(self, enabled = False): self.displayBestUnit = bool(enabled) def repaint(self): if self.problemMap is None: return self.scene.clear() self.resizeScene() height = self.scene.height() width = self.scene.width() if self.displayCities: cityBrush = QBrush(QColor(0, 0, 0), Qt.SolidPattern) cityPen = QPen(cityBrush, 5.0) for city in self.problemMap.cities: x = width * city.positionX y = height * city.positionY self.scene.addEllipse(x, y, 4, 4, cityPen, cityBrush) if self.displayConnections: connectionBrush = QBrush(QColor(0, 0, 255), Qt.SolidPattern) connectionPen = QPen(connectionBrush, 1.0) for city in self.problemMap.cities: for neighbour in city.connections: x = width * city.positionX y = height * city.positionY x2 = width * self.problemMap.cities[neighbour].positionX y2 = height * self.problemMap.cities[neighbour].positionY self.scene.addLine(x, y, x2, y2, connectionPen) if self.displayBestUnit and self.bestUnit is not None: bestUnitBrush = QBrush(QColor(255, 0, 0), Qt.SolidPattern) bestUnitPen = QPen(bestUnitBrush, 2.0) for i in range(-1, len(self.bestUnit.path)-1): currCity = self.problemMap.cities[self.bestUnit.path[i]] nextCity = self.problemMap.cities[self.bestUnit.path[i+1]] x = width * currCity.positionX y = height * currCity.positionY x2 = width * nextCity.positionX y2 = height * nextCity.positionY self.scene.addLine(x, y, x2, y2, bestUnitPen) self.view.fitInView(self.scene.sceneRect())
class GUI(Ui_MainWindow): def __init__(self): super().setupUi(MainWindow) self.initUI() #connect widgets with functions def initUI(self): self.scene1=QGraphicsScene() self.scene2=QGraphicsScene() self.scene3=QGraphicsScene() self.scene4=QGraphicsScene() self.actionOpen.triggered.connect(self.imageOpen) self.histogram.clicked.connect(self.imageHistogram) self.GrayvalueScrollBar.valueChanged.connect(self.sliderval) self.OTSU.clicked.connect(self.OTSUThreshold) self.MedianFilter.clicked.connect(self.medianfilter) self.MeanFilter.clicked.connect(self.meanfilter) self.GaussianFilter.clicked.connect(self.gaussianfilter) self.CoustomizedFilter.clicked.connect(self.coustomizefilter) self.BinaryErosion.clicked.connect(self.binaryerosion) self.BinaryDilation.clicked.connect(self.binarydilation) self.actionClear_All.triggered.connect(self.clearall) self.DistanceTransform.clicked.connect(self.distancetransform) self.Skeleton.clicked.connect(self.skeleton) self.SkeletonRestoration.clicked.connect(self.skeletonrestoration) self.GrayErosion.clicked.connect(self.grayerosion) self.GrayDilation.clicked.connect(self.graydilation) self.EdgeDetection.clicked.connect(self.edgedetection) self.Gradient.clicked.connect(self.gradient) self.Reconstraction_Binary.clicked.connect(self.reconstruction_binary) self.Reconstraction_Gray.clicked.connect(self.reconstruction_gray) #function menubar-file-open: Open image and show it in view1 def imageOpen(self): # filename,_ = QFileDialog.getOpenFileName(MainWindow,'Open a image',os.getenv('HOME')) filename,_ = QFileDialog.getOpenFileName(MainWindow,'Open a image','.',"Image Files(*.bmp *jpg *png *jpeg)") # filename="/home/lab105/git-sen/python_gui/lena512.bmp" # print(filename) pix=QtGui.QPixmap(filename) pix=pix.scaledToHeight(256) self.image=plt.imread(filename) Size=self.image.shape if (len(Size)==3): if (type(self.image[1,1,1]) is np.float32): self.image=misc.imread(filename) self.image=self.image[:,:,1] self.image_temp=self.image self.scene1.addPixmap(QPixmap(pix)) self.View1.setScene(self.scene1) self.clearall() #function mainwindow tab histogram-greylevel histogram: compute and show the greyvalue histogram in view 2 def imageHistogram(self): greyimage=self.image #greyimage.dtype Height, Width=greyimage.shape x=np.zeros(Height*Width) for h in range(Height): for w in range(Width): x[h*Height+w]=greyimage[h,w] num_bins=255 plt.figure(figsize=(256,256),dpi=1) n,self.bins,patches=plt.hist(x,num_bins,normed=1,facecolor='green',alpha=0.5) plt.axis("off") plt.gca().set_position([0,0,1,1]) self.figure=plt.gcf() canvas2=FigureCanvas(self.figure) self.scene2.addWidget(canvas2) self.View2.setScene(self.scene2) def sliderval(self): Threshold=self.GrayvalueScrollBar.value() self.Binarization(Threshold) # self.label.setText(str(Threshold)) #threshlod function def Binarization(self,Threshold): #filename="/home/lab105/git-sen/python_gui/lena512.bmp" #img=misc.imread(filename) img=self.image BinaryArray= img >Threshold plt.close(3) plt.figure(num=3,figsize=(256,256),dpi=1) plt.axis("off") plt.gca().set_position([0,0,1,1]) plt.imshow(BinaryArray,cmap='binary_r') figure3=plt.gcf() canvas3=FigureCanvas(figure3) self.scene3.clear() self.scene3.addWidget(canvas3) self.View3.setScene(self.scene3) self.label.setText(str(Threshold)) def OTSUThreshold(self): img=self.image thresh=threshold_otsu(img) binary=img > thresh self.showView4(binary) def showView4(self,image): plt.close(4) plt.figure(num=4,figsize=(256,256),dpi=1) if (image.max()>1): plt.imshow(image,cmap='gray') else: plt.imshow(image,cmap='binary_r') plt.gca().set_position([0,0,1,1]) plt.axis("off") figure4=plt.gcf() canvas4=FigureCanvas(figure4) self.scene4.clear() self.scene4.addWidget(canvas4) self.View4.setScene(self.scene4) def getmatrixsize(self): matrixsize=3 if (self.radioButton_1.isChecked()): matrixsize=3 if (self.radioButton_2.isChecked()): matrixsize=5 return matrixsize def medianfilter(self): self.image_temp=ndimage.median_filter(self.image_temp,size=int(self.plainTextEdit.toPlainText())) self.showView4(self.image_temp) def meanfilter(self): self.image_temp=ndimage.uniform_filter(self.image_temp,size=int(self.plainTextEdit.toPlainText())) self.showView4(self.image_temp) def gaussianfilter(self): self.image_temp=ndimage.gaussian_filter(self.image_temp,sigma=float(self.plainTextEdit_2.toPlainText())) self.showView4(self.image_temp) def getmatrix(self): self.Matrix=[] if (self.getmatrixsize()==3): matrix=np.zeros((3,3)) matrix[0,0]=float(self.plainTextEdit1_1.toPlainText()) matrix[0,1]=float(self.plainTextEdit1_2.toPlainText()) matrix[0,2]=float(self.plainTextEdit1_3.toPlainText()) matrix[1,0]=float(self.plainTextEdit2_1.toPlainText()) matrix[1,1]=float(self.plainTextEdit2_2.toPlainText()) matrix[1,2]=float(self.plainTextEdit2_3.toPlainText()) matrix[2,0]=float(self.plainTextEdit3_1.toPlainText()) matrix[2,1]=float(self.plainTextEdit3_2.toPlainText()) matrix[2,2]=float(self.plainTextEdit3_3.toPlainText()) if (matrix.max()==0): matrix[:,:]=1 if (self.getmatrixsize()==5): matrix=np.zeros((5,5)) matrix[0,0]=float(self.plainTextEdit1_1.toPlainText()) matrix[0,1]=float(self.plainTextEdit1_2.toPlainText()) matrix[0,2]=float(self.plainTextEdit1_3.toPlainText()) matrix[0,3]=float(self.plainTextEdit1_4.toPlainText()) matrix[0,4]=float(self.plainTextEdit1_5.toPlainText()) matrix[1,0]=float(self.plainTextEdit2_1.toPlainText()) matrix[1,1]=float(self.plainTextEdit2_2.toPlainText()) matrix[1,2]=float(self.plainTextEdit2_3.toPlainText()) matrix[1,3]=float(self.plainTextEdit2_4.toPlainText()) matrix[1,4]=float(self.plainTextEdit2_5.toPlainText()) matrix[2,0]=float(self.plainTextEdit3_1.toPlainText()) matrix[2,1]=float(self.plainTextEdit3_2.toPlainText()) matrix[2,2]=float(self.plainTextEdit3_3.toPlainText()) matrix[2,3]=float(self.plainTextEdit3_4.toPlainText()) matrix[2,4]=float(self.plainTextEdit3_5.toPlainText()) matrix[3,0]=float(self.plainTextEdit4_1.toPlainText()) matrix[3,1]=float(self.plainTextEdit4_2.toPlainText()) matrix[3,2]=float(self.plainTextEdit4_3.toPlainText()) matrix[3,3]=float(self.plainTextEdit4_4.toPlainText()) matrix[3,4]=float(self.plainTextEdit4_5.toPlainText()) matrix[4,0]=float(self.plainTextEdit5_1.toPlainText()) matrix[4,1]=float(self.plainTextEdit5_2.toPlainText()) matrix[4,2]=float(self.plainTextEdit5_3.toPlainText()) matrix[4,3]=float(self.plainTextEdit5_4.toPlainText()) matrix[4,4]=float(self.plainTextEdit5_5.toPlainText()) if (matrix.max()==0): matrix[:,:]=1 self.Matrix=matrix def coustomizefilter(self): self.getmatrix() self.image_temp=ndimage.correlate(self.image_temp,self.Matrix) self.showView4(self.image_temp) def binaryerosion(self): self.getmatrix() self.image_temp=ndimage.binary_erosion(self.image_temp,self.Matrix) self.showView4(self.image_temp) def binarydilation(self): self.getmatrix() self.image_temp=ndimage.binary_dilation(self.image_temp,self.Matrix) self.showView4(self.image_temp) def distancetransform(self): Size=self.image_temp.shape distance=np.zeros(Size) distance=distance+self.image_temp self.getmatrix() while (self.image_temp.max()!=0): self.image_temp=ndimage.binary_erosion(self.image_temp,self.Matrix) distance=distance+self.image_temp self.image_temp=self.image self.showView4(distance) def clearall(self): self.scene2.clear() self.scene3.clear() self.scene4.clear() self.image_temp=self.image def skeleton(self): Size=self.image_temp.shape skeleton=np.zeros(Size) self.store=np.zeros(Size) skeleton_remain=self.image_temp i=1 while (skeleton_remain.max()!=0): skeleton_remain=ndimage.binary_erosion(self.image_temp,np.ones([2*i-1,2*i-1])) subset=skeleton_remain-ndimage.binary_opening(skeleton_remain,np.ones([3,3])) skeleton=np.logical_or(skeleton,subset) self.store=self.store+subset*i i=i+1 self.showView4(skeleton) def skeletonrestoration(self): i=self.store.max() Size=self.image_temp.shape result=mid_result=np.zeros(Size) while (i!=0): index= self.store == i mid_result=ndimage.binary_dilation(index,np.ones([2*i-1,2*i-1])) result=np.logical_or(result,mid_result) i=i-1 self.showView4(result) def grayerosion(self): self.getmatrix() self.image_temp=ndimage.grey_erosion(self.image_temp,footprint=self.Matrix) self.showView4(self.image_temp) def graydilation(self): self.getmatrix() self.image_temp=ndimage.grey_dilation(self.image_temp,footprint=self.Matrix) self.showView4(self.image_temp) def getEdgeType(self): Type='S' if (self.S.isChecked()): Type='S' if (self.I.isChecked()): Type='I' if (self.E.isChecked()): Type='E' return Type def edgedetection(self): Type=self.getEdgeType() Size=self.image_temp.shape EdgeImage=np.zeros(Size) if (Type=='S'): EdgeImage=ndimage.grey_dilation(self.image_temp,footprint=np.ones([3,3]))-ndimage.grey_erosion(self.image_temp,footprint=np.ones([3,3])) if (Type=='I'): EdgeImage=self.image_temp-ndimage.grey_erosion(self.image_temp,footprint=np.ones([3,3])) if (Type=='E'): EdgeImage=ndimage.grey_dilation(self.image_temp,footprint=np.ones([3,3]))-self.image_temp self.showView4(EdgeImage) def gradient(self): Type=self.getEdgeType() Size=self.image_temp.shape EdgeImage=np.zeros(Size) if (Type=='S'): EdgeImage=(ndimage.grey_dilation(self.image_temp,footprint=np.ones([3,3]))-ndimage.grey_erosion(self.image_temp,footprint=np.ones([3,3])))/2 if (Type=='I'): EdgeImage=(self.image_temp-ndimage.grey_erosion(self.image_temp,footprint=np.ones([3,3])))/2 if (Type=='E'): EdgeImage=(ndimage.grey_dilation(self.image_temp,footprint=np.ones([3,3]))-self.image_temp)/2 self.showView4(EdgeImage) def reconstruction_binary(self): Size=self.image_temp.shape Mark_temp=np.zeros(Size) Mark=np.zeros(Size) Mark[:,112]=1 while ((not np.array_equal(Mark,Mark_temp))): Mark_temp=Mark Mark=ndimage.binary_dilation(Mark,np.ones([3,3])) Mark=np.logical_and(Mark,self.image_temp) self.showView4(Mark) def reconstruction_gray(self): Size=self.image_temp.shape Mark_temp=np.zeros(Size) Mark=np.zeros(Size) Mark[:,112]=self.image_temp[:,112] while ((not np.array_equal(Mark,Mark_temp))): Mark_temp=Mark Mark=ndimage.grey_dilation(Mark,footprint=np.ones([3,3])) logical=Mark >= self.image_temp Mark=Mark-Mark*logical+self.image_temp*logical self.showView4(Mark)
class BrushingModel(QObject): brushSizeChanged = pyqtSignal(int) brushColorChanged = pyqtSignal(QColor) brushStrokeAvailable = pyqtSignal(QPointF, object) drawnNumberChanged = pyqtSignal(int) minBrushSize = 1 maxBrushSize = 61 defaultBrushSize = 3 defaultDrawnNumber = 1 defaultColor = Qt.white erasingColor = Qt.black erasingNumber = 100 def __init__(self, parent=None): QObject.__init__(self, parent=parent) self.sliceRect = None self.bb = QRect() #bounding box enclosing the drawing self.brushSize = self.defaultBrushSize self.drawColor = self.defaultColor self._temp_color = None self._temp_number = None self.drawnNumber = self.defaultDrawnNumber self.pos = None self.erasing = False self._hasMoved = False self.drawOnto = None #an empty scene, where we add all drawn line segments #a QGraphicsLineItem, and which we can use to then #render to an image self.scene = QGraphicsScene() def toggleErase(self): self.erasing = not (self.erasing) if self.erasing: self.setErasing() else: self.disableErasing() def setErasing(self): self.erasing = True self._temp_color = self.drawColor self._temp_number = self.drawnNumber self.setBrushColor(self.erasingColor) self.brushColorChanged.emit(self.erasingColor) self.setDrawnNumber(self.erasingNumber) def disableErasing(self): self.erasing = False self.setBrushColor(self._temp_color) self.brushColorChanged.emit(self.drawColor) self.setDrawnNumber(self._temp_number) def setBrushSize(self, size): self.brushSize = size self.brushSizeChanged.emit(self.brushSize) def setDrawnNumber(self, num): self.drawnNumber = num self.drawnNumberChanged.emit(num) def getBrushSize(self): return self.brushSize def brushSmaller(self): b = self.brushSize if b > self.minBrushSize: self.setBrushSize(b - 1) def brushBigger(self): b = self.brushSize if self.brushSize < self.maxBrushSize: self.setBrushSize(b + 1) def setBrushColor(self, color): self.drawColor = QColor(color) self.brushColorChanged.emit(self.drawColor) def beginDrawing(self, pos, sliceRect): ''' pos -- QPointF-like ''' self.sliceRect = sliceRect self.scene.clear() self.bb = QRect() self.pos = QPointF(pos.x(), pos.y()) self._hasMoved = False def endDrawing(self, pos): has_moved = self._hasMoved # _hasMoved will change after calling moveTo if has_moved: self.moveTo(pos) else: assert (self.pos == pos) self.moveTo(QPointF(pos.x() + 0.0001, pos.y() + 0.0001)) # move a little # Qt seems to use strange rules for determining which pixels to set when rendering a brush stroke to a QImage. # We seem to get better results if we do the following: # 1) Slightly offset the source window because apparently there is a small shift in the data # 2) Render the scene to an image that is MUCH larger than the scene resolution (4x by 4x) # 3) Downsample each 4x4 patch from the large image back to a single pixel in the final image, # applying some threshold to determine if the final pixel is on or off. tempi = QImage(QSize(4 * self.bb.width(), 4 * self.bb.height()), QImage.Format_ARGB32_Premultiplied) #TODO: format tempi.fill(0) painter = QPainter(tempi) # Offset the source window. At first I thought the right offset was 0.5, because # that would seem to make sure points are rounded to pixel CENTERS, but # experimentation indicates that 0.25 is slightly better for some reason... source_rect = QRectF(QPointF(self.bb.x() + 0.25, self.bb.y() + 0.25), QSizeF(self.bb.width(), self.bb.height())) target_rect = QRectF(QPointF(0, 0), QSizeF(4 * self.bb.width(), 4 * self.bb.height())) self.scene.render(painter, target=target_rect, source=source_rect) painter.end() # Now downsample: convert each 4x4 patch into a single pixel by summing and dividing ndarr = qimage2ndarray.rgb_view(tempi)[:, :, 0].astype(int) ndarr = ndarr.reshape((ndarr.shape[0], ) + (ndarr.shape[1] // 4, ) + (4, )) ndarr = ndarr.sum(axis=-1) ndarr = ndarr.transpose() ndarr = ndarr.reshape((ndarr.shape[0], ) + (ndarr.shape[1] // 4, ) + (4, )) ndarr = ndarr.sum(axis=-1) ndarr = ndarr.transpose() ndarr //= 4 * 4 downsample_threshold = (7. / 16) * 255 labels = numpy.where(ndarr >= downsample_threshold, numpy.uint8(self.drawnNumber), numpy.uint8(0)) labels = labels.swapaxes(0, 1) assert labels.shape[0] == self.bb.width() assert labels.shape[1] == self.bb.height() ## ## ensure that at least one pixel is label when the brush size is 1 ## ## this happens when the user just clicked without moving ## in that case the lineitem will be so tiny, that it won't be rendered ## into a single pixel by the code above if not has_moved and self.brushSize <= 1 and numpy.count_nonzero( labels) == 0: labels[labels.shape[0] // 2, labels.shape[1] // 2] = self.drawnNumber self.brushStrokeAvailable.emit(QPointF(self.bb.x(), self.bb.y()), labels) def dumpDraw(self, pos): res = self.endDrawing(pos) self.beginDrawing(pos, self.sliceRect) return res def moveTo(self, pos): #data coordinates oldX, oldY = self.pos.x(), self.pos.y() x, y = pos.x(), pos.y() line = QGraphicsLineItem(oldX, oldY, x, y) line.setPen( QPen(QBrush(Qt.white), self.brushSize, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) self.scene.addItem(line) self._hasMoved = True #update bounding Box if not self.bb.isValid(): self.bb = QRect(QPoint(oldX, oldY), QSize(1, 1)) #grow bounding box self.bb.setLeft( min(self.bb.left(), max(0, x - self.brushSize // 2 - 1))) self.bb.setRight( max(self.bb.right(), min(self.sliceRect[0] - 1, x + self.brushSize // 2 + 1))) self.bb.setTop(min(self.bb.top(), max(0, y - self.brushSize // 2 - 1))) self.bb.setBottom( max(self.bb.bottom(), min(self.sliceRect[1] - 1, y + self.brushSize // 2 + 1))) #update/move position self.pos = pos
class Spectrum(QWidget): """Plot the power spectrum for a specified channel. Attributes ---------- parent : instance of QMainWindow the main window. x_limit : tuple or list 2 values specifying the limit on x-axis y_limit : tuple or list 2 values specifying the limit on y-axis log : bool log-transform the data or not idx_chan : instance of QComboBox the element with the list of channel names. idx_x_min : instance of QLineEdit value with min x value idx_x_max : instance of QLineEdit value with max x value idx_y_min : instance of QLineEdit value with min y value idx_y_max : instance of QLineEdit value with max y value idx_log : instance of QCheckBox widget that defines if log should be used or not idx_fig : instance of QGraphicsView the view with the power spectrum scene : instance of QGraphicsScene the scene with GraphicsItems Notes ----- If data contains NaN, it doesn't create any spectrum (feature or bug?). """ def __init__(self, parent): super().__init__() self.parent = parent self.config = ConfigSpectrum(self.display_window) self.selected_chan = None self.idx_chan = None self.idx_fig = None self.scene = None self.create() def create(self): """Create empty scene for power spectrum.""" self.idx_chan = QComboBox() self.idx_chan.activated.connect(self.display_window) self.idx_fig = QGraphicsView(self) self.idx_fig.scale(1, -1) layout = QVBoxLayout() layout.addWidget(self.idx_chan) layout.addWidget(self.idx_fig) self.setLayout(layout) self.resizeEvent(None) def show_channame(self, chan_name): self.selected_chan = self.idx_chan.currentIndex() self.idx_chan.clear() self.idx_chan.addItem(chan_name) self.idx_chan.setCurrentIndex(0) def update(self): """Add channel names to the combobox.""" self.idx_chan.clear() for chan_name in self.parent.traces.chan: self.idx_chan.addItem(chan_name) if self.selected_chan is not None: self.idx_chan.setCurrentIndex(self.selected_chan) self.selected_chan = None def display_window(self): """Read the channel name from QComboBox and plot its spectrum. This function is necessary it reads the data and it sends it to self.display. When the user selects a smaller chunk of data from the visible traces, then we don't need to call this function. """ if self.idx_chan.count() == 0: self.update() chan_name = self.idx_chan.currentText() lg.info('Power spectrum for channel ' + chan_name) if chan_name: trial = 0 data = self.parent.traces.data(trial=trial, chan=chan_name) self.display(data) else: self.scene.clear() def display(self, data): """Make graphicsitem for spectrum figure. Parameters ---------- data : ndarray 1D vector containing the data only This function can be called by self.display_window (which reads the data for the selected channel) or by the mouse-events functions in traces (which read chunks of data from the user-made selection). """ value = self.config.value self.scene = QGraphicsScene(value['x_min'], value['y_min'], value['x_max'] - value['x_min'], value['y_max'] - value['y_min']) self.idx_fig.setScene(self.scene) self.add_grid() self.resizeEvent(None) s_freq = self.parent.traces.data.s_freq f, Pxx = welch(data, fs=s_freq, nperseg=int(min((s_freq, len(data))))) # force int freq_limit = (value['x_min'] <= f) & (f <= value['x_max']) if self.config.value['log']: Pxx_to_plot = log(Pxx[freq_limit]) else: Pxx_to_plot = Pxx[freq_limit] self.scene.addPath(Path(f[freq_limit], Pxx_to_plot), QPen(QColor(LINE_COLOR), LINE_WIDTH)) def add_grid(self): """Add axis and ticks to figure. Notes ----- I know that visvis and pyqtgraphs can do this in much simpler way, but those packages create too large a padding around the figure and this is pretty fast. """ value = self.config.value # X-AXIS # x-bottom self.scene.addLine(value['x_min'], value['y_min'], value['x_min'], value['y_max'], QPen(QColor(LINE_COLOR), LINE_WIDTH)) # at y = 0, dashed self.scene.addLine(value['x_min'], 0, value['x_max'], 0, QPen(QColor(LINE_COLOR), LINE_WIDTH, Qt.DashLine)) # ticks on y-axis y_high = int(floor(value['y_max'])) y_low = int(ceil(value['y_min'])) x_length = (value['x_max'] - value['x_min']) / value['x_tick'] for y in range(y_low, y_high): self.scene.addLine(value['x_min'], y, value['x_min'] + x_length, y, QPen(QColor(LINE_COLOR), LINE_WIDTH)) # Y-AXIS # left axis self.scene.addLine(value['x_min'], value['y_min'], value['x_max'], value['y_min'], QPen(QColor(LINE_COLOR), LINE_WIDTH)) # larger ticks on x-axis every 10 Hz x_high = int(floor(value['x_max'])) x_low = int(ceil(value['x_min'])) y_length = (value['y_max'] - value['y_min']) / value['y_tick'] for x in range(x_low, x_high, 10): self.scene.addLine(x, value['y_min'], x, value['y_min'] + y_length, QPen(QColor(LINE_COLOR), LINE_WIDTH)) # smaller ticks on x-axis every 10 Hz y_length = (value['y_max'] - value['y_min']) / value['y_tick'] / 2 for x in range(x_low, x_high, 5): self.scene.addLine(x, value['y_min'], x, value['y_min'] + y_length, QPen(QColor(LINE_COLOR), LINE_WIDTH)) def resizeEvent(self, event): """Fit the whole scene in view. Parameters ---------- event : instance of Qt.Event not important """ value = self.config.value self.idx_fig.fitInView(value['x_min'], value['y_min'], value['x_max'] - value['x_min'], value['y_max'] - value['y_min']) def reset(self): """Reset widget as new""" self.idx_chan.clear() if self.scene is not None: self.scene.clear() self.scene = None
class TrainerDialog(QDialog, Ui_Trainer): scene = None data_manager = None tooth1 = None tooth2 = None align_step = 0 pca = None trained = pyqtSignal(PCA) def __init__(self, data_manager): super(TrainerDialog, self).__init__() self.setupUi(self) self.setAttribute(Qt.WA_DeleteOnClose) self.scene = QGraphicsScene() self.scene.setBackgroundBrush(QBrush(QColor.fromRgb(50, 50, 50))) self.graphicsView.setScene(self.scene) self.alignButton.clicked.connect(self.make_step) self.trainButton.clicked.connect(self.train) assert isinstance(data_manager, DataManager) self.data_manager = data_manager self.change_teeth(1) teeth = data_manager.get_all_teeth(False) self.choiceSlider.setRange(1, len(teeth) - 1) self.choiceSlider.valueChanged.connect(self.change_teeth) def change_teeth(self, idx): teeth = self.data_manager.get_all_teeth(True) self.tooth1 = teeth[0] self.tooth2 = teeth[idx] self.tooth1.outline_pen = QPen(QColor.fromRgb(255, 0, 0)) self.tooth2.outline_pen = QPen(QColor.fromRgb(0, 255, 0)) self.scene.clear() self.tooth1.draw(self.scene, True, False, False) self.tooth2.draw(self.scene, True, False, False) self._focus_view() self.align_step = 0 def make_step(self): if self.align_step == 3: return if self.align_step == 0: self.tooth1.move_to_origin() self.tooth2.move_to_origin() if self.align_step == 1: self.tooth1.normalize_shape() self.tooth2.normalize_shape() self.tooth1.outline_pen.setWidthF(0.02) self.tooth2.outline_pen.setWidthF(0.02) if self.align_step == 2: self.tooth2.align(self.tooth1) self.scene.clear() self.tooth1.draw(self.scene, True, False, False) self.tooth2.draw(self.scene, True, False, False) self._focus_view() self.align_step += 1 def _focus_view(self): rect = self.scene.itemsBoundingRect() self.scene.setSceneRect(rect) self.graphicsView.fitInView(rect, Qt.KeepAspectRatio) def train(self): self.pca = StatisticalShapeModel.create(self.data_manager) self.pca.threshold(self.thresholdSpinBox.value()) self._show_training_result() self.trained.emit(self.pca) def _show_training_result(self): mean_tooth = Tooth(to_landmarks_format(self.pca.mean)) test_tooth = self.data_manager.get_tooth(0, 0, True) test_tooth.align(mean_tooth) tooth_data = test_tooth.landmarks.flatten() projection = self.pca.project(tooth_data) reconstructed_data = self.pca.reconstruct(projection) shapes = [self.pca.mean, tooth_data, reconstructed_data] colors = [[255, 0, 0], [0, 255, 255], [255, 255, 0]] self.scene.clear() for i, shape in enumerate(shapes): tooth = Tooth(to_landmarks_format(shape)) r, g, b = colors[i] tooth.outline_pen = QPen(QColor.fromRgb(r, g, b)) tooth.outline_pen.setWidthF(0.02) tooth.draw(self.scene, True, False, False) self._focus_view() self.compCountLabel.setText(str(len(self.pca.eigen_values)))
class qfi_VSI (QGraphicsView): viewUpdate = pyqtSignal() def __init__(self,winParent): QGraphicsView.__init__(self) self.winParent=winParent self.viewUpdate.connect(self.update) self.m_climbRate = 0 self.m_scaleX = 0 self.m_scaleY = 0 self.m_originalHeight = 240 self.m_originalWidth = 240 self.m_originalVsiCtr = QPointF(120,120) self.m_faceZ = -20 self.m_handZ = -10 self.m_caseZ = 10 self.m_itemHand = None self.m_itemFace = None self.m_itemCase = None self.setStyleSheet("background: transparent; border: none"); self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setInteractive(False) self.setEnabled(False) self.m_scene = QGraphicsScene(self) self.setScene(self.m_scene) self.init() def init (self): self.m_scaleX = self.width() / self.m_originalWidth self.m_scaleY = self.height() / self.m_originalHeight self.m_itemHand = QGraphicsSvgItem(":/qfi/images/vsi/vsi_hand.svg") self.m_itemHand.setCacheMode (QGraphicsItem.NoCache) self.m_itemHand.setZValue( self.m_handZ ) self.m_itemHand.setTransform( QTransform.fromScale( self.m_scaleX, self.m_scaleY ), True ) self.m_itemHand.setTransformOriginPoint( self.m_originalVsiCtr ) self.m_scene.addItem (self.m_itemHand) self.m_itemFace = QGraphicsSvgItem(":/qfi/images/vsi/vsi_face.svg") self.m_itemFace.setCacheMode (QGraphicsItem.NoCache) self.m_itemFace.setZValue( self.m_faceZ ) self.m_itemFace.setTransform( QTransform.fromScale( self.m_scaleX, self.m_scaleY ), True ) self.m_itemFace.setTransformOriginPoint( self.m_originalVsiCtr ) self.m_scene.addItem (self.m_itemFace) self.m_itemCase = QGraphicsSvgItem(":/qfi/images/vsi/vsi_case.svg") self.m_itemCase.setCacheMode (QGraphicsItem.NoCache) self.m_itemCase.setZValue( self.m_caseZ ) self.m_itemCase.setTransform( QTransform.fromScale( self.m_scaleX, self.m_scaleY ), True ) self.m_itemCase.setTransformOriginPoint( self.m_originalVsiCtr ) self.m_scene.addItem (self.m_itemCase) self.centerOn (self.width()/2, self.height()/2) self.updateView() def reinit(self): if (self.m_scene): self.m_scene.clear() self.init() def update(self): self.updateView() def setClimbRate (self, climbRate): self.m_climbRate = climbRate if (self.m_climbRate < -2000): self.m_climbRate = -2000 if (self.m_climbRate > 2000): self.m_climbRate = 2000 def resizeEvent (self, event): QGraphicsView.resizeEvent (self,event) self.reinit() def reset (self): self.m_itemHand = None self.m_itemFace = None self.m_itemCase = None self.m_climbRate = 0.0 def updateView(self): self.m_itemHand.setRotation( self.m_climbRate * 0.086 ) self.m_scene.update()
class CircuitDiagramView(QGraphicsView): mousePress = pyqtSignal(tuple, tuple, name='mousePress') mouseMove = pyqtSignal(tuple, tuple, name='mouseMove') mouseRelease = pyqtSignal(tuple, tuple, name='mouseRelease') def __init__(self, parent=None): QGraphicsView.__init__(self, parent) self._model = None self.controller = None self.setAcceptDrops(True) # setup & render circuit diagram grid self.scene = QGraphicsScene() self.setScene(self.scene) self._shouldShowSelection = False self._selection = None self._dragging = False self.mousePosition = None self.draggingStart = None self.render() @property def shouldShowSelection(self): return self._shouldShowSelection @shouldShowSelection.setter def shouldShowSelection(self, value): if self.shouldShowSelection is not value and value is not None: self._shouldShowSelection = value self.render() @property def model(self): return self._model @model.setter def model(self, value): self._model = value self.model.modelChanged.connect(self.render) @property def selection(self): return self._selection @selection.setter def selection(self, value): if self.selection is not value: self._selection = value self.render() @property def dragging(self): return self._dragging @dragging.setter def dragging(self, value): self._dragging = value self.render() def componentTypeToImageName(self, componentType): dictionary = { ComponentType.Battery: "assets/battery.png", ComponentType.Resistor: "assets/resistor.png", ComponentType.Voltmeter: "assets/voltmeter.png", ComponentType.Ammeter: "assets/ammeter.png", ComponentType.Switch: "assets/switch-off.png", ComponentType.Bulb: "assets/bulb-off.png", ComponentType.Button: "assets/button-off.png", } return dictionary[componentType] def componentToImage(self, component): if component.type == ComponentType.Wire: image = QPixmap("assets/icon.png").scaled(self.blockSideLength, self.blockSideLength) if component.numberOfConnections() == 1: image = QPixmap("assets/wire-top.png").scaled(self.blockSideLength, self.blockSideLength) if component.connections[Direction.Right] is not None: image = image.transformed(QtGui.QTransform().rotate(90)) elif component.connections[Direction.Bottom] is not None: image = image.transformed(QtGui.QTransform().rotate(180)) elif component.connections[Direction.Left] is not None: image = image.transformed(QtGui.QTransform().rotate(270)) elif component.numberOfConnections() == 2: if component.connections[Direction.Left] is not None and component.connections[Direction.Right] is not None: image = QPixmap("assets/wire-left-right.png").scaled(self.blockSideLength, self.blockSideLength) elif component.connections[Direction.Top] is not None and component.connections[Direction.Bottom] is not None: image = QPixmap("assets/wire-left-right.png").scaled(self.blockSideLength, self.blockSideLength).transformed(QtGui.QTransform().rotate(90)) elif component.connections[Direction.Top] is not None and component.connections[Direction.Right] is not None: image = QPixmap("assets/wire-top-right.png").scaled(self.blockSideLength, self.blockSideLength) elif component.connections[Direction.Top] is not None and component.connections[Direction.Left] is not None: image = QPixmap("assets/wire-top-right.png").scaled(self.blockSideLength, self.blockSideLength).transformed(QtGui.QTransform().rotate(270)) elif component.connections[Direction.Bottom] is not None and component.connections[Direction.Right] is not None: image = QPixmap("assets/wire-top-right.png").scaled(self.blockSideLength, self.blockSideLength).transformed(QtGui.QTransform().rotate(90)) elif component.connections[Direction.Bottom] is not None and component.connections[Direction.Left] is not None: image = QPixmap("assets/wire-top-right.png").scaled(self.blockSideLength, self.blockSideLength).transformed(QtGui.QTransform().rotate(180)) elif component.numberOfConnections() == 3: image = QPixmap("assets/wire-left-top-right.png").scaled(self.blockSideLength, self.blockSideLength) if component.connections[Direction.Left] is None: image = image.transformed(QtGui.QTransform().rotate(90)) elif component.connections[Direction.Top] is None: image = image.transformed(QtGui.QTransform().rotate(180)) elif component.connections[Direction.Right] is None: image = image.transformed(QtGui.QTransform().rotate(270)) return image else: imageName = "assets/wire-right.png" if component.type == ComponentType.Bulb: if component.isOn(): imageName = "assets/bulb-on.png" else: imageName = "assets/bulb-off.png" elif component.type == ComponentType.Switch: if component.closed: imageName = "assets/switch-on.png" else: imageName = "assets/switch-off.png" elif component.type == ComponentType.Button: if component.closed: imageName = "assets/button-on.png" else: imageName = "assets/button-off.png" else: imageName = self.componentTypeToImageName(component.type) return QPixmap(imageName).scaled(self.blockSideLength, self.blockSideLength) def mouseCoordinatesToBlockIndex(self, x, y): if self.model is None or x < self.startingX or y < self.startingY or x > self.startingX + self.model.gridSize * self.blockSideLength or y > self.startingY + self.model.gridSize * self.blockSideLength: return (-1, -1) else: return (int((x - self.startingX) / self.blockSideLength), int((y - self.startingY) / self.blockSideLength)) def blockIndexToCoordinate(self, x, y): return (self.startingX + self.blockSideLength * x, self.startingY + self.blockSideLength * y) def mousePressEvent(self, event): index = self.mouseCoordinatesToBlockIndex(event.x(), event.y()) self.mousePress.emit(index, (event.x(), event.y())) def dragEnterEvent(self, event): event.acceptProposedAction() def dragMoveEvent(self, event): index = self.mouseCoordinatesToBlockIndex(event.pos().x(), event.pos().y()) self.mouseMove.emit(index, (event.pos().x(), event.pos().y())) def dropEvent(self, event): event.acceptProposedAction() index = self.mouseCoordinatesToBlockIndex(event.pos().x(), event.pos().y()) self.mouseRelease.emit(index, (event.pos().x(), event.pos().y())) def mouseMoveEvent(self, event): self.mousePosition = (event.x(), event.y()) if self.dragging: self.render() index = self.mouseCoordinatesToBlockIndex(event.x(), event.y()) self.mouseMove.emit(index, (event.pos().x(), event.pos().y())) def mouseReleaseEvent(self, event): index = self.mouseCoordinatesToBlockIndex(event.x(), event.y()) self.mouseRelease.emit(index, (event.pos().x(), event.pos().y())) def resizeEvent(self, event): self.render() def render(self): if self.model is not None: self.scene.clear() self.renderCircuitDiagramGrid() self.renderComponents() def renderComponents(self): if self.model is not None: for component in self.model.components: pixmap = self.componentToImage(component) pixmapItem = self.scene.addPixmap(pixmap) offset = self.blockIndexToCoordinate(component.position[0],component.position[1]) pixmapItem.setOffset(offset[0],offset[1]) pixmapItem.setTransformationMode(Qt.SmoothTransformation) if component is self.selection: if self.dragging: renderPosition = (self.startingX + self.selection.position[0] * self.blockSideLength + self.mousePosition[0] - self.draggingStart[0], self.startingY + self.selection.position[1] * self.blockSideLength + self.mousePosition[1] - self.draggingStart[1]) pixmapItem.setOffset(renderPosition[0], renderPosition[1]) elif self.shouldShowSelection: pen = QPen(QBrush(QColor(0,0,255,100)), 2, Qt.DashLine) self.scene.addRect(self.startingX + component.position[0] * self.blockSideLength, self.startingY + component.position[1] * self.blockSideLength, self.blockSideLength, self.blockSideLength, pen) if component.type is ComponentType.Ammeter: font = QFont("Arial", self.blockSideLength/3.5) reading = self.scene.addText(str("%.2f" % component.current) + "A", font) offset = self.blockIndexToCoordinate(component.position[0],component.position[1]) reading.setPos(offset[0]+self.blockSideLength/20,offset[1]+self.blockSideLength/4) elif component.type is ComponentType.Voltmeter: font = QFont("Arial", self.blockSideLength/3.5) reading = self.scene.addText(str("%.2f" % component.voltage) + "V", font) offset = self.blockIndexToCoordinate(component.position[0],component.position[1]) reading.setPos(offset[0]+self.blockSideLength/20,offset[1]+self.blockSideLength/4) def renderCircuitDiagramGrid(self): pen = QPen(QBrush(QColor(200,200,200,255)), 1) pen2 = QPen(QBrush(QColor(100,100,100,255)), 3) width = self.width() height = self.height() self.blockSideLength = width / (self.model.gridSize + 2) if width < height else height / (self.model.gridSize + 2) # draw vertical lines currentX = width / 2 self.startingX = currentX - (self.model.gridSize / 2) * self.blockSideLength while currentX - self.blockSideLength >= 0: currentX -= self.blockSideLength while currentX < width: self.scene.addLine(currentX, 1, currentX, height - 1, pen) currentX += self.blockSideLength # draw horizontal lines currentY = height / 2 self.startingY = currentY - (self.model.gridSize / 2) * self.blockSideLength while currentY - self.blockSideLength >= 0: currentY -= self.blockSideLength while currentY < height: self.scene.addLine(1, currentY, width - 1, currentY, pen) currentY += self.blockSideLength self.scene.addLine(self.startingX, self.startingY, self.startingX + self.model.gridSize * self.blockSideLength, self.startingY, pen2) self.scene.addLine(self.startingX, self.startingY + self.model.gridSize * self.blockSideLength, self.startingX + self.model.gridSize * self.blockSideLength, self.startingY + 10 * self.blockSideLength, pen2) self.scene.addLine(self.startingX, self.startingY, self.startingX, self.startingY + self.model.gridSize * self.blockSideLength, pen2) self.scene.addLine(self.startingX + self.model.gridSize * self.blockSideLength, self.startingY, self.startingX + self.model.gridSize * self.blockSideLength, self.startingY + 10 * self.blockSideLength, pen2)
class CanvasModel(object): def __init__(self): self.scene = QGraphicsScene() # Canvas area self.scale_factor = 1 # Scaling factor self.original_image = None # Original image, used for scaling self.image = None # Image viewable in our canvas self.c_width = 0 # Container width self.c_height = 0 # Container height def set_image(self, image): self.original_image = image def setGeometry(self, container_width, container_height): self.c_width = container_width self.c_height = container_height self.scene.setSceneRect(0, 0, self.c_width, self.c_height) def update_image(self, selection): # Check for container width to prevent behaviour when container is not initialized yet (ex. passing an image as argument) if self.original_image is not None and self.c_width != 0: # Selection defines the viewport behaviour # 0: Ratio scaling (uses canvas/image-size) # 1: Scale to container width # 2: Scale to container height # 3: Scale to original size if selection == 0: ratio = [self.original_image.width() / self.c_width, self.original_image.height() / self.c_height] if ratio[0] > 1 and ratio[0] > ratio[1]: self.image = self.original_image.scaledToWidth(self.c_width, Qt.SmoothTransformation) elif ratio[1] > 1 and ratio[1] > ratio[0]: self.image = self.original_image.scaledToHeight(self.c_height, Qt.SmoothTransformation) else: # Small image, show in original size self.image = self.original_image elif selection == 1: self.image = self.original_image.scaledToWidth(self.c_width, Qt.SmoothTransformation) elif selection == 2: self.image = self.original_image.scaledToHeight(self.c_height, Qt.SmoothTransformation) elif selection == 3: self.image = self.original_image # Update scene self.scene.clear() self.scene.addItem(CustomQGraphicsPixmapItem(QPixmap.fromImage(self.image), self.c_width, self.c_height)) self.scene.update() def scale_image(self, factor): if self.original_image is not None: self.scale_factor *= factor self.image = self.original_image.scaled(self.image.width() * self.scale_factor, self.image.height() * self.scale_factor, Qt.KeepAspectRatio, Qt.SmoothTransformation) # Reset scale factor self.scale_factor = 1 self.scene.clear() self.scene.addItem(CustomQGraphicsPixmapItem(QPixmap.fromImage(self.image), self.c_width, self.c_height)) self.scene.update() def rotate_image(self, rotation): if self.original_image is not None: print(rotation) # Rotate the original and viewable image to ensure a constant workflow when modifying from canvas matrix = QTransform() matrix.translate(self.image.width() / 2, self.image.height() / 2) matrix.rotate(rotation) matrix.translate(-self.image.width() / 2, -self.image.height() / 2) # Save transformed image self.image = self.image.transformed(matrix) original_matrix = QTransform() original_matrix.translate(self.original_image.width() / 2, self.original_image.height() / 2) original_matrix.rotate(rotation) original_matrix.translate(-self.original_image.width() / 2, -self.original_image.height() / 2) # Save transformed image self.original_image = self.original_image.transformed(original_matrix) self.scene.clear() self.scene.addItem(CustomQGraphicsPixmapItem(QPixmap.fromImage(self.image), self.c_width, self.c_height)) self.scene.update() def flip_image(self, direction): if self.original_image is not None: if direction == 0: self.image = self.image.mirrored(True, False) self.original_image = self.original_image.mirrored(True, False) else: self.image = self.image.mirrored(False, True) self.original_image = self.original_image.mirrored(False, True) self.scene.clear() self.scene.addItem(CustomQGraphicsPixmapItem(QPixmap.fromImage(self.image), self.c_width, self.c_height)) self.scene.update()
class Shufti(ShuftiWindow): def __init__(self): super(Shufti,self).__init__() try: self.key = sys.argv[1] except IndexError: print('\nshufti 2.2\n\nTo use shufti from the terminal, you must specify the full path to an image as a parameter.\n') sys.exit(1) self.dbSanitise() self.formats = ('.png', '.jpg', '.jpeg', '.gif', '.bmp', '.pbm', '.pgm', '.ppm', '.xbm', '.xpm', '.dds', '.icns', '.jp2', '.mng', '.tga', '.tiff', '.wbmp', '.webp') try: open(self.key, 'r') except IOError: print('There was an error opening the file') sys.exit(1) if self.key.lower().endswith(self.formats): # If inshuft = 0, the image is not in shufti's image database self.inshuft = 0 self.rotval = 0 self.rotvals = (0,-90,-180,-270) self.dbfile = expanduser("~/.config/shufti/shufti.db") self.dbdir = os.path.dirname(self.dbfile) if not os.path.isfile(self.dbfile): self.createDB() self.db = QtSql.QSqlDatabase.addDatabase('QSQLITE') self.db.setDatabaseName(self.dbfile) self.db.open() self.query = QtSql.QSqlQuery() self.dbSearch(self.dbkey) # Set common window attributes self.path, self.title = os.path.split(self.key) self.setWindowTitle(str(self.title)) self.img = QPixmap(self.key) self.scene = QGraphicsScene() self.scene.addPixmap(self.img) self.view = ShuftiView(self.scene, self) self.view.setDragMode(QGraphicsView.ScrollHandDrag) self.view.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.view.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) # Create array of images in current image dir self.imgfiles = [] for filename in glob.glob(str(self.path) + '/*'): base, ext = os.path.splitext(filename) if ext.lower() in self.formats: self.imgfiles.append(filename) # Find location of current image in imgfiles array self.dirpos = 0 while self.dirpos < len(self.imgfiles) and self.imgfiles[self.dirpos] != self.key: self.dirpos += 1 # If we have no inshuftery, we use the defaults if self.inshuft == 0: self.newImage() else: self.oldImage() else: print("Unsupported file format") sys.exit(1) def newImage(self): self.zoom = 1 self.rotate = 0 self.resize(self.img.size()) self.view.resize(self.img.width() + 2, self.img.height() + 2) self.show() self.view.verticalScrollBar().setValue(0) self.view.horizontalScrollBar().setValue(0) def oldImage(self): if self.rotate == -90: self.rotval = 1 elif self.rotate == -180: self.rotval = 2 elif self.rotate == -270: self.rotval = 3 self.resize(self.img.size()) self.updateView() self.show() self.setGeometry(self.winposx, self.winposy, self.winsizex, self.winsizey) self.view.verticalScrollBar().setValue(self.vscroll) self.view.horizontalScrollBar().setValue(self.hscroll) def toggleFullscreen(self): if self.isFullScreen(): self.showNormal() else: self.showFullScreen() def keyPressEvent(self, event): if event.key() == QtCore.Qt.Key_F11: self.toggleFullscreen() elif event.key() == QtCore.Qt.Key_Equal or event.key() == QtCore.Qt.Key_E: self.zoomIn() elif event.key() == QtCore.Qt.Key_Minus or event.key() == QtCore.Qt.Key_D: self.zoomOut() elif event.key() == QtCore.Qt.Key_1: self.zoomReset() elif event.key() == QtCore.Qt.Key_S: self.rotateImg(-1) elif event.key() == QtCore.Qt.Key_R: self.rotateImg(1) elif event.key() == QtCore.Qt.Key_F: self.fitView() elif event.key() == QtCore.Qt.Key_Space: self.dirBrowse(1) elif event.key() == QtCore.Qt.Key_Backspace: self.dirBrowse(-1) elif event.key() == QtCore.Qt.Key_V: self.vertMax() elif event.key() == QtCore.Qt.Key_Z: self.horizMax() elif event.key() == QtCore.Qt.Key_Q: self.close() def mouseDoubleClickEvent(self, event): self.toggleFullscreen() def createDB(self): if not os.path.exists(self.dbdir): os.makedirs(self.dbdir) self.db = QtSql.QSqlDatabase.addDatabase('QSQLITE') self.db.setDatabaseName(self.dbfile) self.query = QtSql.QSqlQuery() self.db.open() self.query.exec_("create table shuftery(filename text primary key, " "zoom real, winposx int, winposy int, winsizex int, winsizey int, " "hscroll int, vscroll int, rotate int)") return True def zoomIn(self): self.zoom *= 1.05 self.updateView() def zoomOut(self): self.zoom /= 1.05 self.updateView() def zoomReset(self): self.zoom = 1 self.updateView() def rotateImg(self, clock): self.rotval += clock if self.rotval == 4: self.rotval = 0 elif self.rotval < 0: self.rotval = 3 self.rotate = self.rotvals[self.rotval] self.updateView() def fitView(self): self.view.fitInView(self.scene.sceneRect(), QtCore.Qt.KeepAspectRatio) if self.rotate == 0: self.zoom = self.view.transform().m11() elif self.rotate == -90: self.zoom = (self.view.transform().m12()) * -1 elif self.rotate == -180: self.zoom = (self.view.transform().m11()) * -1 else: self.zoom = self.view.transform().m12() def updateView(self): self.view.setTransform(QTransform().scale(self.zoom, self.zoom).rotate(self.rotate)) def winState(self): self.winsizex = self.geometry().width() self.winsizey = self.geometry().height() self.vscroll = self.view.verticalScrollBar().value() self.hscroll = self.view.horizontalScrollBar().value() self.winposx = self.pos().x() self.winposy = self.pos().y() def dbInsert(self): self.query.exec_("insert into shuftery values('%s" % self.dbkey + "', " + str(self.zoom) + ", " + str(self.winposx) + ", " + str(self.winposy) + ", " + str(self.winsizex) + ", " + str(self.winsizey) + ", " + str(self.hscroll) + ", " + str(self.vscroll) + ", " + str(self.rotate) + ")") def dbUpdate(self): self.query.exec_("update shuftery set zoom=" + str(self.zoom) + ", winposx=" + str(self.winposx) + ", winposy=" + str(self.winposy) + ", winsizex=" + str(self.winsizex) + ", winsizey=" + str(self.winsizey) + ", hscroll=" + str(self.hscroll) + ", vscroll=" + str(self.vscroll) + ", rotate=" + str(self.rotate) + " where filename='%s'" % self.dbkey) def dbSearch(self, field): self.query.exec_("SELECT * FROM shuftery WHERE filename='%s'" % field) # If the image is found in shufti.db, load the previous view settings while self.query.next() and self.inshuft == 0: self.zoom = self.query.value(1) self.winposx = self.query.value(2) self.winposy = self.query.value(3) self.winsizex = self.query.value(4) self.winsizey = self.query.value(5) self.hscroll = self.query.value(6) self.vscroll = self.query.value(7) self.rotate = self.query.value(8) self.inshuft = 1 def dbSanitise(self): self.dbkey = self.key.replace("\"", "\"\"") self.dbkey = self.dbkey.replace("\'", "\'\'") self.dbkey = self.dbkey.replace("\\", "\\\\") def dirBrowse(self, direc): if len(self.imgfiles) > 1: self.dirpos += direc if self.dirpos > (len(self.imgfiles) - 1): self.dirpos = 0 elif self.dirpos < 0: self.dirpos = (len(self.imgfiles) - 1) shufti.winState() if self.inshuft == 0: shufti.dbInsert() else: shufti.dbUpdate() self.key = self.imgfiles[self.dirpos] self.dbSanitise() self.path, self.title = os.path.split(self.key) self.setWindowTitle(str(self.title) + " - shufti") self.inshuft = 0 self.dbSearch(self.dbkey) self.scene.clear() self.view.resetTransform() self.img = QPixmap(self.key) self.scene.addPixmap(self.img) if self.inshuft == 0: self.newImage() else: self.oldImage() def vertMax(self): self.screen_res = app.desktop().availableGeometry(shufti) self.screenh = self.screen_res.height() self.winsizex = self.geometry().width() self.winposx = self.pos().x() self.setGeometry(self.winposx, 0, self.winsizex, self.screenh) def horizMax(self): self.screen_res = app.desktop().availableGeometry(shufti) self.screenw = self.screen_res.width() self.winsizey = self.geometry().height() self.winposy = self.pos().y() self.setGeometry(0, self.winposy, self.screenw, self.winsizey) def about(self): self.pop = AboutShufti() self.pop.resize(450, 200) self.pop.setWindowTitle("About shufti") self.pop.show()
class ExportDialog(QMainWindow, Ui_MainWindow): """ Окно экспорта """ def __init__(self, parent, settings: str): super().__init__() self.setupUi(self) self.parent = parent self.image_format = 4 self.file = '' self.export_dir_template = os.path.sep self.export_file_template = "" self.bg_item = None self.settings = json.loads(settings) self.csv_headers = [] self.links = dict() self.test_row = dict() self.openFileBtn.clicked.connect(self.open_file) self.nextPushButton.clicked.connect(self.next_slide) self.prevPushButton.clicked.connect(self.prev_slide) self.toolButtonChangeDir.clicked.connect(self.open_dir) self.startGen.clicked.connect(self.export) self.stackedWidget.currentChanged.connect(self.slide_change) self.scene = QGraphicsScene() self.graphicsView = QGraphicsView() self.graphicsView.setObjectName("graphicsView") self.graphicsView.setFocus() self.linkSettinghorizontalLayout.insertWidget(0, self.graphicsView, 0) self.graphicsView.setScene(self.scene) self.spinBoxRow.valueChanged.connect(self.reload_row) self.encodingComboBox.currentTextChanged.connect(self.render_table) self.haveHeaderCheckBox.stateChanged.connect(self.render_table) self.delimiterLineEdit.editingFinished.connect(self.render_table) self.lineEditDir.editingFinished.connect(self.edit_path) self.lineEditFileMask.editingFinished.connect(self.edit_file) self.strDelimiterLineEdit.editingFinished.connect(self.render_table) self.textBrowserDirs.anchorClicked.connect(self.dir_link_click) self.textBrowserFileName.anchorClicked.connect(self.file_link_click) def reload_row(self, i): self.test_row = self.get_csv_row(i) self.render_items() def get_csv_row(self, row=1): data = dict() for i, name in enumerate(self.csv_headers): itm = self.csvTable.item(row, i) if itm: data[name] = itm.text() else: data[name] = '' return data def get_links_dict(self): data = dict() for row in range(self.tableLinkSettings.rowCount()): itm_name = self.tableLinkSettings.item(row, 0) itm_data = self.tableLinkSettings.cellWidget(row, 1) if itm_name and itm_data: name = itm_name.text() data[name] = self.tableLinkSettings.cellWidget( row, 1).currentText() return data def render_preview(self): if self.settings['bg']: if self.bg_item: for item in self.scene.items(): if item != self.bg_item: self.scene.removeItem(item) else: self.scene.clear() img = QPixmap(self.settings['bg']) self.image_format = img.toImage().format() self.bg_item = QGraphicsPixmapItem(img) self.scene.addItem(self.bg_item) self.scene.update() def render_items(self, event=None): self.links = self.get_links_dict() self.render_preview() for item in self.settings['items']: text = QGraphicsTextItem() font_color = QColor('black') text.setPos(QPointF(item['x'], item['y'])) font = QFont() font_name = item['params'].get(const.ITEM_DATA_KEY_FONT) if font_name: font.fromString(font_name) font_size = item['params'].get(const.ITEM_DATA_KEY_FONT_SIZE) if font_size: font.setPointSize(font_size) else: font.setPointSize(12) font_color_list = item['params'].get( const.ITEM_DATA_KEY_FONT_COLOR) if font_color_list: font_color.setRgb(*font_color_list) text.setFont(font) text_align = item['params'].get(const.ITEM_DATA_KEY_FONT_ALIGN) text.setFont(font) text.setTextWidth(item['w']) text.setDefaultTextColor(font_color) text.setHtml( f"<div align='{text_align}'>{self.test_row[self.links[item['name']]]}</div>" ) self.scene.addItem(text) def edit_path(self, *args): self.export_dir_template = self.lineEditDir.text() self.build_path(self.test_row) def edit_file(self, *args): self.export_file_template = self.lineEditFileMask.text() self.build_path(self.test_row) def build_path(self, row: dict, preview=True): path = self.export_dir_template selected_path = self.lineEditSaveDir.text() if selected_path: path = selected_path + path for k, v in row.items(): path = path.replace(f'#{k}#', v) path = os.path.abspath(os.path.normpath(path)) if self.export_file_template: path = path + os.path.sep + self.export_file_template + '.png' for k, v in row.items(): path = path.replace(f'#{k}#', v) if preview: self.dirPreview.setText(path) else: return path def dir_link_click(self, url): sep = '' if self.export_dir_template: if self.export_dir_template[-1] != os.path.sep: sep = os.path.sep else: sep = os.path.sep self.export_dir_template = self.export_dir_template + sep + url.toString( ) + '#' self.lineEditDir.setText(self.export_dir_template) self.build_path(self.test_row) def file_link_click(self, url): self.export_file_template = self.export_file_template + url.toString( ) + '#' self.lineEditFileMask.setText(self.export_file_template) self.build_path(self.test_row) def update_buttons(self): html = ['<ul>'] for h in self.csv_headers: li = f"<li><a href='#{h}'>#{h}#</a></li>" html.append(li) html.append('</ul>') self.textBrowserDirs.setHtml(const.DIRS_HTML + "\n".join(html)) self.textBrowserFileName.setHtml(const.FILE_MASK_HTML + "\n".join(html)) def update_settings_table(self): self.tableLinkSettings.setRowCount(0) fields = [itm['name'] for itm in self.settings['items']] fields.sort() self.update_buttons() for i, field in enumerate(fields): field_item = QtWidgets.QTableWidgetItem(field) field_item.setFlags(field_item.flags() ^ Qt.ItemIsEditable) self.tableLinkSettings.setRowCount( self.tableLinkSettings.rowCount() + 1) self.tableLinkSettings.setItem(i, 0, field_item) combo_box = QtWidgets.QComboBox(self) combo_box.addItems(self.csv_headers) combo_box.currentTextChanged.connect(self.render_items) self.tableLinkSettings.setCellWidget(i, 1, combo_box) self.test_row = self.get_csv_row() self.render_items() def slide_change(self, index): cnt = self.stackedWidget.count() - 1 if index == 0: self.prevPushButton.setEnabled(False) else: self.prevPushButton.setEnabled(True) if index == cnt: self.nextPushButton.setEnabled(False) else: self.nextPushButton.setEnabled(True) def next_slide(self): cnt = self.stackedWidget.count() - 1 current = self.stackedWidget.currentIndex() if current + 1 <= cnt: self.stackedWidget.setCurrentIndex(current + 1) def prev_slide(self): current = self.stackedWidget.currentIndex() if current - 1 >= 0: self.stackedWidget.setCurrentIndex(current - 1) def open_file(self): self.file = QFileDialog.getOpenFileName(self, 'Открыть файл', filter="CSV (*.csv)")[0] self.lineEditSaveDir.setText( os.path.dirname(os.path.abspath(self.file))) self.selectedFile.setText("Файл: " + self.file) self.render_table() self.nextPushButton.setEnabled(True) def open_dir(self): dir = QFileDialog.getExistingDirectory(self, 'Выбор директории') if dir: self.lineEditSaveDir.setText(dir) self.build_path(self.test_row) def render_table(self): if not self.file: return self.csvTable.clear() self.csv.setCursor(QCursor(Qt.WaitCursor)) have_head = self.haveHeaderCheckBox.checkState() != 0 with open(self.file, encoding=self.encodingComboBox.currentText()) as csv_file: reader = csv.reader(csv_file, delimiter=self.delimiterLineEdit.text(), quotechar=self.strDelimiterLineEdit.text()) if have_head: title = next(reader) self.csv_headers = title self.csvTable.setColumnCount(len(title)) self.csvTable.setHorizontalHeaderLabels(title) else: title_len = len(next(reader)) self.csvTable.setColumnCount(title_len) self.csv_headers = list( map(lambda x: str(x + 1), range(title_len))) csv_file.seek(0) self.csvTable.setRowCount(0) for i, row in enumerate(reader): self.csvTable.setRowCount(self.csvTable.rowCount() + 1) for j, elem in enumerate(row): self.csvTable.setItem(i, j, QTableWidgetItem(elem)) self.spinBoxRow.setMaximum(i) self.progressBar.setMaximum(i) self.csvTable.resizeColumnsToContents() self.csv.setCursor(QCursor(Qt.ArrowCursor)) self.update_settings_table() def export(self): for i in range(self.csvTable.rowCount()): self.progressBar.setValue(i) self.reload_row(i) file_name = self.build_path(self.test_row, preview=False) path = os.path.dirname(file_name) if not os.path.exists(path): os.makedirs(path) img = QImage(self.scene.sceneRect().size().toSize(), self.image_format) img.fill(Qt.transparent) painter = QPainter(img) painter.setRenderHint(QPainter.Antialiasing) self.scene.render(painter) if not img.save(file_name, quality=100): print('fail', file_name) else: del painter # нужно дропать обязательно, иначе в памяти остается связь и оно ложится del img # что бы это понять я потратил 3 часа
class qfi_TC(QGraphicsView): viewUpdate = pyqtSignal() def __init__(self, winParent): QGraphicsView.__init__(self) self.winParent = winParent self.viewUpdate.connect(self.updateView) self.m_itemBack = None self.m_itemBall = None self.m_itemFace_1 = None self.m_itemFace_2 = None self.m_itemMark = None self.m_itemCase = None self.m_turnRate = 0 self.m_slipSkid = 0 self.m_scaleX = 0 self.m_scaleY = 0 self.m_originalHeight = 240 self.m_originalWidth = 240 self.m_originalMarkCtr = QPointF(120, 120) self.m_originalBallCtr = QPointF(120, -36) self.m_backZ = -70 self.m_ballZ = -60 self.m_face1Z = -50 self.m_face2Z = -40 self.m_markZ = -30 self.m_caseZ = 10 self.setStyleSheet("background: transparent; border: none") self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setInteractive(False) self.setEnabled(False) self.reset() self.m_scene = QGraphicsScene(self) self.setScene(self.m_scene) self.m_scene.clear() self.init() def init(self): self.m_scaleX = self.width() / self.m_originalWidth self.m_scaleY = self.height() / self.m_originalHeight self.reset() self.m_itemBack = QGraphicsSvgItem(":/qfi/images/tc/tc_back.svg") self.m_itemBack.setCacheMode(QGraphicsItem.NoCache) self.m_itemBack.setZValue(self.m_backZ) self.m_itemBack.setTransform( QTransform.fromScale(self.m_scaleX, self.m_scaleY), True) self.m_scene.addItem(self.m_itemBack) self.m_itemBall = QGraphicsSvgItem(":/qfi/images/tc/tc_ball.svg") self.m_itemBall.setCacheMode(QGraphicsItem.NoCache) self.m_itemBall.setZValue(self.m_ballZ) self.m_itemBall.setTransform( QTransform.fromScale(self.m_scaleX, self.m_scaleY), True) self.m_itemBall.setTransformOriginPoint(self.m_originalBallCtr) self.m_scene.addItem(self.m_itemBall) self.m_itemFace_1 = QGraphicsSvgItem(":/qfi/images/tc/tc_face_1.svg") self.m_itemFace_1.setCacheMode(QGraphicsItem.NoCache) self.m_itemFace_1.setZValue(self.m_face1Z) self.m_itemFace_1.setTransform( QTransform.fromScale(self.m_scaleX, self.m_scaleY), True) self.m_scene.addItem(self.m_itemFace_1) self.m_itemFace_2 = QGraphicsSvgItem(":/qfi/images/tc/tc_face_2.svg") self.m_itemFace_2.setCacheMode(QGraphicsItem.NoCache) self.m_itemFace_2.setZValue(self.m_face2Z) self.m_itemFace_2.setTransform( QTransform.fromScale(self.m_scaleX, self.m_scaleY), True) self.m_scene.addItem(self.m_itemFace_2) self.m_itemMark = QGraphicsSvgItem(":/qfi/images/tc/tc_mark.svg") self.m_itemMark.setCacheMode(QGraphicsItem.NoCache) self.m_itemMark.setZValue(self.m_markZ) self.m_itemMark.setTransform( QTransform.fromScale(self.m_scaleX, self.m_scaleY), True) self.m_itemMark.setTransformOriginPoint(self.m_originalMarkCtr) self.m_scene.addItem(self.m_itemMark) self.m_itemCase = QGraphicsSvgItem(":/qfi/images/tc/tc_case.svg") self.m_itemCase.setCacheMode(QGraphicsItem.NoCache) self.m_itemCase.setZValue(self.m_caseZ) self.m_itemCase.setTransform( QTransform.fromScale(self.m_scaleX, self.m_scaleY), True) self.m_scene.addItem(self.m_itemCase) self.centerOn(self.width() / 2, self.height() / 2) self.updateView() def reinit(self): if (self.m_scene): self.m_scene.clear() self.init() def update(self): self.updateView() def setTurnRate(self, turnRate): self.m_turnRate = turnRate if (self.m_turnRate < -6): self.m_turnRate = -6 if (self.m_turnRate > 6): self.m_turnRate = 6 def setSlipSkid(self, slipSkid): self.m_slipSkid = slipSkid if (self.m_slipSkid < -15): self.m_slipSkid = -15 if (self.m_slipSkid > 15): self.m_slipSkid = 15 def resizeEvent(self, event): QGraphicsView.resizeEvent(self, event) self.reinit() def reset(self): self.m_itemCase = None self.m_turnRate = 0 self.m_slipSkid = 0 def updateView(self): self.m_scaleX = self.width() / self.m_originalWidth self.m_scaleY = self.height() / self.m_originalHeight self.m_itemBall.setRotation(-self.m_slipSkid) angle = (self.m_turnRate / 3) * 20 self.m_itemMark.setRotation(angle) self.m_scene.update()
class StaticPhotos(QGraphicsView): def __init__(self, photoBaseDir, validPhotoFileExts, photoDeltas, picChangeMs, parent=None): QGraphicsView.__init__(self, parent) self.setAlignment(Qt.AlignLeft | Qt.AlignTop) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) # Vars self.picChangeMs = picChangeMs self.photoBaseDir = photoBaseDir # Widget self.scene = QGraphicsScene() self.setScene(self.scene) self.setBackgroundBrush(QColor("black")) self.setLineWidth(0) self.setFrameShape(QtWidgets.QFrame.NoFrame) # Class vars self.picChgTimer = None self.photoFileManager = PhotoFileManager(validPhotoFileExts, self.photoBaseDir, 7200.00, photoDeltas) self.photoFileManager.startPhotoListUpdate() self.userMovedBack = False # def sizeHint(self): # return QSize(600, 400) def resizeEvent(self, evt=None): xWindowSize = self.width() yWindowSize = self.height() pass def start(self): self.picChgTimer = QTimer() self.picChgTimer.setInterval(self.picChangeMs) self.picChgTimer.setSingleShot(True) self.picChgTimer.timeout.connect(self.picChangeFn) self.picChgTimer.start() # self.picChangeFn() print("Static Photos - starting") def stop(self): if self.picChgTimer is not None: self.picChgTimer.stop() print("Static Photos - stopping") # self.picChgTimer.disconnect(self.picChangeFn) self.photoFileManager.stop() def moveNext(self): self.nextPicItem() def movePrev(self): self.prevPicItem() self.userMovedBack = True def reshow(self): self.showImage() def getCurPhotoFilename(self): return self.photoFileManager.getCurPhotoFilename() def picChangeFn(self): # pass if self.userMovedBack: # Skip this update self.userMovedBack = False else: self.nextPicItem() self.picChgTimer.setInterval(self.picChangeMs) self.picChgTimer.start() def loadImage(self): self.newImg = QImage() self.newImg.load(self.photoFileManager.getCurPhotoFilename()) self.newImgInfo = self.photoFileManager.getCurPhotoInfo() transform = QTransform() transform.rotate(self.newImgInfo.rotationAngle) self.interImg = self.newImg.transformed(transform, Qt.SmoothTransformation) # xReqdSize = self.cellSize.width() * xFactor + self.xBetweenPics * (xFactor-1) # yReqdSize = self.cellSize.height() * yFactor + self.yBetweenPics * (yFactor-1) self.inter2Img = self.interImg.scaled(QSize(self.width(),self.height()), Qt.KeepAspectRatio, Qt.SmoothTransformation) # finalImg = interImg.copy(0,0,xReqdSize,yReqdSize) # print("XY Size", xFactor, yFactor, xReqdSize,yReqdSize) return self.inter2Img, self.newImgInfo def showImage(self): (newImg, newImgInfo) = self.loadImage() # return PicItem(Pixmap(QPixmap(newImg)), -1, -1, xFactor, yFactor, newImgInfo) self.scene.clear() imgSz = newImgInfo.imgSize self.setSceneRect(QRectF(0,0,imgSz.width(), imgSz.height())) pixMap = QPixmap.fromImage(newImg) # # pixMap.setWidth(self.width()) pixMapItem = self.scene.addPixmap(pixMap) # pixMapItem.setPos(50,50) # self.fitInView(QRectF(0, 0, self.width(), self.height()), Qt.KeepAspectRatio) # Add caption caption = QGraphicsTextItem() caption.setDefaultTextColor(QColor(255,255,255)) caption.setPos(0, self.height()*0.94) caption.setFont(QFont("Segoe UI", 30)) caption.setTextWidth(self.width()) # caption.setPos(100, 100) # caption.setTextWidth(1500) # if newImgInfo.createDate is not None: # caption.setPlainText(newImgInfo.createDate.format()); # else: # caption.setPlainText("Image is called bananas"); # print("Tags", newImgInfo.tags) # tagStr = "" # for tag in newImgInfo.tags: # if tag != "Duplicate": # tagStr += (", " if len(tagStr) != 0 else "") + tag # if tagStr == "": # tagStr = "NO TAGS" # captionStr = '<h1 style="text-align:center;width:100%">' + tagStr + '</h1>' # if newImgInfo.createDate is not None: # print(newImgInfo.createDate.format()) # captionStr += '<BR><h2>' + newImgInfo.createDate.format() + '</h2>' captionStr = "" try: if newImgInfo.rating is not None: for i in range(newImgInfo.rating): captionStr += "★" for i in range(5-newImgInfo.rating): captionStr += "☆" if newImgInfo.mainDate is not None: if len(captionStr) != 0: captionStr += " " captionStr += newImgInfo.mainDate.strftime("%d %b %Y") except Exception as excp: print("StaticPhotos: Cannot set caption") captionStr = '<div style="background-color:#000000;text-align: right;padding-right:10dp;">' + captionStr + "</div>" print(captionStr) caption.setHtml(captionStr) self.scene.addItem(caption) self.scene.update() def prevPicItem(self): if self.photoFileManager.getNumPhotos() == 0: return None self.photoFileManager.movePrev() # print ("Loaded photo", self.sourcePhotoList[self.curPhotoIdx], " w", finalImg.width(), " h", finalImg.height(), " facs", xFactor, yFactor) self.showImage() def nextPicItem(self): if self.photoFileManager.getNumPhotos() == 0: return None # print ("Loaded photo", self.sourcePhotoList[self.curPhotoIdx], " w", finalImg.width(), " h", finalImg.height(), " facs", xFactor, yFactor) self.photoFileManager.moveNext() self.showImage() def keyPressEvent(self, event): #QKeyEvent event.ignore()
class ImageView(QGraphicsView): rightMouseButtonPressed = pyqtSignal(float, float) def __init__(self, parent=None): super(ImageView, self).__init__(parent) self.scene = QGraphicsScene() self.setScene(self.scene) self._pixmapHandle = None self.aspectRatioMode = Qt.KeepAspectRatio # self.setDragMode(QGraphicsView.ScrollHandDrag) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.rightMouseButtonPressed.connect(self.handleRightClick) self.zoom = -1 def hasImage(self): return self._pixmapHandle is not None def clearImage(self): """ Removes the current image pixmap from the scene if it exists. """ if self.hasImage(): self.scene.removeItem(self._pixmapHandle) self._pixmapHandle = None self.zoom = -1 self.scene.clear() def pixmap(self): """ Returns the scene's current image pixmap as a QPixmap, or else None if no image exists. :rtype: QPixmap | None """ if self.hasImage(): return self._pixmapHandle.pixmap() return None def image(self): """ Returns the scene's current image pixmap as a QImage, or else None if no image exists. :rtype: QImage | None """ if self.hasImage(): return self._pixmapHandle.pixmap().toImage() return None def setImage(self, image): """ Set the scene's current image pixmap to the input QImage or QPixmap. Raises a RuntimeError if the input image has type other than QImage or QPixmap. :type image: QImage | QPixmap """ if type(image) is QPixmap: pixmap = image elif type(image) is QImage: pixmap = QPixmap.fromImage(image) else: raise RuntimeError( "ImageViewer.setImage: Argument must be a QImage or QPixmap.") if self.hasImage(): self._pixmapHandle.setPixmap(pixmap) else: self._pixmapHandle = self.scene.addPixmap(pixmap) self.setSceneRect(QRectF( pixmap.rect())) # Set scene size to image size. self.updateViewer() def updateViewer(self): """ Show current zoom (if showing entire image, apply current aspect ratio mode). """ if not self.hasImage(): return if self.zoom < 0: self.fitInView(self.sceneRect(), self.aspectRatioMode) self.zoom = self.size().width() / self.scene.width() else: self.setTransform(QTransform().scale(self.zoom, self.zoom)) def wheelEvent(self, event): moose = event.angleDelta().y() if moose > 0: self.zoomIn() elif moose < 0: self.zoomOut() def zoomIn(self): self.zoom *= 1.05 self.updateViewer() def zoomOut(self): self.zoom /= 1.05 self.updateViewer() def mousePressEvent(self, event): if event.button() == Qt.RightButton: scenePos = self.mapToScene(event.pos()) self.rightMouseButtonPressed.emit(scenePos.x(), scenePos.y()) elif event.button() == Qt.LeftButton: self.setDragMode(QGraphicsView.ScrollHandDrag) QGraphicsView.mousePressEvent(self, event) def mouseReleaseEvent(self, event): QGraphicsView.mouseReleaseEvent(self, event) if event.button() == Qt.LeftButton: self.setDragMode(QGraphicsView.NoDrag) def handleRightClick(self, x, y): # row = int(y) # col = int(x) # print("Clicked on image pixel (row="+str(row)+", column="+str(col)+")") pass
class CharIdentifierInput(QDialog, Ui_CharIdentifierInput): """ Get a character A dialog for creating / getting a character The followings are the operations in the dialog -# Painting a character -# Set : analyze the character drawn which is composed from the following stages -# Transform the character to the size of the main item -# Draw a network composed from squares -# Decide which squares are occupied by the character -# Save : Saves the character -# Load : Loads the character from file -# Cancel : exit and retrun False -# OK : exit and return True Graphical structure of the dialog -# Vertical box layout -# Buttons horizontal layout -# GraphicsView which holds a -# Graphics scene which hols a -# CharItem """ def __init__(self, parent, filename: str=None): """CharIdentifierInput constructor Args: parent : The parent window or dialog filename : The character will be loaded from the file """ QDialog.__init__(self, parent) self.setupUi(self) self.setFixedSize(mainItemWidth + 2 * mainItemPadding + 40, mainItemHeight + 2 * mainItemPadding + 60) self.createGui() self.pushButton_set.clicked.connect(self.pushButton_set_clicked) self.pushButton_save.clicked.connect(self.pushButton_save_clicked) self.pushButton_load.clicked.connect(self.pushButton_load_clicked) self.pushButton_cancel.clicked.connect(self.reject) self.pushButton_OK.clicked.connect(self.accept) self.pushButton_reset.clicked.connect(self.pushButton_reset_clicked) self.pushButton_revertSet.clicked.connect(self.pushButton_revertSet_clicked) self.dirty = False self.filename = filename if filename: self.pushButton_load_clicked(filename) def createGui(self): """ Create the scene and the new item """ self.graphicsScene = QGraphicsScene() self.graphicsView.setScene(self.graphicsScene) self.itemBoundaries = QRectF(0, 0, mainItemWidth, mainItemHeight) self.itemPos = QPointF(mainItemPadding + 3, mainItemPadding) self.graphicsScene.setSceneRect(0, 0, mainItemWidth + 2 * mainItemPadding, mainItemHeight + 2 * mainItemPadding) self.newItem() def newItem(self): """ Create new main item """ self.mainItem = CharItem(self.itemBoundaries, self.itemPos) self.graphicsScene.addItem(self.mainItem) def pushButton_set_clicked(self): """ Activate the set operation of the main item """ self.mainItem.set() def pushButton_save_clicked(self): """ Slot : Activate the save operation """ # If there where no changes - return if not self.mainItem.dirty: QMessageBox.critical(None, "Character Identifier - Save", "Nothing to save") return # Get the previous filename and path path = QFileInfo(self.filename).path() if self.filename else os.path.join(dataDir, "Chapter 3 - Distance Metrics") fname = QFileDialog.getSaveFileName(self, "Character Identifier - Save", path, "Character Identifier Files (*.chr)") # If the user pressed the cancel button in the dialog - return if not fname: return if not fname[0].lower().endswith(".chr"): fname[0] += ".chr" self.filename = fname[0] try: # Open the file create the stream and activate the save method of the # main item fh = QFile(self.filename) if not fh.open(QIODevice.WriteOnly): raise IOError(fh.errorString()) stream = QDataStream(fh) self.mainItem.save(stream, self.filename) except IOError as e: QMessageBox.warning(self, "Character Identifier -- Save Error", "Failed to save {}: {}".format( self.filename, e)) finally: if fh is not None: fh.close() def pushButton_load_clicked(self, filename: str=None): """ Slot : Activate the load from file operation """ # If the character was not loaded from a file and no save was done if not self.filename: self.save() path = QFileInfo(self.filename).path() if self.filename else os.path.join( dataDir, "Chapter 3 - Distance Metrics") fname = QFileDialog.getOpenFileName(self, "Character Identifier - Open", path, "Character Identifier Files (*.chr)") if not fname: return self.filename = fname[0] fh = None else: self.filename = filename try: fh = QFile(self.filename) if not fh.open(QIODevice.ReadOnly): raise IOError(fh.errorString()) items = self.graphicsScene.items() while items: item = items.pop() self.graphicsScene.removeItem(item) del item stream = QDataStream(fh) self.mainItem = CharItem(self.itemBoundaries, self.itemPos) self.graphicsScene.addItem(self.mainItem) self.mainItem.load(stream, self.filename) self.dirty = False except IOError as e: QMessageBox.warning(self, "Page Designer -- Open Error", "Failed to open {}: {}".format(self.filename, e)) finally: if fh is not None: fh.close() def accept(self): """ Slot : OK exit """ # If the item was not set - set it if not self.mainItem.wasSetted: self.mainItem.set() # Save the item self.save() return super(CharIdentifierInput, self).accept() def save(self): """ save operation This method is activated before all the operations that cause The item to be removed from the screen """ # If the item was changed - ask for saving if self.mainItem.dirty: if QMessageBox.question(None, "Char Identifier Input", "Do You want to save changes ?", QMessageBox.StandardButtons(QMessageBox.Yes | QMessageBox.No)) == QMessageBox.Yes: self.pushButton_save_clicked() def reject(self): """ Slot : reject operation exit the dialog with true """ self.save() return super(CharIdentifierInput, self).accept() def pushButton_reset_clicked(self): """ Slot : clear the presentation """ self.save() self.graphicsScene.clear() self.graphicsView.viewport().update() self.newItem() def pushButton_revertSet_clicked(self): """ Slot : revert the setting for continue drowning """ self.mainItem.revertTransform()
class Ui_MainWindow(QMainWindow, Ui_MainWindowBase): def __init__(self): super(Ui_MainWindow, self).__init__() self.setupUi(self) self.videoPlaybackInit() self.blocklyInit() self.imgInit() self.menuInit() def videoPlaybackInit(self): self.videoPlaybackWidget.hide() self.videoPlaybackWidget.frameChanged.connect(self.setFrame, type=Qt.QueuedConnection) self.filePath = None def blocklyInit(self): self.blocklyWebView.setUrl(QtCore.QUrl(blocklyURL)) self.blocklyEvaluationTimer = QtCore.QTimer(parent=self.blocklyWebView) self.blocklyEvaluationTimer.setInterval(1*100) self.blocklyEvaluationTimer.timeout.connect(self.evaluateSelectedBlock) self.blocklyEvaluationTimer.start() self.filterClassHash = None self.filter = None self.selectedBlockID = None self.fgbg = None def imgInit(self): self.cv_img = cv2.imread(os.path.join(sampleDataPath,"color_filter_test.png")) self.im_output = None self.inputScene = QGraphicsScene() self.inputGraphicsView.setScene(self.inputScene) self.inputGraphicsView.resizeEvent = self.inputGraphicsViewResized self.outputPixmap = None self.outputScene = QGraphicsScene() self.outputGraphicsView.setScene(self.outputScene) self.outputGraphicsView.resizeEvent = self.outputGraphicsViewResized qimg = misc.cvMatToQImage(self.cv_img) self.inputPixmap = QPixmap.fromImage(qimg) self.inputPixmapItem = QGraphicsPixmapItem(self.inputPixmap) self.inputPixmapItem.mousePressEvent = self.getPixmapItemClickedPos self.inputScene.addItem(self.inputPixmapItem) def menuInit(self): self.actionOpenVideo.triggered.connect(self.openVideoFile) self.actionOpenImage.triggered.connect(self.openImageFile) self.actionSaveVideo.triggered.connect(self.saveVideoFile) self.actionSaveFilterData.triggered.connect(self.saveFilterFile) self.actionOpenFilterData.triggered.connect(self.openFilterFile) self.actionCreateBackground.triggered.connect(self.createBackground) def dragEnterEvent(self,event): event.acceptProposedAction() def dropEvent(self,event): mime = event.mimeData() if mime.hasUrls(): urls = mime.urls() if len(urls) > 0: self.processDropedFile(urls[0].toLocalFile()) event.acceptProposedAction() def closeEvent(self,event): pass def processDropedFile(self,filePath): root,ext = os.path.splitext(filePath) if ext == ".filter": # Read Filter self.openFilterFile(filePath=filePath) return elif self.openImageFile(filePath=filePath): return elif self.openVideoFile(filePath=filePath): return def setFrame(self, frame): if frame is not None: self.cv_img = frame self.updateInputGraphicsView() self.evaluateSelectedBlock() def setRectangleParameterToBlock(self, topLeft, bottomRight): height, width, dim = self.cv_img.shape array = [ [topLeft.x()/width, topLeft.y()/height], [bottomRight.x()/width, bottomRight.y()/height] ] parameters = {'array': '{0}'.format(array)} string = json.dumps({k: str(v) for k, v in parameters.items()}) webFrame = self.blocklyWebView.page().mainFrame() webFrame.evaluateJavaScript("Apps.setValueToSelectedBlock({0});".format(string)) def setArrayParameterToBlock(self, array): height, width, dim = self.cv_img.shape array = [[x[0]/width, x[1]/height] for x in array] parameters = {'array': '{0}'.format(array)} string = json.dumps({k: str(v) for k, v in parameters.items()}) webFrame = self.blocklyWebView.page().mainFrame() webFrame.evaluateJavaScript("Apps.setValueToSelectedBlock({0});".format(string)) def createBackground(self, activated=False): if self.videoPlaybackWidget.isOpened(): self.videoPlaybackWidget.stop() bg_dialog = BackgroundGeneratorDialog(self) bg_dialog.setWindowModality(Qt.WindowModal) bg_dialog.videoPlaybackWidget.copySource(self.videoPlaybackWidget) res = bg_dialog.exec() if res == QDialog.Accepted: if bg_dialog.fgbg is not None: self.fgbg = bg_dialog.fgbg.getBackgroundImage() def openVideoFile(self, activated=False, filePath = None): if filePath is None: filePath, _ = QFileDialog.getOpenFileName(None, 'Open Video File', userDir) if len(filePath) is not 0: self.filePath = filePath self.fgbg = None ret = self.videoPlaybackWidget.openVideo(filePath) if ret == False: return False self.videoPlaybackWidget.show() self.filterClassHash = None return True def openImageFile(self, activated=False, filePath = None): if filePath == None: filePath, _ = QFileDialog.getOpenFileName(None, 'Open Image File', userDir) if len(filePath) is not 0: self.filePath = filePath img = cv2.imread(filePath) if img is None: return False self.cv_img = img self.fgbg = None self.videoPlaybackWidget.hide() self.updateInputGraphicsView() # Initialize Filter when opening new file. self.filterClassHash = None return True else: return False def updateInputGraphicsView(self): self.inputScene.removeItem(self.inputPixmapItem) qimg = misc.cvMatToQImage(self.cv_img) self.inputPixmap = QPixmap.fromImage(qimg) rect = QtCore.QRectF(self.inputPixmap.rect()) self.inputScene.setSceneRect(rect) self.inputPixmapItem = QGraphicsPixmapItem(self.inputPixmap) self.inputScene.addItem(self.inputPixmapItem) self.inputGraphicsView.viewport().update() self.inputGraphicsViewResized() def getPixmapItemClickedPos(self, event): pos = event.scenePos().toPoint() print(pos) def inputPixmapItemClicked(self, event): pos = event.scenePos().toPoint() img = self.inputPixmap.toImage() pix = img.pixel(pos) rgb = QColor(pix).name() logger.debug("Selected pixel color: {0}".format(rgb)) parameters = { 'Color': rgb, } string = json.dumps(parameters) webFrame = self.blocklyWebView.page().mainFrame() webFrame.evaluateJavaScript("Apps.setValueToSelectedBlock({0});".format(string)) def openFilterFile(self, activated=False, filePath = None): if filePath is None: filePath, _ = QFileDialog.getOpenFileName(None, 'Open Block File', userDir, "Block files (*.filter)") if len(filePath) is not 0: logger.debug("Open Filter file: {0}".format(filePath)) filterIO = FilterIO(filePath) self.fgbg = filterIO.getBackgroundImg() exec(filterIO.getFilterCode(), globals()) blockXML = re.sub(r"[\n\r]",'', filterIO.getBlockXMLData()) frame = self.blocklyWebView.page().mainFrame() frame.evaluateJavaScript("Apps.setBlockData('{0}');".format(blockXML)) def saveFilterFile(self): self.blocklyEvaluationTimer.stop() if self.filePath is not None: candidateFilePath = os.path.splitext(self.filePath)[0] + '.filter' else: candidateFilePath = userDir filePath, _ = QFileDialog.getSaveFileName(None, 'Save Filter File', candidateFilePath, "Filter files (*.filter)") if len(filePath) is not 0: logger.debug("Saving Filter file: {0}".format(filePath)) frame = self.blocklyWebView.page().mainFrame() filterIO = FilterIO() filterIO.setBlockXMLData(frame.evaluateJavaScript("Apps.getBlockData();")) filterClassText = self.parseToClass(frame.evaluateJavaScript("Apps.getCodeFromWorkspace();")) filterIO.setFilterCode(filterClassText) filterIO.setBackgroundImg(self.fgbg) filterIO.save(filePath) self.blocklyEvaluationTimer.start() def inputGraphicsViewResized(self, event=None): self.inputGraphicsView.fitInView(QtCore.QRectF(self.inputPixmap.rect()), QtCore.Qt.KeepAspectRatio) def outputGraphicsViewResized(self, event=None): if self.outputPixmap is None: self.outputGraphicsView.fitInView(self.outputScene.sceneRect(), QtCore.Qt.KeepAspectRatio) else: self.outputGraphicsView.fitInView(QtCore.QRectF(self.outputPixmap.rect()), QtCore.Qt.KeepAspectRatio) def parseToClass(self, text): additionalText = """#self.fgbg = None #self.resize_flag = {resize_flag} #if self.resize_flag: # im_input = cv2.pyrDown(im_input) if self.resize_flag: {input} = cv2.pyrDown({input}) if self.fgbg is not None: {input} = cv2.absdiff({input}, self.fgbg) """.format(resize_flag=self.actionResize.isChecked(), input="{input}") text = additionalText + text lines = text.split("\n") classMemberPattern = r"^#" classMembers = [] filterOperations = [] for line in lines: if re.match(classMemberPattern, line): classMembers.append(line.lstrip("#")) else: filterOperations.append(line) generator = ClassTextGenerator('filterOperation') generator.functions['__init__']['lines'] = classMembers generator.functions['__init__']['args'] = ['im_input'] filterOperations.append('return {output}') generator.addFunction('filterFunc', filterOperations, args=['im_input'], returnVal=True) return generator.generate().format(input="im_input", output="im_output") def reflectSelectedBlockStateIntoUI(self): webFrame = self.blocklyWebView.page().mainFrame() data = webFrame.evaluateJavaScript("Apps.getBlockTypeFromSelectedBlock();") if data is None: self.resetSceneAction(self.selectedBlockID) self.selectedBlockID = None return blockType = data['type'] blockID = data['id'] blockAttributes = data['attributes'] if self.selectedBlockID != blockID: self.resetSceneAction(self.selectedBlockID) self.selectedBlockID = blockID if 'regionSelector' in blockAttributes: parameters = webFrame.evaluateJavaScript("Apps.getValueFromSelectedBlock();") graphicsItem = self.getGrphicsItemFromInputScene(blockID) if graphicsItem is not None: if graphicsItem.isVisible() is False: graphicsItem.show() else: height, width, dim = self.cv_img.shape array = [[x[0]*width, x[1]*height] for x in eval(parameters['array'])] if blockType == "rectRegionSelector": graphicsItem = ResizableRect() elif blockType == "ellipseRegionSelector": graphicsItem = ResizableEllipse() elif blockType == "polyRegionSelector": graphicsItem = MovablePolygon() self.inputScene.addItem(graphicsItem) graphicsItem.setPoints(array) graphicsItem.setObjectName(blockID) graphicsItem.geometryChange.connect(self.setArrayParameterToBlock) self.updateInputGraphicsView() elif 'colorSelector' in blockAttributes: self.inputPixmapItem.mousePressEvent = self.inputPixmapItemClicked else: self.inputPixmapItem.mousePressEvent = self.getPixmapItemClickedPos def resetSceneAction(self, blockID): graphicsItem = self.getGrphicsItemFromInputScene(blockID) if graphicsItem is not None: graphicsItem.hide() self.inputPixmapItem.mousePressEvent = QGraphicsPixmapItem(self.inputPixmapItem).mousePressEvent def getGrphicsItemFromInputScene(self, blockID): try: int(blockID) except: return None for item in self.inputScene.items(): # QGraphicsObjectをSceneから取り出そうとすると, # 親クラスであるQGraphicsItem(QPixmapGraphicsItem)にダウンキャスト # されて返ってくるためtryが必要. try: if blockID == item.objectName(): return item except: pass return None def evaluateSelectedBlock(self, update=True): self.im_output = None frame = self.blocklyWebView.page().mainFrame() text = frame.evaluateJavaScript("Apps.getCodeFromSelectedBlock();") self.reflectSelectedBlockStateIntoUI() if text == "" or text is None: text = frame.evaluateJavaScript("Apps.getCodeFromWorkspace();") if text is None: return False xmlText = frame.evaluateJavaScript("Apps.getBlockData();") text = self.parseToClass(text) logger.debug("Generated Code: {0}".format(text)) textHash = hashlib.md5(text.encode()) if self.filterClassHash != textHash: self.filterClassHash = textHash try: exec(text, globals()) self.filter = filterOperation(self.cv_img) self.filter.fgbg = self.fgbg except Exception as e: logger.debug("Block Evaluation Error: {0}".format(e)) return False try: self.im_output = self.filter.filterFunc(self.cv_img) except Exception as e: logger.debug("Filter execution Error: {0}".format(e)) return False if update: self.outputScene.clear() try: qimg = misc.cvMatToQImage(self.im_output) self.outputPixmap = QPixmap.fromImage(qimg) except: pass rect = QtCore.QRectF(self.outputPixmap.rect()) self.outputScene.setSceneRect(rect) self.outputScene.addPixmap(self.outputPixmap) self.outputGraphicsView.viewport().update() self.outputGraphicsViewResized() return True def saveVideoFile(self, activated=False): self.blocklyEvaluationTimer.stop() if self.evaluateSelectedBlock(False): if self.filePath is not None: candidateFilePath = os.path.splitext(self.filePath)[0] + '_processed.avi' else: candidateFilePath = userDir + '_processed.avi' filePath, _ = QFileDialog.getSaveFileName(None, 'Save Video', candidateFilePath, "AVI files (*.avi)") if len(filePath) is not 0: logger.debug("Saving Video: {0}".format(filePath)) self.videoPlaybackWidget.stop() fourcc = cv2.VideoWriter_fourcc(*'X264') out = cv2.VideoWriter(filePath, fourcc, self.videoPlaybackWidget.getFPS(), self.im_output.shape[1::-1]) numFrames = self.videoPlaybackWidget.getMaxFramePos()+1 progress = QProgressDialog("Running...\nOpenH264 Video Codec provided by Cisco Systems, Inc.", "Abort", 0, numFrames, self) progress.setWindowModality(Qt.WindowModal) currentFrameNo = self.videoPlaybackWidget.getFramePos() for i in range(numFrames): progress.setValue(i) if progress.wasCanceled(): break ret, input_frame = self.videoPlaybackWidget.readFrame(i) output_frame = self.filter.filterFunc(input_frame) if len(output_frame.shape)==2: output_frame = cv2.cvtColor(output_frame, cv2.COLOR_GRAY2BGR) out.write(output_frame) out.release() self.videoPlaybackWidget.moveToFrame(currentFrameNo) progress.setValue(numFrames) self.blocklyEvaluationTimer.start()
class InitialPoseDialog(QDialog, Ui_PoseDialog): data_manager = None image = None y_line = 0 y_top_line = 0 y_lower_line = 0 landmark_size = 2 lines = None middle_idx = 0 pose_model = None def __init__(self, data_manager): super(InitialPoseDialog, self).__init__() self.setupUi(self) self.setAttribute(Qt.WA_DeleteOnClose) assert isinstance(data_manager, DataManager) self.data_manager = data_manager self.pose_model = InitialPoseModel(data_manager) self.scene = QGraphicsScene() self.graphicsView.setScene(self.scene) self.image = Filter.crop_image(self.data_manager.radiographs[0].image) self.findButton.clicked.connect(self.find_jaw_divider) self.openButton.clicked.connect(self._open_radiograph) self._redraw() def find_jaw_divider(self): self.y_top_line, self.y_lower_line = self.pose_model._find_jaw_separation_line(self.pose_model._crop_image_sides(self.image)) upper_jaw_image = self.pose_model.crop_upper_jaw(self.image, self.y_top_line) lower_jaw_image = self.pose_model.crop_lower_jaw(self.image, self.y_lower_line) # Filter the image upper_jaw_image = Filter.process_image(upper_jaw_image, median_kernel=5, bilateral_kernel=17, bilateral_color=6) lower_jaw_image = Filter.process_image(lower_jaw_image, median_kernel=5, bilateral_kernel=17, bilateral_color=6) upper_jaw_image = self.pose_model._convert_to_binary_image(upper_jaw_image) lower_jaw_image = self.pose_model._convert_to_binary_image(lower_jaw_image) upper_lines = self.pose_model._find_hough_lines(upper_jaw_image, threshold=15) lower_lines = self.pose_model._find_hough_lines(lower_jaw_image, threshold=15) # Filter out lines upper_lines = self.pose_model._filter_lines(upper_lines, upper_jaw_image.shape, line_offset=6, max_line_gap=90) lower_lines = self.pose_model._filter_lines(lower_lines, lower_jaw_image.shape, line_offset=2, max_line_gap=60) self.image = lower_jaw_image self.lines = lower_lines self._redraw() def _open_radiograph(self): file_dialog = QFileDialog(self) file_dialog.setDirectory("./data/Radiographs") file_dialog.setFileMode(QFileDialog.ExistingFile) file_dialog.setNameFilter("Radiograph (*.tif)") if file_dialog.exec_() and len(file_dialog.selectedFiles()) == 1: radiograph = Radiograph() radiograph.path_to_img = file_dialog.selectedFiles()[0] #self.image = radiograph.image #crop_translation = -Filter.get_cropping_region(radiograph.image).left_top self.image = Filter.crop_image(radiograph.image) self.lines = None self._redraw() def _redraw(self, normalize=False): self.scene.clear() img = self.image.copy() if normalize: img = (img / img.max()) * 255 # Draw image qimg = toQImage(img.astype(np.uint8)) self.scene.addPixmap(QPixmap.fromImage(qimg)) # Add jaws divider self.scene.addLine(QLineF(0, self.y_line, self.image.shape[1], self.y_line), pen=QPen(QColor.fromRgb(255, 0, 0))) self.scene.addLine(QLineF(0, self.y_top_line, self.image.shape[1], self.y_top_line), pen=QPen(QColor.fromRgb(255, 0, 0))) self.scene.addLine(QLineF(0, self.y_lower_line, self.image.shape[1], self.y_lower_line), pen=QPen(QColor.fromRgb(255, 0, 0))) # Add image center self.scene.addEllipse(self.image.shape[0]/2 - self.landmark_size, self.image.shape[1]/2 - self.landmark_size, self.landmark_size * 2, self.landmark_size * 2, pen=QPen(QColor.fromRgb(255, 0, 0)), brush=QBrush(QColor.fromRgb(255, 0, 0))) # Draw Hough lines if self.lines is not None: #for x1,y1,x2,y2 in self.lines[0]: for i, line_param in enumerate(self.lines): rho,theta = line_param a = np.cos(theta) b = np.sin(theta) x0 = a*rho y0 = b*rho x1 = int(x0 + 200*(-b)) y1 = int(y0 + 200*(a)) x2 = int(x0 - 200*(-b)) y2 = int(y0 - 200*(a)) self.scene.addLine(QLineF(x1, y1, x2, y2), pen=QPen(QColor.fromRgb(0, 255, 0)))
class qfi_ADI (QGraphicsView): viewUpdate = pyqtSignal() def __init__(self,winParent): QGraphicsView.__init__(self) self.winParent=winParent self.viewUpdate.connect(self.update) self.m_roll = 0 self.m_pitch = 0 self.m_faceDeltaX_new = 0 self.m_faceDeltaX_old = 0 self.m_faceDeltaY_new = 0 self.m_faceDeltaY_old = 0 self.m_originalHeight = 240 self.m_originalWidth = 240 self.m_originalPixPerDeg = 1.7 self.m_originalAdiCtr = QPointF(120,120) self.m_backZ = -30 self.m_faceZ = -20 self.m_ringZ = -10 self.m_caseZ = 10 self.setStyleSheet("background: transparent; border: none"); self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setInteractive(False) self.setEnabled(False) self.m_scene = QGraphicsScene(self) self.setScene(self.m_scene) self.init() def init (self): self.m_scaleX = self.width() / self.m_originalWidth self.m_scaleY = self.height() / self.m_originalHeight self.m_itemBack = QGraphicsSvgItem(":/qfi/images/adi/adi_back.svg") self.m_itemBack.setCacheMode (QGraphicsItem.NoCache) self.m_itemBack.setZValue( self.m_backZ ) self.m_itemBack.setTransform( QTransform.fromScale( self.m_scaleX, self.m_scaleY ), True ) self.m_itemBack.setTransformOriginPoint( self.m_originalAdiCtr ) self.m_scene.addItem (self.m_itemBack) self.m_itemFace = QGraphicsSvgItem(":/qfi/images/adi/adi_face.svg") self.m_itemFace.setCacheMode (QGraphicsItem.NoCache) self.m_itemFace.setZValue( self.m_faceZ ) self.m_itemFace.setTransform( QTransform.fromScale( self.m_scaleX, self.m_scaleY ), True ) self.m_itemFace.setTransformOriginPoint( self.m_originalAdiCtr ) self.m_scene.addItem (self.m_itemFace) self.m_itemRing = QGraphicsSvgItem(":/qfi/images/adi/adi_ring.svg") self.m_itemRing.setCacheMode (QGraphicsItem.NoCache) self.m_itemRing.setZValue( self.m_ringZ ) self.m_itemRing.setTransform( QTransform.fromScale( self.m_scaleX, self.m_scaleY ), True ) self.m_itemRing.setTransformOriginPoint( self.m_originalAdiCtr ) self.m_scene.addItem (self.m_itemRing) self.m_itemCase = QGraphicsSvgItem(":/qfi/images/alt/alt_case.svg") self.m_itemCase.setCacheMode (QGraphicsItem.NoCache) self.m_itemCase.setZValue( self.m_caseZ ) self.m_itemCase.setTransform( QTransform.fromScale( self.m_scaleX, self.m_scaleY ), True ) self.m_itemCase.setTransformOriginPoint( self.m_originalAdiCtr ) self.m_scene.addItem (self.m_itemCase) self.centerOn (self.width()/2, self.height()/2) self.updateView() def reinit(self): if (self.m_scene): self.m_scene.clear() self.init() def update(self): self.updateView() self.m_faceDeltaX_old = self.m_faceDeltaX_new self.m_faceDeltaY_old = self.m_faceDeltaY_new def setRoll (self, roll): self.m_roll = roll if (self.m_roll < -180): self.m_roll = -180 if (self.m_roll > 180): self.m_roll = 180 def setPitch (self, pitch): self.m_pitch = pitch if (self.m_pitch < -25): self.m_pitch = -25 if (self.m_pitch > 25): self.m_pitch = 25 def resizeEvent (self, event): QGraphicsView.resizeEvent (self,event) self.reinit() def reset (self): self.m_itemBack = None self.m_itemFace = None self.m_itemRing = None self.m_itemCase = None self.m_roll = 0.0 self.m_pitch = 0.0 def updateView(self): self.m_scaleX = self.width() / self.m_originalWidth self.m_scaleY = self.height() / self.m_originalHeight self.m_itemBack.setRotation(- self.m_roll) self.m_itemRing.setRotation(- self.m_roll) self.m_itemFace.setRotation(- self.m_roll) roll_rad = math.pi * self.m_roll / 180.0 delta = self.m_originalPixPerDeg * self.m_pitch self.m_faceDeltaX_new = self.m_scaleX * delta * math.sin( roll_rad ) self.m_faceDeltaY_new = self.m_scaleY * delta * math.cos( roll_rad ) self.m_itemFace.moveBy( self.m_faceDeltaX_new - self.m_faceDeltaX_old, self.m_faceDeltaY_new - self.m_faceDeltaY_old ) self.m_scene.update()
class MainWindow(QMainWindow): def __init__(self, parent: QWidget=None) -> None: super(MainWindow, self).__init__(parent) uic.loadUi(os.path.join(getResourcesPath(), 'ui', 'mainwindow.ui'), self) self.actionExit.triggered.connect(QApplication.quit) self.actionLoad_G_Code.triggered.connect(self.askGCodeFile) self.actionPrint.triggered.connect(self.actionPrintSlot) self.actionClear.triggered.connect(self.actionClearSlot) self.actionZoomIn.triggered.connect(self.zoomIn) self.actionZoomOut.triggered.connect(self.zoomOut) self.actionResetZoom.triggered.connect(self.resetZoom) self.actionSetPenWidth.triggered.connect(self.askPenWidth) self.actionShowMovement.toggled.connect(self.actionShowMovementSlot) self.checkBoxActionShowMovement = QCheckBox( self.actionShowMovement.text(), self.toolBar) self.checkBoxActionShowMovement.setChecked(True) # noinspection PyUnresolvedReferences self.checkBoxActionShowMovement.toggled.connect( self.actionShowMovementSlot) self.toolBar.insertWidget(self.actionSetMoveLineColor, self.checkBoxActionShowMovement) self.actionSetMoveLineColor.triggered.connect( self.actionSetMoveLineColorSlot) self.zoomFactor = 1 self._precision = 1 self._moveLineColor = Qt.green self.material = None self.scene = QGraphicsScene() self.graphicsView.setScene(self.scene) self.graphicsView.scale(1, -1) self.graphicsView.setBackgroundBrush(QBrush(Qt.lightGray)) self.clearScene() self.updateStatusBar() @property def moveLineColor(self) -> QColor: return self._moveLineColor @moveLineColor.setter def moveLineColor(self, new_color: QColor) -> None: self._moveLineColor = new_color for item in self.scene.items(): if isinstance(item, QGraphicsMovementLineItem): item.color = self.moveLineColor @property def precision(self) -> number: return self._precision @precision.setter def precision(self, new_precision: number) -> None: self._precision = new_precision for item in self.scene.items(): if isinstance(item, PenWidthSettable) and\ isinstance(item, QGraphicsItem): item.penWidth = self.precision self.updateStatusBar() def actionPrintSlot(self) -> None: printer = QPrinter() printer.setPageOrientation(QPageLayout.Landscape) if QPrintDialog(printer).exec_(): painter = QPainter(printer) painter.setRenderHint(QPainter.Antialiasing) view = QGraphicsView() view.setScene(self.scene) view.setSceneRect(QRectF(0, 0, 290, 200)) view.fitInView(QRectF(0, 0, 290, 200), Qt.KeepAspectRatio) view.scale(1, -1) view.render(painter) del painter # necessary, thanks Qt def updateStatusBar(self) -> None: # noinspection PyUnresolvedReferences self.statusBar.showMessage('Current pen width: %.3f' % self._precision) def actionShowMovementSlot(self, toggle: bool) -> None: self.checkBoxActionShowMovement.setChecked(toggle) self.actionShowMovement.setChecked(toggle) for item in self.scene.items(): if isinstance(item, QGraphicsMovementLineItem): item.setVisible(toggle) def askPenWidth(self) -> None: # noinspection PyCallByClass, PyTypeChecker res = QInputDialog.getDouble(self, 'Change pen width', 'Enter new pen width:', self.precision, -10000, 10000, 3) if res[1]: self.precision = res[0] def actionClearSlot(self) -> None: if self.askClearScene(): self.clearScene() def actionSetMoveLineColorSlot(self) -> None: # Inspector doesn't understand Qt's static methods # noinspection PyCallByClass,PyTypeChecker color = QColorDialog.getColor(self.moveLineColor, self, 'Select new move line color') if QColor.isValid(color): self.moveLineColor = color def askClearScene(self) -> bool: msgbox = QMessageBox(self) msgbox.setText('This will clear the area.') msgbox.setInformativeText('Are you sure you want to continue?') msgbox.setStandardButtons( QMessageBox.Cancel | QMessageBox.Ok) msgbox.setDefaultButton(QMessageBox.Cancel) ret = msgbox.exec() if ret == QMessageBox.Ok: return True return False def clearScene(self) -> None: self.scene.clear() self.precision = 1 self.updateStatusBar() self.material = self.scene.addRect(QRectF(0, 0, 290, 200)) self.material.setPen(QPen(Qt.white)) self.material.setBrush(QBrush(Qt.white)) def askGCodeFile(self) -> None: # noinspection PyCallByClass, PyTypeChecker filetuple = QFileDialog.getOpenFileName(self, 'Select G Code file', getResourcesPath(), 'G Code files (*.gcode);;' 'Text files (*.txt);;' 'All Files (*.*)') if filetuple: if os.path.isfile(filetuple[0]): self.loadGCode(filetuple[0]) def zoomIn(self) -> None: self.graphicsView.scale(1.15, 1.15) self.zoomFactor *= 1.15 def zoomOut(self) -> None: self.graphicsView.scale(1.0 / 1.15, 1.0 / 1.15) self.zoomFactor /= 1.15 def resetZoom(self) -> None: self.graphicsView.scale(1.0 / self.zoomFactor, 1.0 / self.zoomFactor) self.zoomFactor = 1 def loadGCode(self, filename: str) -> None: rawSteps = [] # a step is tuple of str (command) and dict of arg -> value # eg ('G1', {'X': 0}) with open(filename) as f: for index, line in enumerate(f): line = line.split(';', 1)[0] if not line: continue splitted = line.strip().split(' ') cmd = splitted[0] packedArgs = splitted[1:] args = {} for arg in packedArgs: args[arg[0]] = arg[1:] rawSteps.append((cmd, args)) for rawStep in rawSteps: cmd = rawStep[0] args = rawStep[1] if cmd == 'G2' or cmd == 'G3': try: args['I'] except KeyError: args['I'] = 0 try: args['J'] except KeyError: args['J'] = 0 self.execGCode(rawSteps) def execGCode(self, codes: List[GCode]) -> None: relative_mode = False prevX = 0 prevY = 0 for code in codes: cmd = code[0] args = code[1] if 'X' in args: x = float(args['X']) + (prevX if relative_mode else 0) else: x = prevX if 'Y' in args: y = float(args['Y']) + (prevY if relative_mode else 0) else: y = prevY if cmd == 'G0': line = QGraphicsMovementLineItem( line=QLineF(prevX, prevY, x, y), color=self._moveLineColor, penWidth=self.precision) if not self.checkBoxActionShowMovement.isChecked(): line.setVisible(False) self.scene.addItem(line) elif cmd == 'G1': self.scene.addItem( QGraphicsColoredLineItem( line=QLineF(prevX, prevY, x, y), penWidth=self.precision)) elif cmd == 'G2' or cmd == 'G3': offsetX = float(args['I']) offsetY = float(args['J']) if offsetX == 0 and offsetY == 0: # only R given radius = float(args['R']) dx = x - prevX dy = y - prevY dist = math.sqrt(dx ** 2 + dy ** 2) h = math.sqrt((radius ** 2) - ((dist ** 2) / 4)) tmpx = dy * h / dist tmpy = -dx * h / dist ccw = (cmd == 'G3') if (ccw and radius > 0) or ((not ccw) and radius < 0): tmpx = -tmpx tmpy = -tmpy middleX = tmpx + (2 * x - dx) / 2 middleY = tmpy + (2 * y - dy) / 2 else: radius = math.sqrt(offsetX ** 2 + offsetY ** 2) middleX = prevX + offsetX middleY = prevY + offsetY rectBottomLeftX = middleX - radius rectBottomLeftY = middleY - radius rectLength = 2 * radius alpha = math.degrees(math.atan2(prevY - middleY, prevX - middleX)) beta = math.degrees(math.atan2(y - middleY, x - middleX)) if cmd == 'G2': if beta > alpha: if beta >= 180: beta -= 360 else: alpha += 360 elif cmd == 'G3': if beta < alpha: if alpha > 180: alpha -= 360 else: beta += 360 delta = alpha - beta if delta == 0: delta = 360 ellipse = QGraphicsArcItem(rectBottomLeftX, rectBottomLeftY, rectLength, rectLength, penWidth=self.precision) ellipse.setStartAngle(-alpha) ellipse.setSpanAngle(delta) self.scene.addItem(ellipse) elif cmd == 'G91': relative_mode = True elif cmd == 'G90': relative_mode = False elif cmd == 'G28': # reference drive + general init relative_mode = False x = -0.9 y = 242.3 prevX = x prevY = y
class ui_simulator(object): def init_ui(self, simulator): simulator.setObjectName("Simulator") simulator.setFixedSize(748, 519) self.frame = QFrame(simulator) self.frame.setGeometry(QtCore.QRect(50, 340, 651, 151)) self.frame.setFrameShape(QFrame.StyledPanel) self.frame.setFrameShadow(QFrame.Raised) self.frame.setObjectName("frame") self.group = QGroupBox(self.frame) self.group.setGeometry(QtCore.QRect(10, 10, 171, 131)) self.group.setObjectName("group") self.rb_1 = QRadioButton(self.group) self.rb_1.setGeometry(QtCore.QRect(10, 30, 82, 17)) self.rb_1.setObjectName("rb") self.rb_1.toggled.connect(lambda: self.show_nodes(self.rb_1)) self.rb_2 = QRadioButton(self.group) self.rb_2.setGeometry(QtCore.QRect(10, 50, 82, 17)) self.rb_2.setObjectName("rb_2") self.rb_2.toggled.connect(lambda: self.show_nodes(self.rb_2)) self.rb_3 = QRadioButton(self.group) self.rb_3.setGeometry(QtCore.QRect(10, 70, 82, 17)) self.rb_3.setObjectName("rb_3") self.rb_3.toggled.connect(lambda: self.show_nodes(self.rb_3)) self.rb_4 = QRadioButton(self.group) self.rb_4.setGeometry(QtCore.QRect(10, 90, 82, 17)) self.rb_4.setObjectName("rb_4") self.rb_4.toggled.connect(lambda: self.show_nodes(self.rb_4)) self.button = QPushButton(self.frame) self.button.setGeometry(QtCore.QRect(210, 110, 75, 23)) self.button.setObjectName("button") self.button.clicked.connect(self.runner) # self.button.click(self, PyQt5.QtWidgets.PYQT_SIGNAL("clicked()"), self.runner) # QObject.connect(self.button, PYQT_SIGNAL("clicked()"), b2_clicked) self.button.setToolTip('Run simulation using selected number of nodes') self.frame_2 = QFrame(simulator) self.frame_2.setGeometry(QtCore.QRect(50, 39, 641, 291)) self.frame_2.setFrameShape(QFrame.StyledPanel) self.frame_2.setFrameShadow(QFrame.Raised) self.frame_2.setObjectName("frame_2") self.graphics = QGraphicsView(self.frame_2) self.graphics.setGeometry(QtCore.QRect(0, 0, 641, 291)) self.graphics.setObjectName("graphics") self.scene = QGraphicsScene(0, 0, 600, 250) self.label = QLabel(simulator) self.label.setGeometry(QtCore.QRect(50, 10, 61, 20)) self.label.setObjectName("label") self.console = QLabel(self.frame) self.console.setGeometry(QtCore.QRect(300, 10, 61, 20)) self.console.setObjectName("console_label") self.textarea = QTextEdit(simulator) self.textarea.setStyleSheet("color: white; background-color: black;") self.textarea.setReadOnly(True) self.textarea.setGeometry(QtCore.QRect(410, 350, 300, 131)) self.textarea.setObjectName("textarea") self.retranslate_ui(simulator) QtCore.QMetaObject.connectSlotsByName(simulator) def retranslate_ui(self, simulator): simulator.setWindowTitle(_translate("Simulator", "Simulator", None)) self.group.setTitle(_translate("Simulator", "Nodes:", None)) self.console.setText("Console: ") self.rb_1.setText(_translate("Simulator", "5", None)) self.rb_2.setText(_translate("Simulator", "10", None)) self.rb_3.setText(_translate("Simulator", "15", None)) self.rb_4.setText(_translate("Simulator", "20", None)) self.button.setText(_translate("Simulator", "Start", None)) self.label.setText(_translate("Simulator", "Node Grid:", None)) @pyqtSlot() def runner(self): grid = Grid() air = sc() self.group.setEnabled(False) self.textarea.setTextColor(Qt.white) node_names = list(string.ascii_uppercase) for i in range(len(self.random_x)): grid.add_node(node_names[i], self.random_x[i], self.random_y[i]) # grid.establish_conn() grid.establish_conn(True) nd = grid.node_dictionary # print(nd.keys()) for n in nd.values(): # print(str(n.x_pos) + " " +str(n.y_pos)) self.textarea.append( str(n.name) + " Neighbor Table: " + str([x.name for x in n.neighbors.keys()]) + "\nRouting table: " + str(n.RT) + "\n") for item in self.graphics.scene().items(): i = self.graphics.scene().items().index(item) item.setToolTip("Node name: " + str(node_names[i]) + "\n X: " + str(self.random_x[i]) + " Y: " + str(self.random_y[i])) for x in range(5): for item in self.graphics.scene().items(): item.setBrush(Qt.green) self.textarea.append("Transmission attempt: " + str(x + 1)) src = nd[random.choice(list(nd.keys()))] dst = nd[random.choice(list(nd.keys()))] while src is dst: dst = nd[random.choice(list(nd.keys()))] src.prepare_msg(src, dst, 'Hi') self.textarea.append("Sending from " + src.name + " to " + dst.name) while src.buffer: src_pos = self.random_x.index(src.x_pos) dst_pos = self.random_x.index(dst.x_pos) self.graphics.scene().items()[src_pos].setBrush(Qt.blue) self.graphics.scene().items()[dst_pos].setBrush(Qt.red) self.textarea.append("Current Transmission range (" + src.name + "): " + str(src.t_range) + "m") air.carry(src.send_msg()) rcv = list(air.transmit_to) self.textarea.append("Next hop: " + str(air.message.target_node)) air.propagate(self.textarea) for node in rcv: if node.buffer: src = node QApplication.processEvents() time.sleep(0.5) self.textarea.append('-------------') self.group.setEnabled(True) def show_nodes(self, button): self.scene.setSceneRect(0, 0, 600, 250) self.textarea.setText("") self.scene.clear() # scene.setSceneRect(0, 0, 600, 250) nodes = int(button.text()) self.random_x = random.sample(range(1, 31), nodes) self.random_y = random.sample(range(1, 31), nodes) for i in range(len(self.random_x)): item = QGraphicsEllipseItem(self.random_x[i] * 8, self.random_y[i] * 8, 15, 15) item.setToolTip("X: " + str(self.random_x[i]) + " Y: " + str(self.random_y[i])) item.setBrush(Qt.green) self.scene.addItem(item) self.graphics.setScene(self.scene) self.graphics.update()
class MapCanvas(QGraphicsView): def __init__(self): # UI Init super(QGraphicsView, self).__init__() self.setAutoFillBackground(True) self.setAttribute(Qt.WA_StyledBackground) self.setStyleSheet( 'QGraphicsView { background-color: rgba(0, 0, 0, 255); }' ) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setContentsMargins(0, 0, 0, 0) self.setTransformationAnchor(self.AnchorViewCenter) self.setFocusPolicy(Qt.StrongFocus) self.setRenderHint(QPainter.Antialiasing) # Class Init self._scene = QGraphicsScene(self) self.setScene(self._scene) self.scale_ratio = 1 self.map_data = None self.map_line_path_items = {} self.map_points_items = [] self.map_points_text_items = [] self.map_grid_path_item = QGraphicsPathItem() self.map_points_player_items = {} self.players = {} # Application Settings self.settings = settings.Settings('parse99') def load_map(self, map_name): self._scene.clear() self.map_data = MapData(map_name) self.create_grid_lines() self.create_map_lines() self.create_map_points() self.update_players() self.set_scene_padding(self.map_data.map_grid_geometry.width, self.map_data.map_grid_geometry.height) self.draw() self.centerOn(0, 0) def create_grid_lines(self): grid_line_width = self.settings.get_value('maps', 'grid_line_width') self.map_grid_path_item = QGraphicsPathItem() line_path = QPainterPath() for map_line in self.map_data.grid_lines: line_path.moveTo(map_line.x1, map_line.y1) line_path.lineTo(map_line.x2, map_line.y2) self.map_grid_path_item = QGraphicsPathItem(line_path) color = QColor().fromRgb(255, 255, 255, 25) self.map_grid_path_item.setPen( QPen( color, grid_line_width / self.scale_ratio ) ) def create_map_lines(self): map_line_width = self.settings.get_value('maps', 'map_line_width') # use color as string for dictionary keys to preserve line colours self.map_line_path_items = {} line_path = {} colors = {} for map_line in self.map_data.map_lines: key = str(map_line.r) + ',' \ + str(map_line.g) + ',' \ + str(map_line.b) if key not in line_path.keys(): line_path[key] = QPainterPath() colors[key] = QColor().fromRgb( map_line.r, map_line.g, map_line.b ) line_path[key].moveTo(QPointF(map_line.x1, map_line.y1)) line_path[key].lineTo(QPointF(map_line.x2, map_line.y2)) for key in line_path.keys(): self.map_line_path_items[key] = QGraphicsPathItem(line_path[key]) self.map_line_path_items[key].setPen( QPen( colors[key], map_line_width / self.scale_ratio ) ) def create_map_points(self): self.map_points_text_items = [] self.map_points_items = [] for map_point in self.map_data.map_points: color = QColor().fromRgb(map_point.r, map_point.g, map_point.b) rect = QGraphicsRectItem( QRectF( QPointF(map_point.x, map_point.y), QSizeF(5 / self.scale_ratio, 5 / self.scale_ratio) ) ) rect.setPen(QPen(Qt.black, 1 / self.scale_ratio)) rect.setBrush(color) self.map_points_items.append(rect) text = QGraphicsTextItem(map_point.text) text.setDefaultTextColor(color) text.setPos(map_point.x, map_point.y) text.setFont(QFont('Times New Roman', 8 / self.scale_ratio, 2)) self.map_points_text_items.append(text) def draw(self): # Draw map grid self._scene.addItem(self.map_grid_path_item) # Draw map lines for key in self.map_line_path_items.keys(): self._scene.addItem(self.map_line_path_items[key]) # Draw map points for item in self.map_points_items: self._scene.addItem(item) # Draw map point's text for item in self.map_points_text_items: self._scene.addItem(item) def update_players(self): # Convert lists to sets player_list_set = set(self.players.keys()) # Player points and text should be the same so only use one player_items_set = set(self.map_points_player_items.keys()) # calculate size of player circles circle_size = max(10, 10 / self.scale_ratio) # Draw and/or update all players in players for player in player_list_set: player_data = self.players[player] if player in player_items_set and \ self.map_points_player_items[player] in self._scene.items(): # Update self.map_points_player_items[player_data.name].setRect( player_data.x - circle_size / 2, player_data.y - circle_size / 2, circle_size, circle_size ) else: # Create New Point color = QColor().fromRgb( player_data.r, player_data.g, player_data.b ) circle = QGraphicsEllipseItem( player_data.x - circle_size / 2, player_data.y - circle_size / 2, circle_size, circle_size ) circle.setBrush(color) self.map_points_player_items[player_data.name] = circle self._scene.addItem( self.map_points_player_items[player_data.name] ) # Find/remove players who aren't in players list from the map for key in [player for player in player_items_set if player not in player_list_set]: self._scene.removeItem(self.map_points_player_items[key]) # Center map self.center() def set_scale(self, ratio): # Scale scene self.setTransform(QTransform()) self.scale_ratio = ratio self.scale(self.scale_ratio, self.scale_ratio) # Scale map lines map_line_width = self.settings.get_value('maps', 'map_line_width') for key in self.map_line_path_items.keys(): pen = self.map_line_path_items[key].pen() pen.setWidth( max( map_line_width, map_line_width / self.scale_ratio ) ) self.map_line_path_items[key].setPen(pen) # Scale map grid grid_line_width = self.settings.get_value('maps', 'grid_line_width') pen = self.map_grid_path_item.pen() pen.setWidth( max( grid_line_width, grid_line_width / self.scale_ratio ) ) self.map_grid_path_item.setPen(pen) # Scale map points for i, rect in enumerate(self.map_points_items): rect.setRect( self.map_data.map_points[i].x, self.map_data.map_points[i].y, max(5, 5 / self.scale_ratio), max(5, 5 / self.scale_ratio) ) # Scale map point's text for i, text in enumerate(self.map_points_text_items): text.setFont( QFont( 'Times New Roman', max(8, 8 / self.scale_ratio) ) ) text.setX( self.map_data.map_points[i].x + max(5, 5 / self.scale_ratio) ) # Scale player point circle_size = max(10, 10 / self.scale_ratio) for player in self.map_points_player_items.keys(): self.map_points_player_items[player].setRect( self.players[player].x - circle_size / 2, self.players[player].y - circle_size / 2, circle_size, circle_size ) def set_scene_padding(self, padding_x, padding_y): # Make it so that if you are zoomed out, you can still # drag the map around (not that smooth) rect = self._scene.sceneRect() rect.adjust( -padding_x * 2, -padding_y * 2, padding_x * 2, padding_y * 2 ) self.setSceneRect(rect) def draw_loading_screen(self): pass def fit_to_window(self): pass def center(self): if self.settings.get_value('maps', 'center_on') == 'player': # Center on Player for now by default # Added try/except because initialization causes resize event try: if '__you__' in self.players.keys(): self.centerOn( self.players['__you__'].x, self.players['__you__'].y ) except AttributeError as e: print("MapCanvas().center():", e) def add_player(self, name, time_stamp, location): y, x, z = [float(value) for value in location.strip().split(',')] y = -y x = -x if name not in self.players.keys(): r, g, b = (0, 255, 0) flag = '__other__' user_level = None if name == '__you__': r, g, b = (0, 255, 0) flag = '__you__' user_level = None self.players[name] = Player( name=name, x=x, y=y, z=z, r=r, g=g, b=b, flag=flag, user_level=user_level, time_stamp=time_stamp ) else: self.players[name].x = x self.players[name].y = y self.players[name].z = z self.players[name].time_stamp = time_stamp def wheelEvent(self, event): # Scale based on scroll wheel direction movement = event.angleDelta().y() if movement > 0: self.set_scale(self.scale_ratio + self.scale_ratio * 0.1) else: self.set_scale(self.scale_ratio - self.scale_ratio * 0.1) def keyPressEvent(self, event): # Enable drag mode while control button is being held down if event.modifiers() == Qt.ControlModifier: self.setDragMode(self.ScrollHandDrag) return QGraphicsView.keyPressEvent(self, event) def keyReleaseEvent(self, event): # Disable drag mode when control button released if event.key() == Qt.Key_Control: self.setDragMode(self.NoDrag) return QGraphicsView.keyPressEvent(self, event) def resizeEvent(self, event): self.center() return QGraphicsView.resizeEvent(self, event)
class Traces(QGraphicsView): """Main widget that contains the recordings to be plotted. Attributes ---------- parent : instance of QMainWindow the main window. config : instance of ConfigTraces settings for this widget y_scrollbar_value : int position of the vertical scrollbar data : instance of ChanTime filtered and reref'ed data chan : list of str list of channels (labels and channel group) chan_pos : list of int y-position of each channel (based on value at 0) chan_scale : list of float scaling factor for each channel time_pos : list of QPointF we need to keep track of the position of time label during creation sel_chan : int index of self.chan of the first selected channel sel_xy : tuple of 2 floats x and y position of the first selected point scene : instance of QGraphicsScene the main scene. idx_label : list of instance of QGraphicsSimpleTextItem the channel labels on the y-axis idx_time : list of instance of QGraphicsSimpleTextItem the time labels on the x-axis idx_sel : instance of QGraphicsRectItem the rectangle showing the selection (both for selection and event) idx_info : instance of QGraphicsSimpleTextItem the rectangle showing the selection idx_markers : list of QGraphicsRectItem list of markers in the dataset idx_annot : list of QGraphicsRectItem list of user-made annotations """ def __init__(self, parent): super().__init__() self.parent = parent self.config = ConfigTraces(self.parent.overview.update_position) self.y_scrollbar_value = 0 self.data = None self.chan = [] self.chan_pos = [] # used later to find out which channel we're using self.chan_scale = [] self.time_pos = [] self.sel_chan = None self.sel_xy = (None, None) self.scene = None self.idx_label = [] self.idx_time = [] self.idx_sel = None self.idx_info = None self.idx_markers = [] self.idx_annot = [] self.create_action() def create_action(self): """Create actions associated with this widget.""" actions = {} act = QAction(QIcon(ICON['step_prev']), 'Previous Step', self) act.setShortcut(QKeySequence.MoveToPreviousChar) act.triggered.connect(self.step_prev) actions['step_prev'] = act act = QAction(QIcon(ICON['step_next']), 'Next Step', self) act.setShortcut(QKeySequence.MoveToNextChar) act.triggered.connect(self.step_next) actions['step_next'] = act act = QAction(QIcon(ICON['page_prev']), 'Previous Page', self) act.setShortcut(QKeySequence.MoveToPreviousPage) act.triggered.connect(self.page_prev) actions['page_prev'] = act act = QAction(QIcon(ICON['page_next']), 'Next Page', self) act.setShortcut(QKeySequence.MoveToNextPage) act.triggered.connect(self.page_next) actions['page_next'] = act act = QAction(QIcon(ICON['zoomprev']), 'Wider Time Window', self) act.setShortcut(QKeySequence.ZoomIn) act.triggered.connect(self.X_more) actions['X_more'] = act act = QAction(QIcon(ICON['zoomnext']), 'Narrower Time Window', self) act.setShortcut(QKeySequence.ZoomOut) act.triggered.connect(self.X_less) actions['X_less'] = act act = QAction(QIcon(ICON['zoomin']), 'Larger Amplitude', self) act.setShortcut(QKeySequence.MoveToPreviousLine) act.triggered.connect(self.Y_more) actions['Y_less'] = act act = QAction(QIcon(ICON['zoomout']), 'Smaller Amplitude', self) act.setShortcut(QKeySequence.MoveToNextLine) act.triggered.connect(self.Y_less) actions['Y_more'] = act act = QAction(QIcon(ICON['ydist_more']), 'Larger Y Distance', self) act.triggered.connect(self.Y_wider) actions['Y_wider'] = act act = QAction(QIcon(ICON['ydist_less']), 'Smaller Y Distance', self) act.triggered.connect(self.Y_tighter) actions['Y_tighter'] = act act = QAction(QIcon(ICON['chronometer']), '6 Hours Earlier', self) act.triggered.connect(partial(self.add_time, -6 * 60 * 60)) actions['addtime_-6h'] = act act = QAction(QIcon(ICON['chronometer']), '1 Hour Earlier', self) act.triggered.connect(partial(self.add_time, -60 * 60)) actions['addtime_-1h'] = act act = QAction(QIcon(ICON['chronometer']), '10 Minutes Earlier', self) act.triggered.connect(partial(self.add_time, -10 * 60)) actions['addtime_-10min'] = act act = QAction(QIcon(ICON['chronometer']), '10 Minutes Later', self) act.triggered.connect(partial(self.add_time, 10 * 60)) actions['addtime_10min'] = act act = QAction(QIcon(ICON['chronometer']), '1 Hour Later', self) act.triggered.connect(partial(self.add_time, 60 * 60)) actions['addtime_1h'] = act act = QAction(QIcon(ICON['chronometer']), '6 Hours Later', self) act.triggered.connect(partial(self.add_time, 6 * 60 * 60)) actions['addtime_6h'] = act self.action = actions def read_data(self): """Read the data to plot.""" window_start = self.parent.value('window_start') window_end = window_start + self.parent.value('window_length') dataset = self.parent.info.dataset groups = self.parent.channels.groups chan_to_read = [] for one_grp in groups: chan_to_read.extend(one_grp['chan_to_plot'] + one_grp['ref_chan']) if not chan_to_read: return data = dataset.read_data(chan=chan_to_read, begtime=window_start, endtime=window_end) max_s_freq = self.parent.value('max_s_freq') if data.s_freq > max_s_freq: q = int(data.s_freq / max_s_freq) lg.debug('Decimate (no low-pass filter) at ' + str(q)) data.data[0] = data.data[0][:, slice(None, None, q)] data.axis['time'][0] = data.axis['time'][0][slice(None, None, q)] data.s_freq = int(data.s_freq / q) self.data = _create_data_to_plot(data, self.parent.channels.groups) def display(self): """Display the recordings.""" if self.data is None: return if self.scene is not None: self.y_scrollbar_value = self.verticalScrollBar().value() self.scene.clear() self.create_chan_labels() self.create_time_labels() window_start = self.parent.value('window_start') window_length = self.parent.value('window_length') time_height = max([x.boundingRect().height() for x in self.idx_time]) label_width = window_length * self.parent.value('label_ratio') scene_height = (len(self.idx_label) * self.parent.value('y_distance') + time_height) self.scene = QGraphicsScene(window_start - label_width, 0, window_length + label_width, scene_height) self.setScene(self.scene) self.idx_markers = [] self.idx_annot = [] self.add_chan_labels() self.add_time_labels() self.add_traces() self.display_grid() self.display_markers() self.display_annotations() self.resizeEvent(None) self.verticalScrollBar().setValue(self.y_scrollbar_value) self.parent.info.display_view() self.parent.overview.display_current() def create_chan_labels(self): """Create the channel labels, but don't plot them yet. Notes ----- It's necessary to have the width of the labels, so that we can adjust the main scene. """ self.idx_label = [] for one_grp in self.parent.channels.groups: for one_label in one_grp['chan_to_plot']: item = QGraphicsSimpleTextItem(one_label) item.setBrush(QBrush(QColor(one_grp['color']))) item.setFlag(QGraphicsItem.ItemIgnoresTransformations) self.idx_label.append(item) def create_time_labels(self): """Create the time labels, but don't plot them yet. Notes ----- It's necessary to have the height of the time labels, so that we can adjust the main scene. Not very robust, because it uses seconds as integers. """ min_time = int(floor(min(self.data.axis['time'][0]))) max_time = int(ceil(max(self.data.axis['time'][0]))) n_time_labels = self.parent.value('n_time_labels') self.idx_time = [] self.time_pos = [] for one_time in linspace(min_time, max_time, n_time_labels): x_label = (self.data.start_time + timedelta(seconds=one_time)).strftime('%H:%M:%S') item = QGraphicsSimpleTextItem(x_label) item.setFlag(QGraphicsItem.ItemIgnoresTransformations) self.idx_time.append(item) self.time_pos.append(QPointF(one_time, len(self.idx_label) * self.parent.value('y_distance'))) def add_chan_labels(self): """Add channel labels on the left.""" window_start = self.parent.value('window_start') window_length = self.parent.value('window_length') label_width = window_length * self.parent.value('label_ratio') for row, one_label_item in enumerate(self.idx_label): self.scene.addItem(one_label_item) one_label_item.setPos(window_start - label_width, self.parent.value('y_distance') * row + self.parent.value('y_distance') / 2) def add_time_labels(self): """Add time labels at the bottom.""" for text, pos in zip(self.idx_time, self.time_pos): self.scene.addItem(text) text.setPos(pos) def add_traces(self): """Add traces based on self.data.""" y_distance = self.parent.value('y_distance') self.chan = [] self.chan_pos = [] self.chan_scale = [] row = 0 for one_grp in self.parent.channels.groups: for one_chan in one_grp['chan_to_plot']: # channel name chan_name = one_chan + ' (' + one_grp['name'] + ')' # trace dat = (self.data(trial=0, chan=chan_name) * self.parent.value('y_scale')) dat *= -1 # flip data, upside down path = self.scene.addPath(Path(self.data.axis['time'][0], dat)) path.setPen(QPen(QColor(one_grp['color']), LINE_WIDTH)) # adjust position chan_pos = y_distance * row + y_distance / 2 path.setPos(0, chan_pos) row += 1 self.chan.append(chan_name) self.chan_scale.append(one_grp['scale']) self.chan_pos.append(chan_pos) def display_grid(self): """Display grid on x-axis and y-axis.""" window_start = self.parent.value('window_start') window_length = self.parent.value('window_length') window_end = window_start + window_length if self.parent.value('grid_x'): x_tick = self.parent.value('grid_xtick') x_ticks = arange(window_start, window_end + x_tick, x_tick) for x in x_ticks: x_pos = [x, x] y_pos = [0, self.parent.value('y_distance') * len(self.idx_label)] path = self.scene.addPath(Path(x_pos, y_pos)) path.setPen(QPen(QColor(LINE_COLOR), LINE_WIDTH, Qt.DotLine)) if self.parent.value('grid_y'): for one_label_item in self.idx_label: x_pos = [window_start, window_end] y_pos = [one_label_item.y(), one_label_item.y()] path = self.scene.addPath(Path(x_pos, y_pos)) path.setPen(QPen(QColor(LINE_COLOR), LINE_WIDTH, Qt.DotLine)) def display_markers(self): """Add markers on top of first plot.""" for item in self.idx_markers: self.scene.removeItem(item) self.idx_markers = [] window_start = self.parent.value('window_start') window_length = self.parent.value('window_length') window_end = window_start + window_length y_distance = self.parent.value('y_distance') markers = [] if self.parent.info.markers is not None: if self.parent.value('marker_show'): markers = self.parent.info.markers for mrk in markers: if window_start <= mrk['end'] and window_end >= mrk['start']: mrk_start = max((mrk['start'], window_start)) mrk_end = min((mrk['end'], window_end)) color = QColor(self.parent.value('marker_color')) item = QGraphicsRectItem(mrk_start, 0, mrk_end - mrk_start, len(self.idx_label) * y_distance) item.setPen(color) item.setBrush(color) item.setZValue(-9) self.scene.addItem(item) item = TextItem_with_BG(color.darker(200)) item.setText(mrk['name']) item.setPos(mrk['start'], len(self.idx_label) * self.parent.value('y_distance')) item.setFlag(QGraphicsItem.ItemIgnoresTransformations) item.setRotation(-90) self.scene.addItem(item) self.idx_markers.append(item) def display_annotations(self): """Mark all the bookmarks/events, on top of first plot.""" for item in self.idx_annot: self.scene.removeItem(item) self.idx_annot = [] window_start = self.parent.value('window_start') window_length = self.parent.value('window_length') window_end = window_start + window_length y_distance = self.parent.value('y_distance') raw_chan_name = list(map(take_raw_name, self.chan)) bookmarks = [] events = [] if self.parent.notes.annot is not None: if self.parent.value('annot_show'): bookmarks = self.parent.notes.annot.get_bookmarks() events = self.parent.notes.get_selected_events((window_start, window_end)) annotations = bookmarks + events for annot in annotations: if window_start <= annot['end'] and window_end >= annot['start']: mrk_start = max((annot['start'], window_start)) mrk_end = min((annot['end'], window_end)) if annot in bookmarks: color = QColor(self.parent.value('annot_bookmark_color')) if annot in events: color = convert_name_to_color(annot['name']) if annot['chan'] == ['']: h_annot = len(self.idx_label) * y_distance y_annot = (0, ) item = TextItem_with_BG(color.darker(200)) item.setText(annot['name']) item.setPos(annot['start'], len(self.idx_label) * y_distance) item.setFlag(QGraphicsItem.ItemIgnoresTransformations) item.setRotation(-90) self.scene.addItem(item) self.idx_annot.append(item) zvalue = -8 else: h_annot = y_distance # find indices of channels with annotations chan_idx_in_mrk = in1d(raw_chan_name, annot['chan']) y_annot = asarray(self.chan_pos)[chan_idx_in_mrk] y_annot -= y_distance / 2 zvalue = -7 for y in y_annot: item = QGraphicsRectItem(mrk_start, y, mrk_end - mrk_start, h_annot) item.setPen(color) item.setBrush(color) item.setZValue(zvalue) self.scene.addItem(item) self.idx_annot.append(item) def step_prev(self): """Go to the previous step.""" window_start = (self.parent.value('window_start') - self.parent.value('window_length') / self.parent.value('window_step')) self.parent.overview.update_position(window_start) def step_next(self): """Go to the next step.""" window_start = (self.parent.value('window_start') + self.parent.value('window_length') / self.parent.value('window_step')) self.parent.overview.update_position(window_start) def page_prev(self): """Go to the previous page.""" window_start = (self.parent.value('window_start') - self.parent.value('window_length')) self.parent.overview.update_position(window_start) def page_next(self): """Go to the next page.""" window_start = (self.parent.value('window_start') + self.parent.value('window_length')) self.parent.overview.update_position(window_start) def add_time(self, extra_time): """Go to the predefined time forward.""" window_start = self.parent.value('window_start') + extra_time self.parent.overview.update_position(window_start) def X_more(self): """Zoom in on the x-axis.""" self.parent.value('window_length', self.parent.value('window_length') * 2) self.parent.overview.update_position() def X_less(self): """Zoom out on the x-axis.""" self.parent.value('window_length', self.parent.value('window_length') / 2) self.parent.overview.update_position() def X_length(self, new_window_length): """Use presets for length of the window.""" self.parent.value('window_length', new_window_length) self.parent.overview.update_position() def Y_more(self): """Increase the amplitude.""" self.parent.value('y_scale', self.parent.value('y_scale') * 2) self.parent.traces.display() def Y_less(self): """Decrease the amplitude.""" self.parent.value('y_scale', self.parent.value('y_scale') / 2) self.parent.traces.display() def Y_ampl(self, new_y_scale): """Make amplitude on Y axis using predefined values""" self.parent.value('y_scale', new_y_scale) self.parent.traces.display() def Y_wider(self): """Increase the distance of the lines.""" self.parent.value('y_distance', self.parent.value('y_distance') * 1.4) self.parent.traces.display() def Y_tighter(self): """Decrease the distance of the lines.""" self.parent.value('y_distance', self.parent.value('y_distance') / 1.4) self.parent.traces.display() def Y_dist(self, new_y_distance): """Use preset values for the distance between lines.""" self.parent.value('y_distance', new_y_distance) self.parent.traces.display() def mousePressEvent(self, event): """Create a marker or start selection Parameters ---------- event : instance of QtCore.QEvent it contains the position that was clicked. """ if not self.scene: return xy_scene = self.mapToScene(event.pos()) chan_idx = argmin(abs(asarray(self.chan_pos) - xy_scene.y())) self.sel_chan = chan_idx self.sel_xy = (xy_scene.x(), xy_scene.y()) chk_marker = self.parent.notes.action['new_bookmark'].isChecked() chk_event = self.parent.notes.action['new_event'].isChecked() if not (chk_marker or chk_event): channame = self.chan[self.sel_chan] + ' in selected window' self.parent.spectrum.show_channame(channame) def mouseMoveEvent(self, event): """When normal selection, update power spectrum with current selection. Otherwise, show the range of the new marker. """ if not self.scene: return if self.idx_sel in self.scene.items(): self.scene.removeItem(self.idx_sel) self.idx_sel = None chk_marker = self.parent.notes.action['new_bookmark'].isChecked() chk_event = self.parent.notes.action['new_event'].isChecked() if chk_marker or chk_event: xy_scene = self.mapToScene(event.pos()) y_distance = self.parent.value('y_distance') pos = QRectF(self.sel_xy[0], 0, xy_scene.x() - self.sel_xy[0], len(self.idx_label) * y_distance) item = QGraphicsRectItem(pos.normalized()) item.setPen(NoPen) if chk_marker: color = QColor(self.parent.value('annot_bookmark_color')) elif chk_event: eventtype = self.parent.notes.idx_eventtype.currentText() color = convert_name_to_color(eventtype) item.setBrush(QBrush(color.lighter(115))) item.setZValue(-10) self.scene.addItem(item) self.idx_sel = item return xy_scene = self.mapToScene(event.pos()) pos = QRectF(self.sel_xy[0], self.sel_xy[1], xy_scene.x() - self.sel_xy[0], xy_scene.y() - self.sel_xy[1]) self.idx_sel = QGraphicsRectItem(pos.normalized()) self.idx_sel.setPen(QPen(QColor(LINE_COLOR), LINE_WIDTH)) self.scene.addItem(self.idx_sel) if self.idx_info in self.scene.items(): self.scene.removeItem(self.idx_info) duration = '{0:0.2f}s'.format(abs(xy_scene.x() - self.sel_xy[0])) # get y-size, based on scaling too y = abs(xy_scene.y() - self.sel_xy[1]) scale = self.parent.value('y_scale') * self.chan_scale[self.sel_chan] height = '{0:0.3f}uV'.format(y / scale) item = TextItem_with_BG() item.setText(duration + ' ' + height) item.setPos(self.sel_xy[0], self.sel_xy[1]) self.scene.addItem(item) self.idx_info = item trial = 0 time = self.parent.traces.data.axis['time'][trial] beg_win = min((self.sel_xy[0], xy_scene.x())) end_win = max((self.sel_xy[0], xy_scene.x())) time_of_interest = time[(time >= beg_win) & (time < end_win)] if len(time_of_interest) > MINIMUM_N_SAMPLES: data = self.parent.traces.data(trial=trial, chan=self.chan[self.sel_chan], time=time_of_interest) n_data = len(data) n_pad = (power(2, ceil(log2(n_data))) - n_data) / 2 data = pad(data, (int(ceil(n_pad)), int(floor(n_pad))), 'constant') self.parent.spectrum.display(data) def mouseReleaseEvent(self, event): """Create a new event or marker, or show the previous power spectrum """ if not self.scene: return chk_marker = self.parent.notes.action['new_bookmark'].isChecked() chk_event = self.parent.notes.action['new_event'].isChecked() if chk_marker or chk_event: x_in_scene = self.mapToScene(event.pos()).x() # it can happen that selection is empty (f.e. double-click) if self.sel_xy[0] is not None: # max resolution = sampling frequency # in case there is no data s_freq = self.parent.info.dataset.header['s_freq'] at_s_freq = lambda x: round(x * s_freq) / s_freq start = at_s_freq(self.sel_xy[0]) end = at_s_freq(x_in_scene) if abs(end - start) < self.parent.value('min_marker_dur'): end = start if start <= end: time = (start, end) else: time = (end, start) if chk_marker: self.parent.notes.add_bookmark(time) elif chk_event: eventtype = self.parent.notes.idx_eventtype.currentText() self.parent.notes.add_event(eventtype, time) else: # normal selection if self.idx_info in self.scene.items(): self.scene.removeItem(self.idx_info) self.idx_info = None # restore spectrum self.parent.spectrum.update() self.parent.spectrum.display_window() # general garbage collection self.sel_chan = None self.sel_xy = (None, None) if self.idx_sel in self.scene.items(): self.scene.removeItem(self.idx_sel) self.idx_sel = None def resizeEvent(self, event): """Resize scene so that it fits the whole widget. Parameters ---------- event : instance of QtCore.QEvent not important Notes ----- This function overwrites Qt function, therefore the non-standard name. Argument also depends on Qt. The function is used to change the scale of view, so that the scene fits the whole scene. There are two problems that I could not fix: 1) how to give the width of the label in absolute width, 2) how to strech scene just enough that it doesn't trigger a scrollbar. However, it's pretty good as it is now. """ if self.scene is not None: ratio = self.width() / (self.scene.width() * 1.1) self.resetTransform() self.scale(ratio, 1) def reset(self): self.y_scrollbar_value = 0 self.data = None self.chan = [] self.chan_pos = [] self.chan_scale = [] self.sel_chan = None self.sel_xy = (None, None) if self.scene is not None: self.scene.clear() self.scene = None self.idx_sel = None self.idx_info = None self.idx_label = [] self.idx_time = [] self.time_pos = []
class MainWindow(QMainWindow): def __init__(self, parent): QMainWindow.__init__(self) self.printer = QPrinter() self.load_img = self.load_img_fit self.reload_img = self.reload_auto self.open_new = parent.open_win self.exit = parent.closeAllWindows self.scene = QGraphicsScene() self.img_view = ImageView(self) self.img_view.setScene(self.scene) self.setCentralWidget(self.img_view) self.create_actions() self.create_menu() self.create_dict() self.slides_next = True self.setContextMenuPolicy(Qt.CustomContextMenu) self.customContextMenuRequested.connect(self.showMenu) self.read_prefs() self.read_list = parent.read_list self.write_list = parent.write_list self.pics_dir = os.path.expanduser('~/Pictures') or QDir.currentPath() self.resize(700, 500) def create_actions(self): self.open_act = QAction('&Open', self, shortcut='Ctrl+O') self.open_act.triggered.connect(self.open) self.open_new_act = QAction('Open new window', self, shortcut='Ctrl+Shift+O') self.open_new_act.triggered.connect(partial(self.open, True)) self.reload_act = QAction('&Reload image', self, shortcut='Ctrl+R') self.reload_act.triggered.connect(self.reload_img) self.print_act = QAction('&Print', self, shortcut='Ctrl+P') self.print_act.triggered.connect(self.print_img) self.save_act = QAction('&Save image', self, shortcut='Ctrl+S') self.save_act.triggered.connect(self.save_img) self.close_act = QAction('Close window', self, shortcut='Ctrl+W') self.close_act.triggered.connect(self.close) self.exit_act = QAction('E&xit', self, shortcut='Ctrl+Q') self.exit_act.triggered.connect(self.exit) self.fulls_act = QAction('Fullscreen', self, shortcut='F11', checkable=True) self.fulls_act.triggered.connect(self.toggle_fs) self.ss_act = QAction('Slideshow', self, shortcut='F5', checkable=True) self.ss_act.triggered.connect(self.toggle_slideshow) self.ss_next_act = QAction('Next / Random image', self, checkable=True) self.ss_next_act.triggered.connect(self.set_slide_type) self.ss_next_act.setChecked(True) self.next_act = QAction('Next image', self, shortcut='Right') self.next_act.triggered.connect(self.go_next_img) self.prev_act = QAction('Previous image', self, shortcut='Left') self.prev_act.triggered.connect(self.go_prev_img) self.rotleft_act = QAction('Rotate left', self, shortcut='Ctrl+Left') self.rotleft_act.triggered.connect(partial(self.img_rotate, 270)) self.rotright_act = QAction('Rotate right', self, shortcut='Ctrl+Right') self.rotright_act.triggered.connect(partial(self.img_rotate, 90)) self.fliph_act = QAction('Flip image horizontally', self, shortcut='Ctrl+H') self.fliph_act.triggered.connect(partial(self.img_flip, -1, 1)) self.flipv_act = QAction('Flip image vertically', self, shortcut='Ctrl+V') self.flipv_act.triggered.connect(partial(self.img_flip, 1, -1)) self.resize_act = QAction('Resize image', self, triggered=self.resize_img) self.crop_act = QAction('Crop image', self, triggered=self.crop_img) self.zin_act = QAction('Zoom &In', self, shortcut='Up') self.zin_act.triggered.connect(partial(self.img_view.zoom, 1.1)) self.zout_act = QAction('Zoom &Out', self, shortcut='Down') self.zout_act.triggered.connect(partial(self.img_view.zoom, 1 / 1.1)) self.fit_win_act = QAction('Best &fit', self, checkable=True, shortcut='F', triggered=self.zoom_default) self.fit_win_act.setChecked(True) self.prefs_act = QAction('Preferences', self, triggered=self.set_prefs) self.props_act = QAction('Properties', self, triggered=self.get_props) self.help_act = QAction('&Help', self, shortcut='F1', triggered=self.help_page) self.about_act = QAction('&About', self, triggered=self.about_cm) self.aboutQt_act = QAction('About &Qt', self, triggered=qApp.aboutQt) def create_menu(self): self.popup = QMenu(self) main_acts = [self.open_act, self.open_new_act, self.reload_act, self.print_act, self.save_act] edit_acts1 = [self.rotleft_act, self.rotright_act, self.fliph_act, self.flipv_act] edit_acts2 = [self.resize_act, self.crop_act] view_acts = [self.next_act, self.prev_act, self.zin_act, self.zout_act, self.fit_win_act, self.fulls_act, self.ss_act, self.ss_next_act] help_acts = [self.help_act, self.about_act, self.aboutQt_act] end_acts = [self.prefs_act, self.props_act, self.close_act, self.exit_act] for act in main_acts: self.popup.addAction(act) edit_menu = QMenu(self.popup) edit_menu.setTitle('&Edit') for act in edit_acts1: edit_menu.addAction(act) edit_menu.addSeparator() for act in edit_acts2: edit_menu.addAction(act) self.popup.addMenu(edit_menu) view_menu = QMenu(self.popup) view_menu.setTitle('&View') for act in view_acts: view_menu.addAction(act) self.popup.addMenu(view_menu) help_menu = QMenu(self.popup) help_menu.setTitle('&Help') for act in help_acts: help_menu.addAction(act) self.popup.addMenu(help_menu) for act in end_acts: self.popup.addAction(act) self.action_list = main_acts + edit_acts1 + edit_acts2 + view_acts + help_acts + end_acts for act in self.action_list: self.addAction(act) def showMenu(self, pos): self.popup.popup(self.mapToGlobal(pos)) def create_dict(self): """Create a dictionary to handle auto-orientation.""" self.orient_dict = {None: self.load_img, '1': self.load_img, '2': partial(self.img_flip, -1, 1), '3': partial(self.img_rotate, 180), '4': partial(self.img_flip, -1, 1), '5': self.img_rotate_fliph, '6': partial(self.img_rotate, 90), '7': self.img_rotate_flipv, '8': partial(self.img_rotate, 270)} def read_prefs(self): """Parse the preferences from the config file, or set default values.""" try: conf = preferences.Config() values = conf.read_config() self.auto_orient = values[0] self.slide_delay = values[1] self.quality = values[2] except: self.auto_orient = True self.slide_delay = 5 self.quality = 90 self.reload_img = self.reload_auto if self.auto_orient else self.reload_nonauto def set_prefs(self): """Write preferences to the config file.""" dialog = preferences.PrefsDialog(self) if dialog.exec_() == QDialog.Accepted: self.auto_orient = dialog.auto_orient self.slide_delay = dialog.delay_spinb.value() self.quality = dialog.qual_spinb.value() conf = preferences.Config() conf.write_config(self.auto_orient, self.slide_delay, self.quality) self.reload_img = self.reload_auto if self.auto_orient else self.reload_nonauto def open(self, new_win=False): fname = QFileDialog.getOpenFileName(self, 'Open File', self.pics_dir)[0] if fname: if fname.lower().endswith(self.read_list): if new_win: self.open_new(fname) else: self.open_img(fname) else: QMessageBox.information(self, 'Error', 'Cannot load {} images.'.format(fname.rsplit('.', 1)[1])) def open_img(self, fname): self.fname = fname self.reload_img() dirname = os.path.dirname(self.fname) self.set_img_list(dirname) self.img_index = self.filelist.index(self.fname) def set_img_list(self, dirname): """Create a list of readable images from the current directory.""" filelist = os.listdir(dirname) self.filelist = [os.path.join(dirname, fname) for fname in filelist if fname.lower().endswith(self.read_list)] self.filelist.sort() self.last_file = len(self.filelist) - 1 def get_img(self): """Get image from fname and create pixmap.""" image = QImage(self.fname) self.pixmap = QPixmap.fromImage(image) self.setWindowTitle(self.fname.rsplit('/', 1)[1]) def reload_auto(self): """Load a new image with auto-orientation.""" self.get_img() try: orient = GExiv2.Metadata(self.fname)['Exif.Image.Orientation'] self.orient_dict[orient]() except: self.load_img() def reload_nonauto(self): """Load a new image without auto-orientation.""" self.get_img() self.load_img() def load_img_fit(self): """Load the image to fit the window.""" self.scene.clear() self.scene.addPixmap(self.pixmap) self.scene.setSceneRect(0, 0, self.pixmap.width(), self.pixmap.height()) self.img_view.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio) def load_img_1to1(self): """Load the image at its original size.""" self.scene.clear() self.img_view.resetTransform() self.scene.addPixmap(self.pixmap) self.scene.setSceneRect(0, 0, self.pixmap.width(), self.pixmap.height()) pixitem = QGraphicsPixmapItem(self.pixmap) self.img_view.centerOn(pixitem) def go_next_img(self): self.img_index = self.img_index + 1 if self.img_index < self.last_file else 0 self.fname = self.filelist[self.img_index] self.reload_img() def go_prev_img(self): self.img_index = self.img_index - 1 if self.img_index else self.last_file self.fname = self.filelist[self.img_index] self.reload_img() def zoom_default(self): """Toggle best fit / original size loading.""" if self.fit_win_act.isChecked(): self.load_img = self.load_img_fit self.create_dict() self.load_img() else: self.load_img = self.load_img_1to1 self.create_dict() self.load_img() def img_rotate(self, angle): self.pixmap = self.pixmap.transformed(QTransform().rotate(angle)) self.load_img() def img_flip(self, x, y): self.pixmap = self.pixmap.transformed(QTransform().scale(x, y)) self.load_img() def img_rotate_fliph(self): self.img_rotate(90) self.img_flip(-1, 1) def img_rotate_flipv(self): self.img_rotate(90) self.img_flip(1, -1) def resize_img(self): dialog = editimage.ResizeDialog(self, self.pixmap.width(), self.pixmap.height()) if dialog.exec_() == QDialog.Accepted: width = dialog.get_width.value() height = dialog.get_height.value() self.pixmap = self.pixmap.scaled(width, height, Qt.IgnoreAspectRatio, Qt.SmoothTransformation) self.save_img() def crop_img(self): self.img_view.setup_crop(self.pixmap.width(), self.pixmap.height()) dialog = editimage.CropDialog(self, self.pixmap.width(), self.pixmap.height()) if dialog.exec_() == QDialog.Accepted: coords = self.img_view.get_coords() self.pixmap = self.pixmap.copy(*coords) self.load_img() self.img_view.rband.hide() def toggle_fs(self): if self.fulls_act.isChecked(): self.showFullScreen() else: self.showNormal() def toggle_slideshow(self): if self.ss_act.isChecked(): self.showFullScreen() self.start_ss() else: self.toggle_fs() self.timer.stop() self.ss_timer.stop() def start_ss(self): self.timer = QTimer() self.timer.timeout.connect(self.update_img) self.timer.start(self.slide_delay * 1000) self.ss_timer = QTimer() self.ss_timer.timeout.connect(self.update_img) self.ss_timer.start(60000) def update_img(self): if self.slides_next: self.go_next_img() else: self.fname = random.choice(self.filelist) self.reload_img() def set_slide_type(self): self.slides_next = self.ss_next_act.isChecked() def save_img(self): fname = QFileDialog.getSaveFileName(self, 'Save your image', self.fname)[0] if fname: if fname.lower().endswith(self.write_list): keep_exif = QMessageBox.question(self, 'Save exif data', 'Do you want to save the picture metadata?', QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) if keep_exif == QMessageBox.Yes: self.pixmap.save(fname, None, self.quality) exif = GExiv2.Metadata(self.fname) if exif: saved_exif = GExiv2.Metadata(fname) for tag in exif.get_exif_tags(): saved_exif[tag] = exif[tag] saved_exif.set_orientation(GExiv2.Orientation.NORMAL) saved_exif.save_file() else: QMessageBox.information(self, 'Error', 'Cannot save {} images.'.format(fname.rsplit('.', 1)[1])) def print_img(self): dialog = QPrintDialog(self.printer, self) if dialog.exec_(): painter = QPainter(self.printer) rect = painter.viewport() if self.pixmap.width() > self.pixmap.height(): self.pixmap = self.pixmap.transformed(QTransform().rotate(90)) size = self.pixmap.size() size.scale(rect.size(), Qt.KeepAspectRatio) painter.setViewport(rect.x(), rect.y(), size.width(), size.height()) painter.setWindow(self.pixmap.rect()) painter.drawPixmap(0, 0, self.pixmap) def resizeEvent(self, event=None): if self.fit_win_act.isChecked(): try: self.load_img() except: pass def get_props(self): """Get the properties of the current image.""" image = QImage(self.fname) preferences.PropsDialog(self, self.fname.rsplit('/', 1)[1], image.width(), image.height()) def help_page(self): preferences.HelpDialog(self) def about_cm(self): about_message = 'Version: 0.3.9\nAuthor: David Whitlock\nLicense: GPLv3' QMessageBox.about(self, 'About Cheesemaker', about_message)
class Overview(QGraphicsView): """Show an overview of data, such as hypnogram and data in memory. Attributes ---------- parent : instance of QMainWindow the main window. config : ConfigChannels preferences for this widget minimum : int or float start time of the recording, from the absolute time of start_time in s maximum : int or float length of the recordings in s start_time : datetime absolute start time of the recording scene : instance of QGraphicsScene to keep track of the objects idx_current : QGraphicsRectItem instance of the current time window idx_markers : list of QGraphicsRectItem list of markers in the dataset idx_annot : list of QGraphicsRectItem list of user-made annotations """ def __init__(self, parent): super().__init__() self.parent = parent self.config = ConfigOverview(self.update_settings) self.minimum = None self.maximum = None self.start_time = None # datetime, absolute start time self.scene = None self.idx_current = None self.idx_markers = [] self.idx_annot = [] self.setMinimumHeight(TOTAL_HEIGHT + 30) def update(self): """Read full duration and update maximum.""" if self.parent.info.dataset is not None: # read from the dataset, if available header = self.parent.info.dataset.header maximum = header['n_samples'] / header['s_freq'] # in s self.minimum = 0 self.maximum = maximum self.start_time = self.parent.info.dataset.header['start_time'] elif self.parent.notes.annot is not None: # read from annotations annot = self.parent.notes.annot self.minimum = annot.first_second self.maximum = annot.last_second self.start_time = annot.start_time # make it time-zone unaware self.start_time = self.start_time.replace(tzinfo=None) self.parent.value('window_start', 0) # the only value that is reset self.display() def display(self): """Updates the widgets, especially based on length of recordings.""" lg.debug('GraphicsScene is between {}s and {}s'.format(self.minimum, self.maximum)) x_scale = 1 / self.parent.value('overview_scale') lg.debug('Set scene x-scaling to {}'.format(x_scale)) self.scale(1 / self.transform().m11(), 1) # reset to 1 self.scale(x_scale, 1) self.scene = QGraphicsScene(self.minimum, 0, self.maximum, TOTAL_HEIGHT) self.setScene(self.scene) # reset annotations self.idx_markers = [] self.idx_annot = [] self.display_current() for name, pos in BARS.items(): item = QGraphicsRectItem(self.minimum, pos['pos0'], self.maximum, pos['pos1']) item.setToolTip(pos['tip']) self.scene.addItem(item) self.add_timestamps() def add_timestamps(self): """Add timestamps at the bottom of the overview.""" transform, _ = self.transform().inverted() stamps = _make_timestamps(self.start_time, self.minimum, self.maximum, self.parent.value('timestamp_steps')) for stamp, xpos in zip(*stamps): text = self.scene.addSimpleText(stamp) text.setFlag(QGraphicsItem.ItemIgnoresTransformations) # set xpos and adjust for text width text_width = text.boundingRect().width() * transform.m11() text.setPos(xpos - text_width / 2, TIME_HEIGHT) def update_settings(self): """After changing the settings, we need to recreate the whole image.""" self.display() self.display_markers() if self.parent.notes.annot is not None: self.parent.notes.display_notes() def update_position(self, new_position=None): """Update the cursor position and much more. Parameters ---------- new_position : int or float new position in s, for plotting etc. Notes ----- This is a central function. It updates the cursor, then updates the traces, the scores, and the power spectrum. In other words, this function is responsible for keep track of the changes every time the start time of the window changes. """ if new_position is not None: lg.debug('Updating position to {}'.format(new_position)) self.parent.value('window_start', new_position) self.idx_current.setPos(new_position, 0) current_time = (self.start_time + timedelta(seconds=new_position)) msg = 'Current time: ' + current_time.strftime('%H:%M:%S') self.parent.statusBar().showMessage(msg) else: lg.debug('Updating position at {}' ''.format(self.parent.value('window_start'))) if self.parent.info.dataset is not None: self.parent.traces.read_data() if self.parent.traces.data is not None: self.parent.traces.display() self.parent.spectrum.display_window() if self.parent.notes.annot is not None: self.parent.notes.set_stage_index() self.display_current() def display_current(self): """Create a rectangle showing the current window.""" if self.idx_current in self.scene.items(): self.scene.removeItem(self.idx_current) item = QGraphicsRectItem(0, CURR['pos0'], self.parent.value('window_length'), CURR['pos1']) # it's necessary to create rect first, and then move it item.setPos(self.parent.value('window_start'), 0) item.setPen(QPen(Qt.lightGray)) item.setBrush(QBrush(Qt.lightGray)) item.setZValue(-10) self.scene.addItem(item) self.idx_current = item def display_markers(self): """Mark all the markers, from the dataset. This function should be called only when we load the dataset or when we change the settings. """ for rect in self.idx_markers: self.scene.removeItem(rect) self.idx_markers = [] markers = [] if self.parent.info.markers is not None: if self.parent.value('marker_show'): markers = self.parent.info.markers for mrk in markers: rect = QGraphicsRectItem(mrk['start'], BARS['markers']['pos0'], mrk['end'] - mrk['start'], BARS['markers']['pos1']) self.scene.addItem(rect) color = self.parent.value('marker_color') rect.setPen(QPen(QColor(color))) rect.setBrush(QBrush(QColor(color))) rect.setZValue(-5) self.idx_markers.append(rect) def display_annotations(self): """Mark all the bookmarks/events, from annotations. This function is similar to display_markers, but they are called at different stages (f.e. when loading annotations file), so we keep them separate """ for rect in self.idx_annot: self.scene.removeItem(rect) self.idx_annot = [] if self.parent.notes.annot is None: return bookmarks = [] events = [] if self.parent.value('annot_show'): bookmarks = self.parent.notes.annot.get_bookmarks() events = self.parent.notes.get_selected_events() annotations = bookmarks + events for annot in annotations: rect = QGraphicsRectItem(annot['start'], BARS['annot']['pos0'], annot['end'] - annot['start'], BARS['annot']['pos1']) self.scene.addItem(rect) if annot in bookmarks: color = self.parent.value('annot_bookmark_color') if annot in events: color = convert_name_to_color(annot['name']) rect.setPen(QPen(QColor(color), LINE_WIDTH)) rect.setBrush(QBrush(QColor(color))) rect.setZValue(-5) self.idx_annot.append(rect) for epoch in self.parent.notes.annot.epochs: self.mark_stages(epoch['start'], epoch['end'] - epoch['start'], epoch['stage']) def mark_stages(self, start_time, length, stage_name): """Mark stages, only add the new ones. Parameters ---------- start_time : int start time in s of the epoch being scored. length : int duration in s of the epoch being scored. stage_name : str one of the stages defined in global stages. """ y_pos = BARS['stage']['pos0'] # the -1 is really important, otherwise we stay on the edge of the rect old_score = self.scene.itemAt(start_time + length / 2, y_pos + STAGES[stage_name]['pos0'] + STAGES[stage_name]['pos1'] - 1, self.transform()) # check we are not removing the black border if old_score is not None and old_score.pen() == NoPen: lg.debug('Removing old score at {}'.format(start_time)) self.scene.removeItem(old_score) self.idx_annot.remove(old_score) rect = QGraphicsRectItem(start_time, y_pos + STAGES[stage_name]['pos0'], length, STAGES[stage_name]['pos1']) rect.setPen(NoPen) rect.setBrush(STAGES[stage_name]['color']) self.scene.addItem(rect) self.idx_annot.append(rect) def mousePressEvent(self, event): """Jump to window when user clicks on overview. Parameters ---------- event : instance of QtCore.QEvent it contains the position that was clicked. """ if self.scene is not None: x_in_scene = self.mapToScene(event.pos()).x() window_length = self.parent.value('window_length') window_start = int(floor(x_in_scene / window_length) * window_length) self.update_position(window_start) def reset(self): """Reset the widget, and clear the scene.""" self.minimum = None self.maximum = None self.start_time = None # datetime, absolute start time self.idx_current = None self.idx_markers = [] self.idx_annot = [] if self.scene is not None: self.scene.clear() self.scene = None
class RunTimeGui(QMainWindow): activeStateChanged = pyqtSignal(int) runningStateChanged = pyqtSignal(int) loadFromRoot = pyqtSignal(int) def __init__(self, parent=None): super(QMainWindow, self).__init__() self.setWindowTitle("VisualStates RunTime GUI") self.rootState = None # create status bar self.statusBar() self.createTreeView() self.createStateCanvas() self.setGeometry(0, 0, 800, 600) self.show() self.states = {} self.transitions = {} self.activeState = None self.activeStateChanged.connect(self.activeStateChangedHandle) self.runningStateChanged.connect(self.runningStateChangedHandle) self.loadFromRoot.connect(self.loadFromRootHandle) self.memory = None self.ipcThread = None def createTreeView(self): dockWidget = QDockWidget() dockWidget.setAllowedAreas(Qt.LeftDockWidgetArea) dockWidget.setFeatures(QDockWidget.NoDockWidgetFeatures) dockWidget.setTitleBarWidget(QWidget()) self.treeView = QTreeView() self.treeView.clicked.connect(self.treeItemClicked) self.treeModel = TreeModel() self.treeView.setModel(self.treeModel) self.logo = QLabel() logoPixmap = QPixmap(CMAKE_INSTALL_PREFIX + '/share/jderobot/resources/jderobot.png') self.logo.setPixmap(logoPixmap) self.upButton = QPushButton() self.upButton.setText('Up') self.upButton.clicked.connect(self.upButtonClicked) leftContainer = QWidget() leftLayout = QVBoxLayout() leftLayout.addWidget(self.treeView) leftLayout.addWidget(self.upButton) leftLayout.addWidget(self.logo) leftContainer.setLayout(leftLayout) dockWidget.setWidget(leftContainer) self.addDockWidget(Qt.LeftDockWidgetArea, dockWidget) def createStateCanvas(self): self.stateCanvas = QGraphicsView() self.scene = QGraphicsScene() self.scene.setSceneRect(0, 0, 2000, 2000) self.setCentralWidget(self.stateCanvas) self.stateCanvas.setScene(self.scene) self.stateCanvas.setRenderHint(QPainter.Antialiasing) def addState(self, id, name, initial, x, y, parentId): if parentId is not None: self.states[id] = State(id, name, initial, self.states[parentId]) self.states[parentId].addChild(self.states[id]) parentItem = self.treeModel.getByDataId(parentId) # print('parent:' + str(parentItem)) else: self.states[id] = State(id, name, initial, None) if id == 0: self.rootState = self.states[id] self.states[id].setPos(x, y) def addTransition(self, id, name, originId, destinationId, x, y): self.transitions[id] = Transition(id, name, self.states[originId], self.states[destinationId]) self.transitions[id].setPos(x, y) def emitRunningStateById(self, id): # print('emit running state:' + str(id)) self.runningStateChanged.emit(id) def runningStateChangedHandle(self, id): # print('running state:' + str(id)) if id not in self.states: return runningState = self.states[id] parentId = None if runningState.parent is not None: for child in runningState.parent.getChildren(): child.setRunning(False) runningState.setRunning(True) parentId = runningState.parent.id self.treeModel.setAllBackgroundByParentId(Qt.white, parentId) self.treeModel.setBackgroundById(runningState.id, Qt.green) def emitActiveStateById(self, id): self.activeStateChanged.emit(id) def activeStateChangedHandle(self, id): if self.activeState is not None: for child in self.activeState.getChildren(): child.resetGraphicsItem() for tran in child.getOriginTransitions(): tran.resetGraphicsItem() self.activeState = self.states[id] # print('set active state:' + str(id)) self.scene.clear() for childState in self.activeState.getChildren(): # print('add child to scene:' + str(childState.id)) qitem = childState.getGraphicsItem() qitem.setAcceptHoverEvents(False) qitem.setFlag(QGraphicsItem.ItemIsMovable, False) qitem.doubleClicked.connect(self.stateDoubleClicked) self.setAcceptDrops(False) self.scene.addItem(qitem) for tran in childState.getOriginTransitions(): # print('add transition:' + str(tran.id)) qitem = tran.getGraphicsItem() qitem.disableInteraction() self.scene.addItem(qitem) def emitLoadFromRoot(self): self.loadFromRoot.emit(0) def loadFromRootHandle(self, id): self.treeModel.loadFromRoot(self.states[id]) def stateDoubleClicked(self, stateItem): if len(stateItem.stateData.getChildren()) > 0: self.emitActiveStateById(stateItem.stateData.id) def upButtonClicked(self): if self.activeState is not None: if self.activeState.parent is not None: self.emitActiveStateById(self.activeState.parent.id) def getStateById(self,state, id): if state.id == id: return state else: result = None for child in state.getChildren(): result = self.getStateById(child, id) if result is not None: return result return result def treeItemClicked(self, index): # print('clicked item.id:' + str(index.internalPointer().id)) pass def getStateList(self, state, stateList): if len(state.getChildren()) > 0: stateList.append(state) for s in state.getChildren(): self.getStateList(s, stateList) def loopIPC(self): while True: msg = self.getIPCMessage() if msg is not None: # print('msg received:' + msg) methodName = msg.split(' ')[0] id = int(msg.split(' ')[1]) if methodName == 'emitRunningStateById': self.emitRunningStateById(id) else: print('unknown method name') time.sleep(1.0/1000) def activateIPC(self): try: self.memory = sysv_ipc.SharedMemory(123456, sysv_ipc.IPC_CREX) except: # if memory exists just open shared memory self.memory = sysv_ipc.SharedMemory(123456) self.ipcThread = Thread(target=self.loopIPC) self.ipcThread.start() def getIPCMessage(self): if self.memory is not None: data = self.memory.read().decode() if data[0] != '0': self.memory.write('0'.encode()) i = data.find('\0') if i != -1: data = data[:i] return data return None
class MainWindow(QMainWindow): def __init__(self, parent): QMainWindow.__init__(self) self.printer = QPrinter() self.load_img = self.load_img_fit self.reload_img = self.reload_auto self.open_new = parent.open_win self.scene = QGraphicsScene() self.img_view = ImageView(self) self.img_view.setScene(self.scene) self.setCentralWidget(self.img_view) self.create_actions() self.create_menu() self.create_dict() self.create_toolbar() self.slides_next = True self.setContextMenuPolicy(Qt.CustomContextMenu) self.customContextMenuRequested.connect(self.showMenu) self.read_prefs() self.read_list = parent.read_list self.write_list = parent.write_list self.pics_dir = os.path.expanduser('~/Pictures') or QDir.currentPath() self.resize(700, 500) def create_actions(self): self.open_act = QAction('&Open', self, shortcut='Ctrl+O') self.open_act.triggered.connect(self.open) self.open_new_act = QAction('Open new window', self, shortcut='Ctrl+Shift+O') self.open_new_act.triggered.connect(partial(self.open, True)) self.reload_act = QAction('&Reload image', self, shortcut='Ctrl+R') self.reload_act.triggered.connect(self.reload_img) self.print_act = QAction('&Print', self, shortcut='Ctrl+P') self.print_act.triggered.connect(self.print_img) self.save_act = QAction('&Save image', self, shortcut='Ctrl+S') self.save_act.triggered.connect(self.save_img_as) self.close_act = QAction('Close window', self, shortcut='Ctrl+W') self.close_act.triggered.connect(self.close) self.exit_act = QAction('E&xit', self, shortcut='Ctrl+Q') self.exit_act.triggered.connect(self.exit) self.fulls_act = QAction('Fullscreen', self, shortcut='F11', checkable=True) self.fulls_act.triggered.connect(self.toggle_fs) self.ss_act = QAction('Slideshow', self, shortcut='F5', checkable=True) self.ss_act.triggered.connect(self.toggle_slideshow) self.ss_next_act = QAction('Next / Random image', self, checkable=True) self.ss_next_act.triggered.connect(self.set_slide_type) self.ss_next_act.setChecked(True) self.next_act = QAction('Next image', self, shortcut='Right') self.next_act.triggered.connect(self.go_next_img) self.prev_act = QAction('Previous image', self, shortcut='Left') self.prev_act.triggered.connect(self.go_prev_img) self.rotleft_act = QAction('Rotate left', self, shortcut='Ctrl+Left') self.rotleft_act.triggered.connect(partial(self.img_rotate, 270)) self.rotright_act = QAction('Rotate right', self, shortcut='Ctrl+Right') self.rotright_act.triggered.connect(partial(self.img_rotate, 90)) self.fliph_act = QAction('Flip image horizontally', self, shortcut='Ctrl+H') self.fliph_act.triggered.connect(partial(self.img_flip, -1, 1)) self.flipv_act = QAction('Flip image vertically', self, shortcut='Ctrl+V') self.flipv_act.triggered.connect(partial(self.img_flip, 1, -1)) self.resize_act = QAction('Resize image', self, triggered=self.resize_img) self.crop_act = QAction('Crop image', self, triggered=self.crop_img) self.zin_act = QAction('Zoom &In', self, shortcut='Up') self.zin_act.triggered.connect(partial(self.img_view.zoom, 1.1)) self.zout_act = QAction('Zoom &Out', self, shortcut='Down') self.zout_act.triggered.connect(partial(self.img_view.zoom, 1 / 1.1)) self.fit_win_act = QAction('Best &fit', self, checkable=True, shortcut='F', triggered=self.zoom_default) self.fit_win_act.setChecked(True) self.prefs_act = QAction('Preferences', self, triggered=self.set_prefs) self.props_act = QAction('Properties', self, triggered=self.get_props) self.help_act = QAction('&Help', self, shortcut='F1', triggered=self.help_page) self.about_act = QAction('&About', self, triggered=self.about_cm) self.aboutQt_act = QAction('About &Qt', self, triggered=qApp.aboutQt) def create_menu(self): self.popup = QMenu(self) main_acts = [ self.open_act, self.open_new_act, self.reload_act, self.print_act, self.save_act ] edit_acts1 = [ self.rotleft_act, self.rotright_act, self.fliph_act, self.flipv_act ] edit_acts2 = [self.resize_act, self.crop_act] view_acts = [ self.next_act, self.prev_act, self.zin_act, self.zout_act, self.fit_win_act, self.fulls_act, self.ss_act, self.ss_next_act ] help_acts = [self.help_act, self.about_act, self.aboutQt_act] end_acts = [ self.prefs_act, self.props_act, self.close_act, self.exit_act ] for act in main_acts: self.popup.addAction(act) edit_menu = QMenu(self.popup) edit_menu.setTitle('&Edit') for act in edit_acts1: edit_menu.addAction(act) edit_menu.addSeparator() for act in edit_acts2: edit_menu.addAction(act) self.popup.addMenu(edit_menu) view_menu = QMenu(self.popup) view_menu.setTitle('&View') for act in view_acts: view_menu.addAction(act) self.popup.addMenu(view_menu) help_menu = QMenu(self.popup) help_menu.setTitle('&Help') for act in help_acts: help_menu.addAction(act) self.popup.addMenu(help_menu) for act in end_acts: self.popup.addAction(act) self.action_list = main_acts + edit_acts1 + edit_acts2 + view_acts + help_acts + end_acts for act in self.action_list: self.addAction(act) def showMenu(self, pos): self.popup.popup(self.mapToGlobal(pos)) def create_dict(self): """Create a dictionary to handle auto-orientation.""" self.orient_dict = { None: self.load_img, '1': self.load_img, '2': partial(self.img_flip, -1, 1), '3': partial(self.img_rotate, 180), '4': partial(self.img_flip, -1, 1), '5': self.img_rotate_fliph, '6': partial(self.img_rotate, 90), '7': self.img_rotate_flipv, '8': partial(self.img_rotate, 270) } def create_toolbar(self): script_dir = os.path.dirname(os.path.realpath(__file__)) def icon(icon_name): return QIcon(os.path.join(script_dir, "assets", icon_name)) def add_action(description, icon_file, function): action = QAction(icon(icon_file), description, self) action.triggered.connect(function) self.toolbar.addAction(action) self.toolbar = self.addToolBar("File") add_action("save", "save.png", self.save_img) add_action("crop", "crop.png", self.crop_img) add_action("resize", "resize.png", self.resize_img) add_action("save important", "star.png", lambda: self.save_img(rating=100)) add_action("save non important", "hollow_star.png", lambda: self.save_img(rating=0)) def read_prefs(self): """Parse the preferences from the config file, or set default values.""" try: conf = preferences.Config() values = conf.read_config() self.auto_orient = values[0] self.slide_delay = values[1] self.quality = values[2] except: self.auto_orient = True self.slide_delay = 5 self.quality = 90 self.reload_img = self.reload_auto if self.auto_orient else self.reload_nonauto def set_prefs(self): """Write preferences to the config file.""" dialog = preferences.PrefsDialog(self) if dialog.exec_() == QDialog.Accepted: self.auto_orient = dialog.auto_orient self.slide_delay = dialog.delay_spinb.value() self.quality = dialog.qual_spinb.value() conf = preferences.Config() conf.write_config(self.auto_orient, self.slide_delay, self.quality) self.reload_img = self.reload_auto if self.auto_orient else self.reload_nonauto def open(self, new_win=False): fname = QFileDialog.getOpenFileName(self, 'Open File', self.pics_dir)[0] if fname: if fname.lower().endswith(self.read_list): if new_win: self.open_new(fname) else: self.open_img(fname) else: QMessageBox.information( self, 'Error', 'Cannot load {} images.'.format(fname.rsplit('.', 1)[1])) def open_img(self, fname): self.fname = fname self.reload_img() dirname = os.path.dirname(self.fname) self.set_img_list(dirname) self.img_index = self.filelist.index(self.fname) def set_img_list(self, dirname): """Create a list of readable images from the current directory.""" filelist = os.listdir(dirname) self.filelist = [ os.path.join(dirname, fname) for fname in filelist if fname.lower().endswith(self.read_list) ] self.filelist.sort() self.last_file = len(self.filelist) - 1 def set_title(self): file_name = self.fname.rsplit('/', 1)[1] size = " [%d x %d]" % (self.pixmap.width(), self.pixmap.height()) self.setWindowTitle(file_name + size) def get_img(self): """Get image from fname and create pixmap.""" image = QImage(self.fname) self.pixmap = QPixmap.fromImage(image) def reload_auto(self): """Load a new image with auto-orientation.""" self.get_img() try: orient = GExiv2.Metadata(self.fname)['Exif.Image.Orientation'] self.orient_dict[orient]() except: self.load_img() def reload_nonauto(self): """Load a new image without auto-orientation.""" self.get_img() self.load_img() def load_img_fit(self): """Load the image to fit the window.""" self.scene.clear() self.scene.addPixmap(self.pixmap) self.scene.setSceneRect(0, 0, self.pixmap.width(), self.pixmap.height()) self.img_view.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio) self.set_title() def load_img_1to1(self): """Load the image at its original size.""" self.scene.clear() self.img_view.resetTransform() self.scene.addPixmap(self.pixmap) self.scene.setSceneRect(0, 0, self.pixmap.width(), self.pixmap.height()) pixitem = QGraphicsPixmapItem(self.pixmap) self.img_view.centerOn(pixitem) self.set_title() def go_next_img(self): self.img_index = self.img_index + 1 if self.img_index < self.last_file else 0 self.fname = self.filelist[self.img_index] self.reload_img() def go_prev_img(self): self.img_index = self.img_index - 1 if self.img_index else self.last_file self.fname = self.filelist[self.img_index] self.reload_img() def zoom_default(self): """Toggle best fit / original size loading.""" if self.fit_win_act.isChecked(): self.load_img = self.load_img_fit self.create_dict() self.load_img() else: self.load_img = self.load_img_1to1 self.create_dict() self.load_img() def img_rotate(self, angle): self.pixmap = self.pixmap.transformed(QTransform().rotate(angle)) self.load_img() def img_flip(self, x, y): self.pixmap = self.pixmap.transformed(QTransform().scale(x, y)) self.load_img() def img_rotate_fliph(self): self.img_rotate(90) self.img_flip(-1, 1) def img_rotate_flipv(self): self.img_rotate(90) self.img_flip(1, -1) def resize_img(self): dialog = editimage.ResizeDialog(self, self.pixmap.width(), self.pixmap.height()) if dialog.exec_() == QDialog.Accepted: width = dialog.get_width.value() height = dialog.get_height.value() self.pixmap = self.pixmap.scaled(width, height, Qt.IgnoreAspectRatio, Qt.SmoothTransformation) self.load_img() def crop_img(self): def callback(coords): self.pixmap = self.pixmap.copy(*coords) self.load_img() self.img_view.crop(callback) def toggle_fs(self): if self.fulls_act.isChecked(): self.showFullScreen() else: self.showNormal() def toggle_slideshow(self): if self.ss_act.isChecked(): self.showFullScreen() self.start_ss() else: self.toggle_fs() self.timer.stop() self.ss_timer.stop() def start_ss(self): self.timer = QTimer() self.timer.timeout.connect(self.update_img) self.timer.start(self.slide_delay * 1000) self.ss_timer = QTimer() self.ss_timer.timeout.connect(self.update_img) self.ss_timer.start(60000) def update_img(self): if self.slides_next: self.go_next_img() else: self.fname = random.choice(self.filelist) self.reload_img() def set_slide_type(self): self.slides_next = self.ss_next_act.isChecked() def save_img_as(self): fname = QFileDialog.getSaveFileName(self, 'Save your image', self.fname)[0] if fname: if fname.lower().endswith(self.write_list): keep_exif = QMessageBox.question( self, 'Save exif data', 'Do you want to save the picture metadata?', QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) if keep_exif == QMessageBox.Yes: exif = GExiv2.Metadata(self.fname) self.pixmap.save(fname, None, self.quality) if exif: saved_exif = GExiv2.Metadata(fname) for tag in exif.get_exif_tags(): saved_exif[tag] = exif[tag] saved_exif.set_orientation(GExiv2.Orientation.NORMAL) saved_exif.save_file() else: QMessageBox.information( self, 'Error', 'Cannot save {} images.'.format(fname.rsplit('.', 1)[1])) def save_img(self, rating=None): exif = GExiv2.Metadata(self.fname) self.pixmap.save(self.fname, None, self.quality) if rating is not None: exif["Exif.Image.Rating"] = str(rating) if exif: exif.save_file() def print_img(self): dialog = QPrintDialog(self.printer, self) if dialog.exec_(): painter = QPainter(self.printer) rect = painter.viewport() if self.pixmap.width() > self.pixmap.height(): self.pixmap = self.pixmap.transformed(QTransform().rotate(90)) size = self.pixmap.size() size.scale(rect.size(), Qt.KeepAspectRatio) painter.setViewport(rect.x(), rect.y(), size.width(), size.height()) painter.setWindow(self.pixmap.rect()) painter.drawPixmap(0, 0, self.pixmap) def resizeEvent(self, event=None): if self.fit_win_act.isChecked(): try: self.load_img() except: pass def get_props(self): """Get the properties of the current image.""" image = QImage(self.fname) preferences.PropsDialog(self, self.fname.rsplit('/', 1)[1], image.width(), image.height()) def help_page(self): preferences.HelpDialog(self) def about_cm(self): about_message = 'Version: 0.3.9\nAuthor: David Whitlock\nLicense: GPLv3' QMessageBox.about(self, 'About Cheesemaker', about_message) def exit(self): QCoreApplication.quit()
class qfi_ALT (QGraphicsView): viewUpdate = pyqtSignal() def __init__(self,winParent): QGraphicsView.__init__(self) self.winParent=winParent self.viewUpdate.connect(self.updateView) self.m_altitude = 0 self.m_pressure = 28 self.m_originalHeight = 240 self.m_originalWidth = 240 self.m_originalAltCtr = QPointF(120,120) self.m_face1Z = -50 self.m_face2Z = -40 self.m_face3Z = -30 self.m_hand1Z = -20 self.m_hand2Z = -10 self.m_caseZ = 10 self.setStyleSheet("background: transparent; border: none") self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setInteractive(False) self.setEnabled(False) self.m_scene = QGraphicsScene(self) self.setScene(self.m_scene) self.init() def init (self): self.m_scaleX = self.width() / self.m_originalWidth self.m_scaleY = self.height() / self.m_originalHeight self.m_itemFace_1 = QGraphicsSvgItem(":/qfi/images/alt/alt_face_1.svg") self.m_itemFace_1.setCacheMode (QGraphicsItem.NoCache) self.m_itemFace_1.setZValue( self.m_face1Z ) self.m_itemFace_1.setTransform( QTransform.fromScale( self.m_scaleX, self.m_scaleY ), True ) self.m_itemFace_1.setTransformOriginPoint( self.m_originalAltCtr ) self.m_scene.addItem (self.m_itemFace_1) self.m_itemFace_2 = QGraphicsSvgItem(":/qfi/images/alt/alt_face_2.svg") self.m_itemFace_2.setCacheMode (QGraphicsItem.NoCache) self.m_itemFace_2.setZValue( self.m_face2Z ) self.m_itemFace_2.setTransform( QTransform.fromScale( self.m_scaleX, self.m_scaleY ), True ) self.m_itemFace_2.setTransformOriginPoint( self.m_originalAltCtr ) self.m_scene.addItem (self.m_itemFace_2) self.m_itemFace_3 = QGraphicsSvgItem(":/qfi/images/alt/alt_face_3.svg") self.m_itemFace_3.setCacheMode (QGraphicsItem.NoCache) self.m_itemFace_3.setZValue( self.m_face3Z ) self.m_itemFace_3.setTransform( QTransform.fromScale( self.m_scaleX, self.m_scaleY ), True ) self.m_itemFace_3.setTransformOriginPoint( self.m_originalAltCtr ) self.m_scene.addItem (self.m_itemFace_3) self.m_itemHand_1 = QGraphicsSvgItem(":/qfi/images/alt/alt_hand_1.svg") self.m_itemHand_1.setCacheMode (QGraphicsItem.NoCache) self.m_itemHand_1.setZValue( self.m_hand1Z ) self.m_itemHand_1.setTransform( QTransform.fromScale( self.m_scaleX, self.m_scaleY ), True ) self.m_itemHand_1.setTransformOriginPoint( self.m_originalAltCtr ) self.m_scene.addItem (self.m_itemHand_1) self.m_itemHand_2 = QGraphicsSvgItem(":/qfi/images/alt/alt_hand_2.svg") self.m_itemHand_2.setCacheMode (QGraphicsItem.NoCache) self.m_itemHand_2.setZValue( self.m_hand2Z ) self.m_itemHand_2.setTransform( QTransform.fromScale( self.m_scaleX, self.m_scaleY ), True ) self.m_itemHand_2.setTransformOriginPoint( self.m_originalAltCtr ) self.m_scene.addItem (self.m_itemHand_2) self.m_itemCase = QGraphicsSvgItem(":/qfi/images/alt/alt_case.svg") self.m_itemCase.setCacheMode (QGraphicsItem.NoCache) self.m_itemCase.setZValue( self.m_caseZ ) self.m_itemCase.setTransform( QTransform.fromScale( self.m_scaleX, self.m_scaleY ), True ) self.m_itemCase.setTransformOriginPoint( self.m_originalAltCtr ) self.m_scene.addItem (self.m_itemCase) self.centerOn (self.width()/2, self.height()/2) self.updateView() def reinit(self): if (self.m_scene): self.m_scene.clear() self.init() def update(self): self.updateView() def setAltitude (self, altitude): self.m_altitude = altitude def setPressure (self, pressure): self.m_pressure = pressure if (self.m_pressure < 28): self.m_pressure = 28 if (self.m_pressure > 31.5): self.m_pressure = 31.5 def resizeEvent (self, event): QGraphicsView.resizeEvent (self,event) self.reinit() def reset (self): self.m_itemFace_1 = None self.m_itemFace_2 = None self.m_itemFace_3 = None self.m_itemHand_1 = None self.m_itemHand_2 = None self.m_itemCase = None self.m_altitude = 0.0 self.m_pressure = 28.0 def updateView(self): altitude = math.ceil(self.m_altitude + 0.5) angleH1 = self.m_altitude * 0.036 angleH2 = ( altitude % 1000 ) * 0.36 angleF1 = (self.m_pressure - 28.0 ) * 100.0 angleF3 = self.m_altitude * 0.0036 self.m_itemHand_1.setRotation(angleH1) self.m_itemHand_2.setRotation(angleH2) self.m_itemFace_1.setRotation(- angleF1) self.m_itemFace_3.setRotation(angleF3) self.m_scene.update()
class MapCanvas(QGraphicsView): """Map Widget for Everquest Map Files.""" def __init__(self): self._data = None # UI Init super().__init__() self.setObjectName('MapCanvas') self.setAutoFillBackground(True) self.setAttribute(Qt.WA_StyledBackground) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setContentsMargins(0, 0, 0, 0) self.setTransformationAnchor(self.AnchorViewCenter) self.setFocusPolicy(Qt.StrongFocus) self.setRenderHint(QPainter.Antialiasing) self._scene = QGraphicsScene() self.setScene(self._scene) self._scale = config.data['maps']['scale'] self._mouse_location = MouseLocation() def load_map(self, map_name): try: map_data = MapData(str(map_name)) except: traceback.print_exc() else: self._data = map_data self._scene.clear() self._z_index = 0 self._draw() rect = self._scene.sceneRect() rect.adjust(-self._data.geometry.width * 2, -self._data.geometry.height * 2, self._data.geometry.width * 2, self._data.geometry.height * 2) self.setSceneRect(rect) self.update() self.update_() self.centerOn(self._data.geometry.center_x, self._data.geometry.center_y) self._mouse_location = MouseLocation() self._scene.addItem(self._mouse_location) config.data['maps']['last_zone'] = self._data.zone config.save() def _draw(self): for z in self._data.keys(): self._scene.addItem(self._data[z]['paths']) for p in self._data[z]['poi']: self._scene.addItem(p.text) self._scene.addItem(self._data.grid) def update_(self, ratio=None): if not ratio: ratio = self._scale current_alpha = config.data['maps']['current_z_alpha'] / 100 other_alpha = config.data['maps']['other_z_alpha'] / 100 closest_alpha = config.data['maps']['closest_z_alpha'] / 100 # scene self.setTransform(QTransform()) # reset transform object self._scale = to_range(ratio, 0.0006, 5.0) config.data['maps']['scale'] = self._scale self.scale(self._scale, self._scale) # lines and points of interest current_z_level = self._data.geometry.z_groups[self._z_index] closest_z_levels = set() for x in [i for i in [self._z_index - 1, self._z_index + 1] if i > -1]: try: closest_z_levels.add(self._data.geometry.z_groups[x]) except: pass for z in self._data.keys(): alpha = current_alpha if config.data['maps']['use_z_layers']: if z == current_z_level: alpha = current_alpha elif z in closest_z_levels: alpha = closest_alpha else: alpha = other_alpha # lines bolded = 0.5 if config.data['maps']['use_z_layers'] else 0.0 for path in self._data[z]['paths'].childItems(): if z == current_z_level or not config.data['maps'][ 'use_z_layers']: pen = path.pen() pen.setWidth( max(config.data['maps']['line_width'] + bolded, (config.data['maps']['line_width'] + bolded) / self._scale)) path.setPen(pen) else: pen = path.pen() pen.setWidth( max(config.data['maps']['line_width'] - 0.8, (config.data['maps']['line_width'] - 0.8) / self._scale)) path.setPen(pen) self._data[z]['paths'].setOpacity(alpha) # points of interest for p in self._data[z]['poi']: p.update_(min(5, self.to_scale())) if not config.data['maps']['show_poi']: p.text.setOpacity(0) elif config.data['maps']['use_z_layers']: if z == current_z_level: p.text.setOpacity(current_alpha) else: p.text.setOpacity(other_alpha) else: p.text.setOpacity(current_alpha) # players for player in self._data.players.values(): player.update_(self.to_scale()) if config.data['maps']['use_z_layers']: if player.z_level == current_z_level: player.setOpacity(current_alpha) else: player.setOpacity(other_alpha) else: player.setOpacity(current_alpha) # waypoint if self._data.way_point: self._data.way_point.update_(self.to_scale()) if config.data['maps']['use_z_layers']: self._data.way_point.pixmap.setOpacity(current_alpha if ( self._data.way_point.location.z == current_z_level ) else other_alpha) player = self._data.players.get('__you__', None) if player and current_z_level in \ [self._data.way_point.location.z, player.z_level]: self._data.way_point.line.setOpacity(current_alpha) else: self._data.way_point.line.setOpacity(other_alpha) else: self._data.way_point.pixmap.setOpacity(current_alpha) # spawns for spawn in self._data.spawns: spawn.setScale(self.to_scale()) spawn.realign(self.to_scale()) if config.data['maps']['use_z_layers']: spawn.setOpacity(current_alpha if ( spawn.location.z == current_z_level) else other_alpha) else: spawn.setOpacity(current_alpha) # grid lines if config.data['maps']['show_grid']: pen = self._data.grid.pen() pen.setWidth( max(config.data['maps']['grid_line_width'], self.to_scale(config.data['maps']['grid_line_width']))) self._data.grid.setPen(pen) self._data.grid.setVisible(True) else: self._data.grid.setVisible(False) def to_scale(self, float_value=1.0): return float_value / self._scale def center(self): player = None if self._data: player = self._data.players.get('__you__', None) if config.data['maps']['auto_follow'] and player: self.centerOn(player.location.x, player.location.y) def add_player(self, name, timestamp, location): if name not in self._data.players.keys(): self._data.players[name] = Player(name=name, location=location, timestamp=timestamp) self._scene.addItem(self._data.players[name]) else: self._data.players[name].previous_location = self._data.players[ name].location self._data.players[name].location = location self._data.players[name].timestamp = timestamp self._data.players[name].z_level = self._data.get_closest_z_group( self._data.players[name].location.z) if name == '__you__' and config.data['maps']['use_z_layers']: self._z_index = self._data.geometry.z_groups.index( self._data.get_closest_z_group( self._data.players['__you__'].location.z)) self.update_() if self._data.way_point and name == '__you__': self._data.way_point.update_(self.to_scale(), location=location) if name == '__you__' and config.data['maps']['auto_follow']: self.center() def enterEvent(self, event): if config.data['maps']['show_mouse_location']: self._mouse_location.setVisible(True) QGraphicsView.enterEvent(self, event) def leaveEvent(self, event): self._mouse_location.setVisible(False) QGraphicsView.leaveEvent(self, event) def mouseMoveEvent(self, event): self._mouse_location.set_value(self.mapToScene(event.pos()), self._scale, self) QGraphicsView.mouseMoveEvent(self, event) def wheelEvent(self, event): # Scale based on scroll wheel direction movement = event.angleDelta().y() if self.dragMode() == self.NoDrag: if movement > 0: self.update_(self._scale + self._scale * 0.1) else: self.update_(self._scale - self._scale * 0.1) else: if self._data: if movement > 0: self._z_index = max(self._z_index - 1, 0) else: self._z_index = min(self._z_index + 1, len(self._data.geometry.z_groups) - 1) self.update_() # Update Mouse Location self._mouse_location.set_value(self.mapToScene(event.pos()), self._scale, self) def keyPressEvent(self, event): # Enable drag mode while control button is being held down if event.modifiers() == Qt.ControlModifier: self.setDragMode(self.ScrollHandDrag) QGraphicsView.keyPressEvent(self, event) def keyReleaseEvent(self, event): # Disable drag mode when control button released if event.key() == Qt.Key_Control: self.setDragMode(self.NoDrag) QGraphicsView.keyPressEvent(self, event) def resizeEvent(self, event): self.center() QGraphicsView.resizeEvent(self, event) def contextMenuEvent(self, event): # create menu pos = self.mapToScene(event.pos()) menu = QMenu(self) # remove from memory after usage menu.setAttribute(Qt.WA_DeleteOnClose) # remove from memory spawn_point_menu = menu.addMenu('Spawn Point') spawn_point_create = spawn_point_menu.addAction('Create on Cursor') spawn_point_delete = spawn_point_menu.addAction('Delete on Cursor') spawn_point_delete_all = spawn_point_menu.addAction('Delete All') way_point_menu = menu.addMenu('Way Point') way_point_create = way_point_menu.addAction('Create on Cursor') way_point_delete = way_point_menu.addAction('Clear') load_map = menu.addAction('Load Map') # execute action = menu.exec_(self.mapToGlobal(event.pos())) # parse response if action == spawn_point_create: spawn_time = text_time_to_seconds('6:40') dialog = QInputDialog(self) dialog.setWindowTitle('Create Spawn Point') dialog.setLabelText('Respawn Time (hh:mm:ss):') dialog.setTextValue('6:40') if dialog.exec_(): spawn_time = text_time_to_seconds(dialog.textValue()) dialog.deleteLater() spawn = SpawnPoint(location=MapPoint( x=pos.x(), y=pos.y(), z=self._data.geometry.z_groups[self._z_index]), length=spawn_time) self._scene.addItem(spawn) self._data.spawns.append(spawn) spawn.start() if action == spawn_point_delete: pixmap = self._scene.itemAt(pos.x(), pos.y(), QTransform()) if pixmap: group = pixmap.parentItem() if group: self._data.spawns.remove(group) self._scene.removeItem(group) if action == spawn_point_delete_all: for spawn in self._data.spawns: self._scene.removeItem(spawn) self._data.spawns = [] if action == way_point_create: if self._data.way_point: self._scene.removeItem(self._data.way_point.pixmap) self._scene.removeItem(self._data.way_point.line) self._data.way_point = None self._data.way_point = WayPoint(location=MapPoint( x=pos.x(), y=pos.y(), z=self._data.geometry.z_groups[self._z_index])) self._scene.addItem(self._data.way_point.pixmap) self._scene.addItem(self._data.way_point.line) if action == way_point_delete: if self._data.way_point: self._scene.removeItem(self._data.way_point.pixmap) self._scene.removeItem(self._data.way_point.line) self._data.way_point = None if action == load_map: dialog = QInputDialog(self) dialog.setWindowTitle('Load Map') dialog.setLabelText('Select map to load:') dialog.setComboBoxItems( sorted([map.title() for map in MapData.get_zone_dict().keys()])) if dialog.exec_(): self.load_map(dialog.textValue().lower()) dialog.deleteLater() self.update_()
class Widget(QMainWindow, client_form): def __init__(self, parent=None): QMainWindow.__init__(self, parent) self.setupUi(self) self.refreshLabel.setVisible(False) self.client = Client(50000, 3000) self.refreshButton.clicked.connect(self.refresh) self.connectButton.clicked.connect(self.connect) self._graphics_scene = QGraphicsScene(self) self.graphicsView.setScene(self._graphics_scene) self._graphics_scene.mousePressEvent = self.mouse_pressed self.exit_action.triggered.connect(self.exit) self.help_action.triggered.connect(self.show_help) self.bullshit_action.triggered.connect(self.send_incorrect_message) self.viewlog_action.triggered.connect(self.open_log) self.connected = False def open_log(self): if os.uname().sysname == "Darwin": webbrowser.open("file:///" + os.path.abspath("./client.log")) else: webbrowser.open("./client.log") def exit(self): if self.connected: self.revert() self.client.disconnect() self.close() def show_help(self): mb = QMessageBox.information( self, "О программе", "Программа удаленного управления рабочим столом.\n\n" "Создатели:\n" "Алексей Абакумкин, ИУ7-72\n" "Роман Инфлянскас, ИУ7-71\n" "(c) 2014, Москва, МГТУ им. Н. Э. Баумана") def critical(self, msg, log=True): self.revert() QMessageBox.critical(self, "Ошибка", msg) if log: logging.error("{ip}\t{msg}\tОшибка".format(ip=self.client.ip, msg=msg)) def send_incorrect_message(self): if self.connected: try: self.client.send_incorrect_message() except: # mb = QMessageBox.critical(self, "Ошибка", "Сервер перестал отвечать") self.critical("Сервер перестал отвечать") def refresh(self): self.serverList.clear() self.refreshLabel.setVisible(True) self.repaint() for x in self.client.refresh_server_list(): self.serverList.addItem("{0}:{1}".format(x[0], x[1])) self.refreshLabel.setVisible(False) def connect(self): if self.connected: self.revert() self.client.disconnect() return try: login, login_ok = QInputDialog.getText(self, 'Логин', 'Введите логин:') if login_ok: passwd, password_ok = QInputDialog.getText(self, 'Пароль', 'Введите пароль:', 2) if password_ok: server_item = self.serverList.currentItem() try: address = server_item.text().split(":") except: # server_item = self.serverList.findItems('', 0)[0] self.serverList.setCurrentRow(0) server_item = self.serverList.currentItem() address = server_item.text().split(":") if self.client.connect_to_server(address, login, passwd): self.connectButton.setText("Отключиться") self.connected = True else: self.critical("Неверный логин или пароль!", log=False) # mb = QMessageBox.critical(self, "Ошибка", "Неверный логин или пароль!") except TimeoutError: self.critical("Сервер перестал отвечать") # mb = QMessageBox.critical(self, "Ошибка", "Сервер перестал отвечать") def revert(self): self._graphics_scene.clear() self.connectButton.setText("Присоединиться") self.connected = False def paintEvent(self, QPaintEvent): if self.connected: try: self.image_base_64 = self.client.recieve_screenshot() except TimeoutError: self.critical("Сервер перестал отвечать") # mb = QMessageBox.critical(self, "Ошибка", "Сервер перестал отвечать") return self.data = QByteArray.fromBase64(self.image_base_64) self.pm = QPixmap() self.pm.loadFromData(self.data, "PNG") self._graphics_scene.clear() self._graphics_scene.addPixmap(self.pm) self.update() def mouse_pressed(self, event): if self.connected: x = int(event.scenePos().x()) y = int(event.scenePos().y()) button = event.button() if button == 4: button = 3 try: self.client.send_mouse_event(x, y, button) except: self.critical("Сервер перестал отвечать") # mb = QMessageBox.critical(self, "Ошибка", "Сервер перестал отвечать") self.revert()
class panel(QGraphicsView): def __init__(self): super(panel, self).__init__() self.arbolito = None #arbol de entornos self.y = 50 #posicion en y inicial self.escena = QGraphicsScene() #escena de dibujo self.setScene( self.escena) #asignamos la escena al QGraphicsView de la clase # ------------------------------------------------------------------------------------------------- # metodo que verifica cuando se hace click en la escena # ------------------------------------------------------------------------------------------------- def mousePressEvent(self, event): print("clicked") x = event.pos().x() y = event.pos().y() print(x, y) pt = self.mapToScene( event.pos() ) #se escala la posicion de click del QGraphicsView a la escena (QGraphicsScene) root = self.arbolito.get_root() #raiz del arbol if (root != None): rect = QRect( int(pt.x()), int(pt.y()), root.tam, root.tam) # se crea un rectangulo para la colision con el nodo self.__colision(root, rect) # ------------------------------------------------------------------------------------------------- # metodo que verifica si el evento del click se realizo sobre algun nodo # ------------------------------------------------------------------------------------------------- def __colision(self, nodo, rect): #si el nodo entrante fue el clickeado if nodo.rect.intersects(rect): #se muestra un mensaje #con la informacion del nodo-> nombre del procedimiento o funcion msg = QMessageBox() msg.setIcon(QMessageBox.Information) msg.setText("Nombre Ambiente: " + str(nodo.info)) msg.exec_() return True else: #si no se mira si se hizo el click en alguno de los hijos for i in nodo.childrens: self.__colision(i, rect) # ------------------------------------------------------------------------------------------------- # metodo que limpia la escena y llama al metodo de pintado del arbol # ------------------------------------------------------------------------------------------------- def dibujar(self): #self.arbolito.get_root().print_tree() self.escena.clear() self.pintar() # ------------------------------------------------------------------------------------------------- # metodo publico que llama el pintado del arbol y sus lineas desde la razi # ------------------------------------------------------------------------------------------------- def pintar(self): root = self.arbolito.get_root() self.y = 50 self.__pintar_arbol(root, 10, self.y) self.__lineas(root) # ------------------------------------------------------------------------------------------------- # metodo que pinta todos los nodos del arbol # ------------------------------------------------------------------------------------------------- def __pintar_arbol(self, nodo, x, y): pen = QPen(Qt.black) #lapiz de nodo normal pen2 = QPen(Qt.green) #lapiz de nodo actual nodo.x = x #se asigna posicion x al nodo nodo.y = self.y #se asigna posicion y al nodo nodo.rect = QRect( nodo.x, nodo.y, nodo.tam, nodo.tam ) # se crea un rectangulo para el nodo,para los eventos click #print("Pos x : ",nodo.x,"Pos y : ",nodo.y," Dato :",nodo.data," Info : ",nodo.info) xp = nodo.tam / 2 #self.escena.addRect(nodo.rect,pen) if nodo.activo: self.escena.addEllipse(nodo.x, nodo.y, nodo.tam, nodo.tam, pen2) else: self.escena.addEllipse(nodo.x, nodo.y, nodo.tam, nodo.tam, pen) #texto del nodo text = self.escena.addText(str(nodo.data)) text.setPos(QPointF(nodo.x + 2, nodo.y - 3)) x += 50 ##pintar los hijos for i in nodo.childrens: self.y += 40 self.__pintar_arbol(i, x, self.y) # ------------------------------------------------------------------------------------------------- # metodo que pinta las lineas de relacion en el arbol # ------------------------------------------------------------------------------------------------- def __lineas(self, nodo): pen = QPen(Qt.black) xp = nodo.tam / 2 for i in nodo.childrens: xl1_a = nodo.x + nodo.tam + 5 yl1_a = nodo.y + nodo.tam - 5 ylb = i.y + xp self.escena.addLine(nodo.x + nodo.tam, yl1_a, xl1_a, yl1_a) self.escena.addLine(xl1_a, yl1_a, xl1_a, ylb, pen) self.escena.addLine(xl1_a, ylb, i.x, ylb, pen) self.__lineas(i)
class UMLDialog(E5MainWindow): """ Class implementing a dialog showing UML like diagrams. """ NoDiagram = 255 ClassDiagram = 0 PackageDiagram = 1 ImportsDiagram = 2 ApplicationDiagram = 3 FileVersions = ["1.0"] def __init__(self, diagramType, project, path="", parent=None, initBuilder=True, **kwargs): """ Constructor @param diagramType type of the diagram (one of ApplicationDiagram, ClassDiagram, ImportsDiagram, NoDiagram, PackageDiagram) @param project reference to the project object (Project) @param path file or directory path to build the diagram from (string) @param parent parent widget of the dialog (QWidget) @keyparam initBuilder flag indicating to initialize the diagram builder (boolean) @keyparam kwargs diagram specific data """ super(UMLDialog, self).__init__(parent) self.setObjectName("UMLDialog") self.__diagramType = diagramType self.__project = project from .UMLGraphicsView import UMLGraphicsView self.scene = QGraphicsScene(0.0, 0.0, 800.0, 600.0) self.umlView = UMLGraphicsView(self.scene, parent=self) self.builder = self.__diagramBuilder( self.__diagramType, path, **kwargs) if self.builder and initBuilder: self.builder.initialize() self.__fileName = "" self.__initActions() self.__initToolBars() self.setCentralWidget(self.umlView) self.umlView.relayout.connect(self.__relayout) self.setWindowTitle(self.__diagramTypeString()) def __initActions(self): """ Private slot to initialize the actions. """ self.closeAct = \ QAction(UI.PixmapCache.getIcon("close.png"), self.tr("Close"), self) self.closeAct.triggered.connect(self.close) self.openAct = \ QAction(UI.PixmapCache.getIcon("open.png"), self.tr("Load"), self) self.openAct.triggered.connect(self.load) self.saveAct = \ QAction(UI.PixmapCache.getIcon("fileSave.png"), self.tr("Save"), self) self.saveAct.triggered.connect(self.__save) self.saveAsAct = \ QAction(UI.PixmapCache.getIcon("fileSaveAs.png"), self.tr("Save As..."), self) self.saveAsAct.triggered.connect(self.__saveAs) self.saveImageAct = \ QAction(UI.PixmapCache.getIcon("fileSavePixmap.png"), self.tr("Save as Image"), self) self.saveImageAct.triggered.connect(self.umlView.saveImage) self.printAct = \ QAction(UI.PixmapCache.getIcon("print.png"), self.tr("Print"), self) self.printAct.triggered.connect(self.umlView.printDiagram) self.printPreviewAct = \ QAction(UI.PixmapCache.getIcon("printPreview.png"), self.tr("Print Preview"), self) self.printPreviewAct.triggered.connect( self.umlView.printPreviewDiagram) def __initToolBars(self): """ Private slot to initialize the toolbars. """ self.windowToolBar = QToolBar(self.tr("Window"), self) self.windowToolBar.setIconSize(UI.Config.ToolBarIconSize) self.windowToolBar.addAction(self.closeAct) self.fileToolBar = QToolBar(self.tr("File"), self) self.fileToolBar.setIconSize(UI.Config.ToolBarIconSize) self.fileToolBar.addAction(self.openAct) self.fileToolBar.addSeparator() self.fileToolBar.addAction(self.saveAct) self.fileToolBar.addAction(self.saveAsAct) self.fileToolBar.addAction(self.saveImageAct) self.fileToolBar.addSeparator() self.fileToolBar.addAction(self.printPreviewAct) self.fileToolBar.addAction(self.printAct) self.umlToolBar = self.umlView.initToolBar() self.addToolBar(Qt.TopToolBarArea, self.fileToolBar) self.addToolBar(Qt.TopToolBarArea, self.windowToolBar) self.addToolBar(Qt.TopToolBarArea, self.umlToolBar) def show(self, fromFile=False): """ Public method to show the dialog. @keyparam fromFile flag indicating, that the diagram was loaded from file (boolean) """ if not fromFile and self.builder: self.builder.buildDiagram() super(UMLDialog, self).show() def __relayout(self): """ Private method to relayout the diagram. """ if self.builder: self.builder.buildDiagram() def __diagramBuilder(self, diagramType, path, **kwargs): """ Private method to instantiate a diagram builder object. @param diagramType type of the diagram (one of ApplicationDiagram, ClassDiagram, ImportsDiagram, PackageDiagram) @param path file or directory path to build the diagram from (string) @keyparam kwargs diagram specific data @return reference to the instantiated diagram builder @exception ValueError raised to indicate an illegal diagram type """ if diagramType == UMLDialog.ClassDiagram: from .UMLClassDiagramBuilder import UMLClassDiagramBuilder return UMLClassDiagramBuilder( self, self.umlView, self.__project, path, **kwargs) elif diagramType == UMLDialog.PackageDiagram: from .PackageDiagramBuilder import PackageDiagramBuilder return PackageDiagramBuilder( self, self.umlView, self.__project, path, **kwargs) elif diagramType == UMLDialog.ImportsDiagram: from .ImportsDiagramBuilder import ImportsDiagramBuilder return ImportsDiagramBuilder( self, self.umlView, self.__project, path, **kwargs) elif diagramType == UMLDialog.ApplicationDiagram: from .ApplicationDiagramBuilder import ApplicationDiagramBuilder return ApplicationDiagramBuilder( self, self.umlView, self.__project, **kwargs) elif diagramType == UMLDialog.NoDiagram: return None else: raise ValueError(self.tr( "Illegal diagram type '{0}' given.").format(diagramType)) def __diagramTypeString(self): """ Private method to generate a readable string for the diagram type. @return readable type string (string) """ if self.__diagramType == UMLDialog.ClassDiagram: return "Class Diagram" elif self.__diagramType == UMLDialog.PackageDiagram: return "Package Diagram" elif self.__diagramType == UMLDialog.ImportsDiagram: return "Imports Diagram" elif self.__diagramType == UMLDialog.ApplicationDiagram: return "Application Diagram" else: return "Illegal Diagram Type" def __save(self): """ Private slot to save the diagram with the current name. """ self.__saveAs(self.__fileName) @pyqtSlot() def __saveAs(self, filename=""): """ Private slot to save the diagram. @param filename name of the file to write to (string) """ if not filename: fname, selectedFilter = E5FileDialog.getSaveFileNameAndFilter( self, self.tr("Save Diagram"), "", self.tr("Eric Graphics File (*.e5g);;All Files (*)"), "", E5FileDialog.Options(E5FileDialog.DontConfirmOverwrite)) if not fname: return ext = QFileInfo(fname).suffix() if not ext: ex = selectedFilter.split("(*")[1].split(")")[0] if ex: fname += ex if QFileInfo(fname).exists(): res = E5MessageBox.yesNo( self, self.tr("Save Diagram"), self.tr("<p>The file <b>{0}</b> already exists." " Overwrite it?</p>").format(fname), icon=E5MessageBox.Warning) if not res: return filename = fname lines = [ "version: 1.0", "diagram_type: {0} ({1})".format( self.__diagramType, self.__diagramTypeString()), "scene_size: {0};{1}".format(self.scene.width(), self.scene.height()), ] persistenceData = self.builder.getPersistenceData() if persistenceData: lines.append("builder_data: {0}".format(persistenceData)) lines.extend(self.umlView.getPersistenceData()) try: f = open(filename, "w", encoding="utf-8") f.write("\n".join(lines)) f.close() except (IOError, OSError) as err: E5MessageBox.critical( self, self.tr("Save Diagram"), self.tr( """<p>The file <b>{0}</b> could not be saved.</p>""" """<p>Reason: {1}</p>""").format(filename, str(err))) return self.__fileName = filename def load(self): """ Public method to load a diagram from a file. @return flag indicating success (boolean) """ filename = E5FileDialog.getOpenFileName( self, self.tr("Load Diagram"), "", self.tr("Eric Graphics File (*.e5g);;All Files (*)")) if not filename: # Cancelled by user return False try: f = open(filename, "r", encoding="utf-8") data = f.read() f.close() except (IOError, OSError) as err: E5MessageBox.critical( self, self.tr("Load Diagram"), self.tr( """<p>The file <b>{0}</b> could not be read.</p>""" """<p>Reason: {1}</p>""").format(filename, str(err))) return False lines = data.splitlines() if len(lines) < 3: self.__showInvalidDataMessage(filename) return False try: # step 1: check version linenum = 0 key, value = lines[linenum].split(": ", 1) if key.strip() != "version" or \ value.strip() not in UMLDialog.FileVersions: self.__showInvalidDataMessage(filename, linenum) return False else: version = value # step 2: extract diagram type linenum += 1 key, value = lines[linenum].split(": ", 1) if key.strip() != "diagram_type": self.__showInvalidDataMessage(filename, linenum) return False try: self.__diagramType = int(value.strip().split(None, 1)[0]) except ValueError: self.__showInvalidDataMessage(filename, linenum) return False self.scene.clear() self.builder = self.__diagramBuilder(self.__diagramType, "") # step 3: extract scene size linenum += 1 key, value = lines[linenum].split(": ", 1) if key.strip() != "scene_size": self.__showInvalidDataMessage(filename, linenum) return False try: width, height = [float(v.strip()) for v in value.split(";")] except ValueError: self.__showInvalidDataMessage(filename, linenum) return False self.umlView.setSceneSize(width, height) # step 4: extract builder data if available linenum += 1 key, value = lines[linenum].split(": ", 1) if key.strip() == "builder_data": ok = self.builder.parsePersistenceData(version, value) if not ok: self.__showInvalidDataMessage(filename, linenum) return False linenum += 1 # step 5: extract the graphics items ok, vlinenum = self.umlView.parsePersistenceData( version, lines[linenum:]) if not ok: self.__showInvalidDataMessage(filename, linenum + vlinenum) return False except IndexError: self.__showInvalidDataMessage(filename) return False # everything worked fine, so remember the file name self.__fileName = filename return True def __showInvalidDataMessage(self, filename, linenum=-1): """ Private slot to show a message dialog indicating an invalid data file. @param filename name of the file containing the invalid data (string) @param linenum number of the invalid line (integer) """ if linenum < 0: msg = self.tr("""<p>The file <b>{0}</b> does not contain""" """ valid data.</p>""").format(filename) else: msg = self.tr("""<p>The file <b>{0}</b> does not contain""" """ valid data.</p><p>Invalid line: {1}</p>""" ).format(filename, linenum + 1) E5MessageBox.critical(self, self.tr("Load Diagram"), msg)
class Game(QGraphicsView): end_signal = pyqtSignal(int) score_signal = pyqtSignal(int) def __init__(self): """ Function creates MyView object. """ QGraphicsView.__init__(self) self.__init_game() self.__init_ui() def __init_game(self): """ Function initializes all backend game fields. :return: """ self.bombs = [] self.timer = QTimer() self.player = Player.Player(1, 1, 0) self.bots = [ Bot.Bot(10 + (i + 1) * 6, 10 + (i + 1) * 6, i + 1) for i in range(num_of_bots) ] self.score = 0 self.create_board() self.move_dict = { Qt.Key_Left: self.move_left, Qt.Key_Right: self.move_right, Qt.Key_Up: self.move_up, Qt.Key_Down: self.move_down, Qt.Key_Space: self.add_bomb } for bot in self.bots: bot.remember_board(self.board) bot.remember_player_pos([self.player]) bot.remember_bombs(self.bombs) def __init_ui(self): """ Function initializes User Interface and Map view. :return: """ self.scene = QGraphicsScene(0, 0, WINDOW_HEIGHT, WINDOW_WIDTH) self.view = QGraphicsView(self.scene) self.draw_board() self.setScene(self.scene) self.timer.timeout.connect(self.update) self.timer.start(10) self.timer_bots = QTimer() self.timer_bots.timeout.connect(self.move_bot) self.timer_bots.start(200) self.items = self.scene.items() def reinit_game(self): """ Function gets game to init state. :return: """ self.__init_game() self.__init_ui() def get_obj(self, x, y): """ Function returns object in a map by coordinates. :param x: x coordinate of an object :param y: y coordiate of an object :return: Object. """ for item in self.items: if item.x == x and item.y == y: return item else: return None def update(self): """ Function handles all games parameters such as bombs boom, player death etc. Should be called periodically. :return: """ for bomb in self.bombs: self.board[bomb.x][bomb.y] = 'XX' # Add bomb to the board. self.draw_image(bomb.x, bomb.y, path_bomb) if self.player.alive: self.board[self.player.x][ self.player.y] = 'OO' # Add player to the board. self.draw_image(self.player.last_x, self.player.last_y, path_road) self.draw_image(self.player.x, self.player.y, path_bomberman) for bot in self.bots: if bot.alive: self.board[bot.x][bot.y] = 'BB' self.draw_image(bot.last_x, bot.last_y, path_road) self.draw_image(bot.x, bot.y, path_bot) self.score_signal.emit(self.score) self.boom() def read_board_xml(self, filename="map.xml"): """ Function reads game map from the XML file. :param filename: Name of xml file. :return: """ xmldoc = xm.parse(filename) rowslist = xmldoc.getElementsByTagName('row') for i in range(len(rowslist)): obj = rowslist[i].getElementsByTagName('obj') for j in range(len(obj)): self.board[i][j] = obj[j].firstChild.data def write_board_xml(self, filename="map.xml"): """ Function writes game map to the XML file. :param filename: Name of xml file. :return: """ doc = xm.Document() map_elem = doc.createElement("mapa") for i in range(len(self.board)): row_elem = doc.createElement("row") for j in range(len(self.board[0])): obj_elem = doc.createElement("obj") row_elem.appendChild(obj_elem) obj_elem.appendChild(doc.createTextNode(self.board[i][j])) map_elem.appendChild(row_elem) doc.appendChild(map_elem) with open(filename, 'w') as the_file: the_file.write(doc.toprettyxml()) def draw_board(self): """ Function draw whole game map. :return: """ self.scene.clear() for bomba in self.bombs: self.board[bomba.X][bomba.Y] = 'XX' if self.player.alive: self.board[self.player.x][self.player.y] = 'OO' for bot in self.bots: if bot.alive: self.board[bot.x][bot.y] = 'BB' for i in range(len(self.board)): for j in range(len(self.board[i])): if self.board[i][j] == '##': self.draw_image(i, j, path_cant_destroy) elif self.board[i][j] == '**': self.draw_image(i, j, path_can_destroy) elif self.board[i][j] == ' ': self.draw_image(i, j, path_road) elif self.board[i][j] == 'OO': self.draw_image(i, j, path_bomberman) elif self.board[i][j] == 'XX': self.draw_image(i, j, path_bomb) elif self.board[i][j] == 'BB': self.draw_image(i, j, path_bot) def create_board(self): """ Function creates game map. It's based on creating maze algorithm. :return: """ temp = numpy.zeros((MAP_WIDTH, MAP_HEIGHT), dtype=bool) temp = temp.astype(str) for x in range(MAP_WIDTH): for y in range(MAP_HEIGHT): if x == 0 or y == 0 or x == MAP_WIDTH - 1 or y == MAP_HEIGHT - 1: temp[x][y] = "##" elif x % 2 == 0 and y % 2 == 0: temp[x][y] = "##" else: temp[x][y] = "**" if temp[self.player.x + 1][self.player.y] != "##": temp[self.player.x + 1][self.player.y] = " " if temp[self.player.x][self.player.y + 1] != "##": temp[self.player.x][self.player.y + 1] = " " if temp[self.player.x + 2][self.player.y] != "##": temp[self.player.x + 2][self.player.y] = " " if temp[self.player.x][self.player.y + 2] != "##": temp[self.player.x][self.player.y + 2] = " " for i in range(len(self.bots)): if temp[self.bots[i].x - 1][self.bots[i].y] != "##": temp[self.bots[i].x - 1][self.bots[i].y] = " " if temp[self.bots[i].x][self.bots[i].y - 1] != "##": temp[self.bots[i].x][self.bots[i].y - 1] = " " if temp[self.bots[i].x - 2][self.bots[i].y] != "##": temp[self.bots[i].x - 2][self.bots[i].y] = " " if temp[self.bots[i].x][self.bots[i].y - 2] != "##": temp[self.bots[i].x][self.bots[i].y - 2] = " " temp[14][16] = " " temp[16][14] = " " temp[14][15] = " " temp[15][17] = " " temp[15][15] = " " temp[15][14] = " " self.board = temp def draw_image(self, x, y, path): """ Function draw single image on game map. :param x: X coordinate of an image. :param y: Y coordinate of an image. :param path: path with an image to be printed. :return: """ # Remove items from scene. self.items = self.scene.items() item = self.get_obj(x, y) if len(self.items) > MAP_HEIGHT * MAP_WIDTH: if item is not None: self.scene.removeItem(item) item = MyRect.MyRect(x, y, path) item.setAcceptHoverEvents(True) item.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable) self.scene.addItem(item) def keyPressEvent(self, event): """ Key press event. :param event: :return: """ self.move_dict[event.key()](self.player) def move_up(self, player): """ Function checks if player can go up. If can it moves, if can't it does nothing. :param player: Player to be moved. :return: """ if player.y < MAP_HEIGHT - 1 and self.board[player.x][player.y + 1] != '**'\ and self.board[player.x][player.y + 1] != '##': self.board[player.x][player.y] = ' ' player.move('u') def move_down(self, player): """ Function checks if player can go down. If can it moves, if can't it does nothing. :param player: Player to be moved. :return: """ if player.y > 1 and self.board[player.x][player.y - 1] != '**'\ and self.board[player.x][player.y - 1] != '##': self.board[player.x][player.y] = ' ' player.move('d') def move_left(self, player): """ Function checks if player can go left. If can it moves, if can't it does nothing. :param player: Player to be moved. :return: """ if player.x > 1 and self.board[player.x - 1][player.y] != '**'\ and self.board[player.x - 1][player.y] != '##': self.board[player.x][player.y] = ' ' player.move('l') def move_right(self, player): """ Function checks if player can go right. If can it moves, if can't it does nothing. :param player: Player to be moved. :return: """ if player.x < MAP_HEIGHT - 1 and self.board[player.x + 1][player.y] != '**'\ and self.board[player.x + 1][player.y] != '##': self.board[player.x][player.y] = ' ' player.move('r') def add_bomb(self, player): """ Function adds bomb to bombs list. :param player: Player which left the bomb. :return: """ self.bombs.append( Bomb.Bomb(player.x, player.y, time.time(), player.ind)) def boom(self): """ Function handles bombs explosion. :return: """ end = False for bomb in self.bombs: if time.time() - bomb.start > 3: self.clean_fields_after_boom(bomb) end = self.kill_players(bomb) self.bombs.remove(bomb) if bomb.owner == self.player.ind: self.score += bomb_range if end: self.end_signal.emit(1) def clean_fields_after_boom(self, bomb): """ Function cleans fields after bomb explosion. :param bomb: :return: """ for field in bomb.get_cords_in_range(): if 0 < field[0] < MAP_WIDTH and \ 0 < field[1] < MAP_HEIGHT and \ self.board[field[0]][field[1]] != "##": self.board[field[0]][field[1]] = " " self.draw_image(field[0], field[1], path_road) self.board[bomb.x][bomb.y] = " " self.draw_image(bomb.x, bomb.y, path_road) def kill_players(self, bomb): """ Function checks if player is killed by bomb. If is it returns True else returns False :param bomb: Bomb object :return: """ for cords in bomb.get_cords_in_range(): if (self.player.x, self.player.y) == cords: self.player.alive = False for bot in self.bots: if (bot.x, bot.y) == cords: bot.alive = False return not self.player.alive def move_bot(self): """ Function handles bot move. :return: """ for bot in self.bots: old_x = bot.x old_y = bot.y bot.move() if bot.is_bomb_left(): self.bombs.append(Bomb.Bomb(old_x, old_y, time.time(), 1)) self.board[bot.last_x][bot.last_y] = "XX" else: self.board[old_x][old_y] = " " self.board[bot.x][bot.y] = "BB" bot.remember_player_pos([self.player]) bot.remember_board(self.board) bot.remember_bombs(self.bombs)
class FilteringDialog(QDialog, Ui_Dialog): scene = None base_image = None image = None current_sampling_level = 0 sliders = None labels = None fit_allowed = False def __init__(self, data_manager): super(FilteringDialog, self).__init__() self.setupUi(self) self.setAttribute(Qt.WA_DeleteOnClose) assert isinstance(data_manager, DataManager) self.base_image = data_manager.radiographs[0].image h, w = self.base_image.shape ch, cw = h / 2, w / 2 self.base_image = self.base_image[ch - 100:ch + 500, cw - 150:cw + 150].copy() self.image = self.base_image self.scene = QGraphicsScene() self.graphicsView.setScene(self.scene) self.levelSlider.setRange(1, MultiResolutionFramework.levels_count) self.levelSlider.setValue(self.current_sampling_level + 1) self.levelSlider.valueChanged.connect(self._sampling_level_changed) ranges = [(0, 20), (0, 20), (0, 20), (0, 200), (0, 200)] values = [2, 8, 9, 0, 5] self.sliders = list() self.labels = list() for i in range(0, len(ranges)): slider = QSlider(Qt.Horizontal, self.scrollAreaWidgetContents) label = QLabel() slider.setRange(ranges[i][0], ranges[i][1]) slider.setValue(values[i]) slider.valueChanged.connect(self._slider_moved) layout = QHBoxLayout() layout.addWidget(slider) layout.addWidget(label) self.scrollAreaWidgetContents.layout().addLayout(layout) self.sliders.append(slider) self.labels.append(label) self._set_labels() self._redraw() def _sampling_level_changed(self, value): self.current_sampling_level = value - 1 self.image = self.base_image scale = 1.0 for i in range(0, self.current_sampling_level): self.image = MultiResolutionFramework.downsample_image(self.image) scale *= 2 self.graphicsView.resetTransform() self.graphicsView.scale(scale, scale) self._redraw() def _slider_moved(self, value): self._set_labels() self._redraw() def _set_labels(self): for i, label in enumerate(self.labels): value = self.sliders[i].value() if i < 2: value = value * 2 + 1 if value >= 1 else 0 label.setText(str(value)) def _scharr_filter(self, img): grad_x = cv2.Scharr(img, cv2.CV_64F, 1, 0) / 16 grad_y = cv2.Scharr(img, cv2.CV_64F, 0, 1) / 16 grad = np.sqrt(grad_x ** 2 + grad_y ** 2) return grad def _perform_fft(self, img): f = np.fft.fft2(img) fshift = np.fft.fftshift(f) return fshift def _focus_view(self, size): if not self.fit_allowed: self.fit_allowed = True return rect = QRectF(0, 0, size[0], size[1]) self.scene.setSceneRect(rect) def _redraw(self): self.scene.clear() img = self.image.copy() med_kernel = self.sliders[0].value() * 2 + 1 bi_kernel = self.sliders[1].value() * 2 + 1 bi_color = self.sliders[2].value() med = cv2.medianBlur(img, med_kernel) if med_kernel > 1 else img med_bi = cv2.bilateralFilter(med, bi_kernel, bi_color, 200) if bi_kernel > 1 else med fshift = self._perform_fft(med_bi) # scharr = np.array([[ -1/16-1/16j, 1/2-1/8j, +1/16 -1/16j], # [-1/8+0j, 1/2+0j, +1/8 +0j], # [ -1/16+1/16j, 0+1/8j, +1/16 +1/16j]]) # Gx + j*Gy # fshift = signal.convolve2d(fshift, scharr, boundary='symm', mode='same') if self.sliders[3].value() != 0: rows, cols = img.shape crow, ccol = rows / 2, cols / 2 mask = np.zeros(fshift.shape) cv2.circle(mask, (ccol, crow), self.sliders[3].value(), 1, -1) cv2.circle(mask, (ccol, crow), self.sliders[4].value(), 0, -1) fshift *= mask f_ishift = np.fft.ifftshift(fshift) img_back = np.fft.ifft2(f_ishift) img_back = np.abs(img_back) grad_med_bi = self._scharr_filter(img_back) # img = (img / img.max()) * 255 mag = 20 * np.log(np.abs(fshift)) mag = (mag / mag.max()) * 255 img_back = (img_back / img_back.max()) * 255 grad_med_bi = (grad_med_bi / grad_med_bi.max()) * 255 together = np.hstack( (img.astype(np.uint8), mag.astype(np.uint8), img_back.astype(np.uint8), grad_med_bi.astype(np.uint8))) cv2.imwrite("together.png", together) qimg = toQImage(together) self.scene.addPixmap(QPixmap.fromImage(qimg)) self._focus_view((qimg.width(), qimg.height()))
class APISRepresentativeImage(QDialog, FORM_CLASS): def __init__(self, dbm, imageRegistry, currentPath, filmNumber, parent=None): """Constructor.""" super(APISRepresentativeImage, self).__init__(parent) self.dbm = dbm self.imageRegistry = imageRegistry self.currentPath = currentPath self.filmNumber = filmNumber self.newPath = currentPath self.setupUi(self) if GetWindowSize("representative_image"): self.resize(GetWindowSize("representative_image")) self.settings = QSettings(QSettings().value("APIS/config_ini"), QSettings.IniFormat) # Signals/Slot Connections self.rejected.connect(self.onReject) self.buttonBox.rejected.connect(self.onReject) self.buttonBox.accepted.connect(self.onAccept) self.uiSelectImageFromSystem.clicked.connect( self.selectImageFromSystem) self.graphicLoaded = False self.scene = QGraphicsScene() self.uiRepresentativeImageView.setScene(self.scene) # ist FilmProjekt ein FILM? if IsFilm(self.dbm.db, self.filmNumber): self.populateFilmCombo(self.filmNumber) else: self.populateFilmCombo() # wenn nein self.populateFilmCombo() self.uiAvailableImagesCombo.currentIndexChanged.connect( self.loadNewImageByFilm) def populateFilmCombo(self, filmNumber=None): editor = self.uiFilmNumberCombo model = QSqlQueryModel(self) model.setQuery( "SELECT DISTINCT {0} FROM {1} ORDER BY {2}".format( 'filmnummer', 'film', 'filmnummer'), self.dbm.db) tv = QTableView() editor.setView(tv) tv.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) tv.setSelectionMode(QAbstractItemView.SingleSelection) tv.setSelectionBehavior(QAbstractItemView.SelectRows) tv.setAutoScroll(False) editor.setModel(model) editor.setModelColumn(0) editor.setInsertPolicy(QComboBox.NoInsert) tv.resizeColumnsToContents() tv.resizeRowsToContents() tv.verticalHeader().setVisible(False) tv.horizontalHeader().setVisible(True) # tv.setMinimumWidth(tv.horizontalHeader().length()) tv.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) #FIXME PyQt5 AutoCompletion #editor.setAutoCompletion(True) if filmNumber: editor.setCurrentIndex(editor.findText(filmNumber)) self.populateAvailableImagesCombo() else: editor.setCurrentIndex(-1) editor.currentIndexChanged.connect(self.populateAvailableImagesCombo) def populateAvailableImagesCombo(self, idx=None): self.filmNumber = self.uiFilmNumberCombo.currentText() # query image registry availableImages = self.imageRegistry.getImageRegistryForFilm( self.filmNumber) self.uiAvailableImagesCombo.clear() self.uiAvailableImagesCombo.addItems(availableImages) self.uiAvailableImagesCombo.setCurrentIndex(-1) def showEvent(self, event): if self.currentPath: self.uiImagePathLbl.setText(self.currentPath) self.loadImage(self.currentPath) else: self.uiImagePathLbl.setText("--") self.loadText() self.graphicLoaded = True def loadText(self): self.scene.clear() noImageTxt = QGraphicsTextItem() noImageTxt.setPlainText( u"Wählen Sie ein repräsentatives Luftbild aus ...") self.rect = noImageTxt.boundingRect() self.scene.addItem(noImageTxt) self.scene.setSceneRect(self.rect) self.uiRepresentativeImageView.fitInView(self.rect, Qt.KeepAspectRatio) def loadImage(self, path): self.scene.clear() image = QImage(path) size = image.size() self.rect = QRectF(0, 0, size.width(), size.height()) self.scene.addPixmap(QPixmap.fromImage(image)) self.scene.setSceneRect(self.rect) self.uiRepresentativeImageView.fitInView(self.rect, Qt.KeepAspectRatio) def loadNewImageByFilm(self): # generatePath imgDir = self.settings.value("APIS/image_dir") filmDir = self.filmNumber self.newPath = os.path.normpath( imgDir + "\\" + filmDir + "\\" + self.uiAvailableImagesCombo.currentText().replace('.', '_') + ".jpg") self.uiImagePathLbl.setText(self.newPath) self.loadImage(self.newPath) def resizeEvent(self, event): if self.graphicLoaded: self.uiRepresentativeImageView.fitInView(self.rect, Qt.KeepAspectRatio) def selectImageFromSystem(self): dir = self.settings.value("APIS/image_dir") fileName, _filter = QFileDialog.getOpenFileName( self, u"Repräsentatives Luftbild auswählen", dir, "Bild Dateien (*.jpg)") if fileName: self.uiFilmNumberCombo.setCurrentIndex(-1) self.newPath = fileName self.uiImagePathLbl.setText(self.newPath) self.loadImage(self.newPath) def onAccept(self): ''' Check DB Save options when pressing OK button Update Plugin Status ''' SetWindowSize("representative_image", self.size()) self.accept() def onReject(self): ''' Run some actions when the user closes the dialog ''' SetWindowSize("representative_image", self.size()) self.close()
class BackgroundGeneratorDialog(Ui_BackgroundGeneratorDialog, QDialog): def __init__(self, parent=None): QDialog.__init__(self, parent) Ui_BackgroundGeneratorDialog.__init__(self) self.setupUi(self) self.videoPlaybackInit() self.imgInit() self.generateButton.pressed.connect(self.generateBackground) def closeEvent(self,event): pass def videoPlaybackInit(self): self.videoPlaybackWidget.frameChanged.connect(self.setFrame, type=Qt.QueuedConnection) def setFrame(self, frame): if frame is not None: self.cv_img = frame self.updateInputGraphicsView() if self.fgbg is not None: self.updateOutputGraphicsView() def imgInit(self): self.inputScene = QGraphicsScene() self.inputGraphicsView.setScene(self.inputScene) self.inputGraphicsView.resizeEvent = self.inputGraphicsViewResized self.outputScene = QGraphicsScene() self.outputGraphicsView.setScene(self.outputScene) self.outputGraphicsView.resizeEvent = self.outputGraphicsViewResized self.fgbg = None def openVideoFile(self, filePath = None): if len(filePath) is not 0: self.filePath = filePath ret = self.videoPlaybackWidget.openVideo(filePath) if ret == False: return False self.videoPlaybackWidget.show() self.filterClassHash = None return True def updateInputGraphicsView(self): self.inputScene.clear() # self.inputScene.removeItem(self.inputPixMapItem) qimg = cvMatToQImage(self.cv_img) self.inputPixMap = QPixmap.fromImage(qimg) rect = QtCore.QRectF(self.inputPixMap.rect()) self.inputScene.setSceneRect(rect) self.outputScene.setSceneRect(rect) self.inputPixMapItem = QGraphicsPixmapItem(self.inputPixMap) # self.inputScene.setBackgroundBrush(QBrush(self.inputPixMap)) self.inputScene.addItem(self.inputPixMapItem) self.inputGraphicsView.viewport().update() self.inputGraphicsViewResized() def updateOutputGraphicsView(self): if False: out_img = self.fgbg.apply(self.cv_img, learningRate=0) else: bg = self.fgbg.getBackgroundImage() out_img = cv2.absdiff(self.cv_img, bg) self.outputScene.clear() qimg = cvMatToQImage(out_img) self.outputPixMap = QPixmap.fromImage(qimg) rect = QtCore.QRectF(self.outputPixMap.rect()) self.outputScene.setSceneRect(rect) self.outputPixMapItem = QGraphicsPixmapItem(self.outputPixMap) self.outputScene.addItem(self.outputPixMapItem) self.outputGraphicsView.viewport().update() self.outputGraphicsViewResized() def inputGraphicsViewResized(self, event=None): self.inputGraphicsView.fitInView(self.inputScene.sceneRect(), QtCore.Qt.KeepAspectRatio) def outputGraphicsViewResized(self, event=None): self.outputGraphicsView.fitInView(self.outputScene.sceneRect(), QtCore.Qt.KeepAspectRatio) def generateBackground(self): minFrame = self.videoPlaybackWidget.getMinRange() maxFrame = self.videoPlaybackWidget.getMaxRange() stride = self.strideSpinBox.value() numFrames = int((maxFrame-minFrame)/stride) progress = QProgressDialog("Generating background...", "Abort", 0, numFrames, self) progress.setWindowModality(Qt.WindowModal) fgbg = cv2.createBackgroundSubtractorMOG2() currentFrameNo = self.videoPlaybackWidget.currentFrameNo for i, frameNo in enumerate(range(minFrame, maxFrame+1, stride)): progress.setValue(i) if progress.wasCanceled(): break ret, frame = self.videoPlaybackWidget.readFrame(frameNo) fgbg.apply(frame) if not progress.wasCanceled(): self.fgbg = fgbg self.setFrame(self.cv_img) progress.setValue(numFrames) self.videoPlaybackWidget.currentFrameNo = currentFrameNo