class Tank(GameObject): FIRE_CD = 1.0 MAX_MOVE_SPEED = UNIT * 2 MAX_CANNON_ROTATION_SPEED = math.pi / 1.0 MAX_BODY_ROTATION_SPEED = math.pi / 4.0 MISSILE_SPEED = 2.5 * UNIT def __init__(self, color, group): super(Tank, self).__init__() self.graphics = QGraphicsItemGroup() self.body_graphics = TankGraphics(color) self.graphics.addToGroup(self.body_graphics) self.cannon_graphics = CannonGraphics(color) self.graphics.addToGroup(self.cannon_graphics) self.cannon_rotation = 0 self.cannon_rotate_speed = 0 self.group = group self.hp = 50 self.fire_cd = 0 def start(self): pass def update_logic(self): super(Tank, self).update_logic() self.cannon_rotation += self.cannon_rotate_speed * self.arena.dt self.fire_cd -= self.arena.dt def update_graphics(self): super(Tank, self).update_graphics() a = math.degrees(self.cannon_rotation) self.cannon_graphics.setRotation(a) def get_world_aiming(self): return self.rotation + self.cannon_rotation def adjust_aim_clockwise(self, w): self.cannon_rotate_speed = w def open_fire(self): if self.fire_cd <= 0: self.fire_cd = self.FIRE_CD orient = self.get_world_aiming() dv = QPointF(math.cos(orient), math.sin(orient)) * 0.6 * UNIT pos = self.position + dv m = Missile(pos, orient, self.MISSILE_SPEED) self.arena.add(m) return True else: return False def update(self): super(Tank, self).update() def take_damage(self, dmg): self.hp -= dmg if self.hp <= 0: self.cleanup()
def visualize(self): """ called when user clicks draw lsystem. This visualizes the lsystem to allow setup before the actual lsystification takes place """ self.getdata() self.run_lsystem() old_group = self.layersModel.itemFromIndex( self.parent.layersList.currentIndex()).get_graphics_items_group() if old_group: self.parent.scene.removeItem(old_group) group = QGraphicsItemGroup() path = QPainterPath() for idx, point in enumerate( self.lsysteminterpreter.globalstate["pts"]): x = point[0][0][0] y = point[0][1][0] direction = point[1] x = x * self.xscale + self.xoffs y = y * self.yscale + self.yoffs if idx == 0: path.moveTo(x, y) else: path.lineTo(x, y) item = QGraphicsPathItem(path) pen = QPen() pen.setWidth(self.strokeWidth) item.setPen(pen) group.addToGroup(item) self.addNewGraphicsItems(group)
def __drawPoint(self, x, y, index): #横线 line1 = QGraphicsLineItem() line1.setPen(self.pen) line1.setLine(x - self.lineRadius, y, x + self.lineRadius, y) #竖线 line2 = QGraphicsLineItem() line2.setPen(self.pen) line2.setLine(x, y - self.lineRadius, x, y + self.lineRadius) #文字说明 text = QGraphicsTextItem() text.setDefaultTextColor(Qt.blue) text.setFont(self.font) text.setPlainText(self.pointsName[index]) text.setPos(x, y) #放到组中 pointGroup = QGraphicsItemGroup() pointGroup.addToGroup(line1) pointGroup.addToGroup(line2) pointGroup.addToGroup(text) #显示 if self.pointsItem[index] is not None: self.scene.removeItem(self.pointsItem[index]) #保存到字典 self.pointsItem[index] = pointGroup #显示该点 self.scene.addItem(self.pointsItem[index])
class ReviewView(QGraphicsView): """Simple extension of QGraphicsView - containing an image and click-to-zoom/unzoom """ def __init__(self, fnames): QGraphicsView.__init__(self) self.initUI(fnames) def initUI(self, fnames): # Make QGraphicsScene self.scene = QGraphicsScene() # TODO = handle different image sizes. self.images = {} self.imageGItem = QGraphicsItemGroup() self.scene.addItem(self.imageGItem) self.updateImage(fnames) self.setBackgroundBrush(QBrush(Qt.darkCyan)) def updateImage(self, fnames): """Update the image with that from filename""" for n in self.images: self.imageGItem.removeFromGroup(self.images[n]) self.images[n].setVisible(False) if fnames is not None: x = 0 n = 0 for fn in fnames: self.images[n] = QGraphicsPixmapItem(QPixmap(fn)) self.images[n].setTransformationMode(Qt.SmoothTransformation) self.images[n].setPos(x, 0) self.images[n].setVisible(True) self.scene.addItem(self.images[n]) x += self.images[n].boundingRect().width() + 10 self.imageGItem.addToGroup(self.images[n]) n += 1 # Set sensible sizes and put into the view, and fit view to the image. br = self.imageGItem.boundingRect() self.scene.setSceneRect( 0, 0, max(1000, br.width()), max(1000, br.height()), ) self.setScene(self.scene) self.fitInView(self.imageGItem, Qt.KeepAspectRatio) def mouseReleaseEvent(self, event): """Left/right click to zoom in and out""" if (event.button() == Qt.RightButton) or ( QGuiApplication.queryKeyboardModifiers() == Qt.ShiftModifier): self.scale(0.8, 0.8) else: self.scale(1.25, 1.25) self.centerOn(event.pos()) def resetView(self): """Reset the view to its reasonable initial state.""" self.fitInView(self.imageGItem, Qt.KeepAspectRatio)
class TaxiRouteItem(QGraphicsItem): ''' Draws a set of edges that turn on/off together, each possibly labelled. Call prepareGeometryChange after building to initialise correctly. ''' def __init__(self, parentItem, segments, colour): QGraphicsItem.__init__(self, parent=parentItem) self.colour_name = colour self.shape = QPainterPath() self.labels = QGraphicsItemGroup(self) self.bbox = QRectF(0, 0, 0, 0) for (p1, p2), label in segments: lvect = QVector2D(p2 - p1) lpath = QPainterPath() m = TWY_line_margin l = lvect.length() plst = [QPointF(-m, 0), QPointF(-m/3, -m), QPointF(l + m/3, -m), QPointF(l + m, 0), QPointF(l + m/3, m), QPointF(-m/3, m)] lpath.addPolygon(QPolygonF(plst)) lrot = QTransform() lrot.rotateRadians(atan2(lvect.y(), lvect.x())) lpath = lrot.map(lpath) lpath.translate(p1) self.shape.addPath(lpath) rect = QRectF(p1, p2).normalized() if label != None: self.labels.addToGroup(TaxiwayLabelItem(label, rect.center(), self)) self.bbox |= rect self.shape.setFillRule(Qt.WindingFill) self.mouse_highlight = False self.labels.setVisible(False) def hoverEnterEvent(self, event): self.mouse_highlight = self.scene().mouseover_highlights_groundnet_edges if self.mouse_highlight and not self.labels.isVisible(): self.labels.setVisible(True) self.setVisible(False) self.setVisible(True) def hoverLeaveEvent(self, event): self.mouse_highlight = False self.labels.setVisible(self.scene().show_taxiway_names) self.setVisible(False) self.setVisible(True) def boundingRect(self): return withMargins(self.bbox, TWY_line_margin) def shape(self): return self.shape def paint(self, painter, option, widget): if self.mouse_highlight or self.scene().show_ground_networks: painter.setPen(QPen(Qt.NoPen)) brushcol = settings.colour(self.colour_name) brushcol.setAlpha(96 if self.mouse_highlight else 64) painter.setBrush(QBrush(brushcol)) painter.drawPath(self.shape)
def build_tiles_level(level, tile_size, slide_helper: SlideHelper): level_size = slide_helper.get_level_size(level) tiles_rects = slice_rect(level_size, tile_size) tiles_graphics_group = QGraphicsItemGroup() downsample = slide_helper.get_downsample_for_level(level) for tile_rect in tiles_rects: item = TileGraphicsItem(tile_rect, slide_helper.slide_path, level, downsample) item.moveBy(tile_rect[0], tile_rect[1]) tiles_graphics_group.addToGroup(item) return tiles_graphics_group
def __loadGraphicItem(self, shapes, images, condition_variables=None, default_color=Qt.blue): if not images: return ObjectGraphicsItem(shapes, color=default_color) gitem = QGraphicsItemGroup() for image in images: gitem.addToGroup( self.__loadGraphicItemImagePart(image, condition_variables)) return gitem
def addToGroup(self, item, name): ''' Määrittää saman ryhmänimen omaaville yhteisen ryhmän ja palauttaa sen ''' if name.strip() == 'None': return None elif name not in self.groups: group = QGraphicsItemGroup() self.piirtoalusta.scene.addItem(group) group.setFlag(QGraphicsItem.ItemIsSelectable) group.setFlag(QGraphicsItem.ItemIsMovable) group.addToGroup(item) self.groups.update({name: group}) else: group = self.groups[name] group.addToGroup(item)
def makeLines(self, image): # remove existing data on this layer self.removeOldGraphicsItems() group = QGraphicsItemGroup() sections = 4 coordinates = [] bounds = [ self.parent.region1Linify.value(), self.parent.region2Linify.value(), self.parent.region3Linify.value(), self.parent.region3Linify.value() ] for y in range(0, image.height(), 4): drawing = False for linetype in range(sections): if linetype >= 1: qt_y = y + linetype # / sections for x in range(image.width()): grayvalue = qGray(image.pixel(x, y)) start_drawing = (grayvalue < bounds[linetype]) and not drawing if start_drawing: coordinates.append([[x, qt_y]]) drawing = True stop_drawing = ((grayvalue >= bounds[linetype]) or (x == (image.width() - 1))) and drawing if stop_drawing: coordinates[-1].append([x, qt_y]) drawing = False group = QGraphicsItemGroup() for lineseg in coordinates: if len(lineseg) != 2 or len(lineseg[0]) != 2 or len( lineseg[1]) != 2: print("Unexpected lineseg: ", lineseg) else: lineitem = QGraphicsLineItem(lineseg[0][0], lineseg[0][1], lineseg[1][0], lineseg[1][1]) pen = QPen() pen.setWidth(1 / sections) lineitem.setPen(pen) group.addToGroup(lineitem) self.addNewGraphicsItems(group)
def paint_screenshot_image( painter: QPainter, scene: QGraphicsScene, image_size: QSize, scene_rect: QRectF = QRectF(), transparent_background=False, ) -> QImage: # with elapsed_timer() as elapsed: painter.fillRect(QRect(QPoint(0, 0), image_size), painter.background().color()) scene_items = scene.items(scene_rect, Qt.IntersectsItemBoundingRect) only_leaf_items = [ item for item in scene_items if len(item.childItems()) == 0 ] item_parents = {} item_groups = {} for item in only_leaf_items: if item.group(): item_groups[item] = item.group() item.group().setVisible(False) elif item.parentItem(): item_parents[item] = item.parentItem() item.parentItem().setVisible(False) group_for_screenshot = QGraphicsItemGroup() for item in only_leaf_items: group_for_screenshot.addToGroup(item) scene.addItem(group_for_screenshot) group_for_screenshot.setVisible(True) # scene_items2 = scene.items(scene_rect, Qt.IntersectsItemBoundingRect) # print(scene_items2) # print("before render==========================================") rendered_size = scene_rect.size().scaled(QSizeF(image_size), Qt.KeepAspectRatio) dsize = QSizeF(image_size) - rendered_size top_left = QPointF(dsize.width() / 2, dsize.height() / 2) scene.render(painter, QRectF(top_left, rendered_size), scene_rect, Qt.KeepAspectRatio) scene.destroyItemGroup(group_for_screenshot) for item in item_parents: parent = item_parents[item] item.setParentItem(parent) parent.setVisible(True) for item in item_groups: group = item_groups[item] group.addToGroup(item) group.setVisible(True)
def hatchify(self, image): """ actual calculations :param image: bitmap to squigglify :return: """ #print("image width = {0}, image height = {1}".format(image.width(), image.height())) ctimage = ImageOps.autocontrast( qimage_to_pil_image(image).convert("L"), 10) draw_contours = self.parent.includeContoursHatchify.checkState( ) == Qt.Checked draw_hatch = self.parent.includeHatchingHatchify.checkState( ) == Qt.Checked contour_simplify = self.parent.contourSimplificationHatchify.value() hatch_size = self.parent.hatchSizeHatchify.value() resolution = image.width() w, h = image.width(), image.height() aspect_ratio = h / w lines = [] inv_resize_factor = (1, 1) if draw_contours: lines += self.getcontours(ctimage, contour_simplify) if draw_hatch: lines += self.hatch(ctimage, hatch_size) lines = self.sortlines(lines) self.removeOldGraphicsItems() group = QGraphicsItemGroup() for line in lines: path = QPainterPath() for point_idx, point in enumerate(line): if point_idx == 0: path.moveTo(point[0], point[1]) else: path.lineTo(point[0], point[1]) item = QGraphicsPathItem(path) group.addToGroup(item) self.addNewGraphicsItems(group)
def on_actGroup_triggered(self): # 组合 cnt = len(self.scene.selectedItems()) if cnt > 1: # group=self.scene.createItemGroup(self.scene.selectedItems()) group = QGraphicsItemGroup() # 创建组合 self.scene.addItem(group) # 组合添加到场景中 for i in range(0, cnt): item = self.scene.selectedItems()[0] item.setSelected(False) # 清除选择虚线框 item.clearFocus() group.addToGroup(item) # 添加到组合 group.setFlags(QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsFocusable) self.view.frontZ = self.view.frontZ + 1 group.setZValue(self.view.frontZ) # group.clearFocus() self.scene.clearSelection() group.setSelected(True)
def on_qAction8_triggered(self): # 组合 items = self.scene.selectedItems() cnt = len(items) if cnt <= 1: return group = QGraphicsItemGroup() self.scene.addItem(group) for i in range(cnt): item = items[i] item.setSelected(False) item.clearFocus() group.addToGroup(item) group.setFlag(QGraphicsItem.ItemIsFocusable) group.setFlag(QGraphicsItem.ItemIsMovable) group.setFlag(QGraphicsItem.ItemIsSelectable) self.__frontZ += 1 group.setZValue(self.__frontZ) self.scene.clearSelection() group.setSelected(True)
def on_actGroup_triggered(self): items=self.scene.selectedItems() # QGraphicsItem的列表 cnt=len(items) #选中的图形项个数 if (cnt<=1): return group =QGraphicsItemGroup() #创建组合 self.scene.addItem(group) #组合添加到场景中 for i in range(cnt): item=items[i] item.setSelected(False) #清除选择虚线框 item.clearFocus() group.addToGroup(item) #添加到组合 group.setFlag(QGraphicsItem.ItemIsFocusable) group.setFlag(QGraphicsItem.ItemIsMovable) group.setFlag(QGraphicsItem.ItemIsSelectable) self.__frontZ=1+self.__frontZ group.setZValue(self.__frontZ) self.scene.clearSelection() group.setSelected(True)
def addCircle(self, index, points, r): (x, y) = points circleItem = QGraphicsEllipseItem(x - r, y - r, 2 * r, 2 * r) circleItem.setPen(self.pen) # self.scene.addItem(circleItem) #横线 line1 = QGraphicsLineItem() line1.setPen(self.pen) line1.setLine(x - self.lineRadius, y, x + self.lineRadius, y) #竖线 line2 = QGraphicsLineItem() line2.setPen(self.pen) line2.setLine(x, y - self.lineRadius, x, y + self.lineRadius) #文字说明 text = QGraphicsTextItem() text.setDefaultTextColor(Qt.blue) text.setFont(self.font) text.setPlainText(str(self.names[index])) text.setPos(x, y) #放到组中 pointGroup = QGraphicsItemGroup() pointGroup.addToGroup(line1) pointGroup.addToGroup(line2) pointGroup.addToGroup(text) pointGroup.addToGroup(circleItem) #显示该点 self.scene.addItem(pointGroup) self.pointsItem.append(pointGroup)
class BoardGUI(QWidget): """cointain the graphical representation of the Board""" # ratio of bordersize compared to the size of one base square borderRatio = 0.8 baseRectRatio = 14 / 15 # 12/13 for normal ratio but looks weird stoneScale = 0.46 # siganl stoneClicked = pyqtSignal(tuple) def __init__(self, parent, game): super().__init__() self.initUI(game) def initUI(self, game): self.board = game.currentBoard self.game = game self.showCoords = True self.scene = QGraphicsScene() # grid containing coordinates for the scene self.grid = [] self.drawGrid() # initialize and set layout + view self.view = QGraphicsView(self.scene) self.view.setMouseTracking(True) self.view.setViewportUpdateMode(QGraphicsView.FullViewportUpdate) self.setMouseTracking(True) box = QHBoxLayout() box.addWidget(self.view) self.setLayout(box) # stones for all positions are created and listed in self.pos dict self.createPosition() self.makeCoords() # has to be called after drawGrid! def resizeEvent(self, e): self.view.fitInView(self.view.scene().sceneRect(), Qt.KeepAspectRatio) def boardWidth(self): """returns the max width fitting into widget""" width = self.contentsRect().width() * 0.95 height = self.contentsRect().height() * 0.95 return min(width, height * self.baseRectRatio) def boardHeight(self): """returns the max width fitting into widget """ return self.boardWidth() * (1 / self.baseRectRatio) def makeGrid(self): """ returns coords [[(x, y)]] for the Grid according to current window mesures """ # set scenesize to window size self.scene.setSceneRect(0, 0, self.boardWidth(), self.boardHeight()) denom = self.board.size + 2 * self.borderRatio baseWidth = self.boardWidth() / denom baseHeight = self.boardHeight() / denom leftOffset = 0.5 * baseWidth # (self.contentsRect().width()-self.boardWidth())/2 topOffset = 0 # (self.contentsRect().height()-self.boardHeight())/2 partionWidth = [ leftOffset + (self.borderRatio + x) * baseWidth for x in range(self.board.size) ] partionHeight = [ topOffset + (self.borderRatio + x) * baseHeight for x in range(self.board.size) ] grid = [[(x, y) for x in partionWidth] for y in partionHeight] self.grid = grid self.baseWidth = baseWidth def drawGrid(self): """draws the background grid""" self.makeGrid() for line in self.grid: self.scene.addLine(*line[0], *line[-1]) for (pointT, pointB) in zip(self.grid[0], self.grid[-1]): self.scene.addLine(*pointT, *pointB) self.drawHoshis() def makeCoords(self): """ draws Coordinates """ xLabels = "ABCDEFGHIKLMNOPQRSTUVWXYZ" yLabels = list(range(1, 26)) botGrid = [] leftGrid = [] # generate pixel coordinates grids for n in range(self.board.size): (xBot, yBot) = self.grid[self.board.size - 1][n] yBot += self.baseWidth * 0.4 / self.baseRectRatio xBot -= self.baseWidth * 0.1 botGrid.append((xBot, yBot)) (xLeft, yLeft) = self.grid[n][0] xLeft -= self.baseWidth * 1.2 yLeft -= self.baseWidth * 0.3 / self.baseRectRatio leftGrid.append((xLeft, yLeft)) # generate Text items and add them to group self.coordGroup = QGraphicsItemGroup() for n in range(self.board.size): leftText = QGraphicsSimpleTextItem(str(yLabels[n])) leftText.setPos(*leftGrid[n]) self.coordGroup.addToGroup(leftText) bottomText = QGraphicsSimpleTextItem(xLabels[n]) bottomText.setPos(*botGrid[n]) self.coordGroup.addToGroup(bottomText) # draw coordinates and update visibility according to self.showCoords self.scene.addItem(self.coordGroup) self.updateCoords() def updateCoords(self): """ slot that updates the visibility os the coordiantes. """ self.coordGroup.setVisible(self.showCoords) def setCoordVis(self, visibility): """ set the self.showCoords boolean """ self.showCoords = visibility self.updateCoords() def drawHoshis(self): """ Draws Hoshi dots""" hoshis = [] rad = self.baseWidth * 0.15 for (x, y) in self.board.getHoshis(): hoshis.append(self.grid[x][y]) for point in hoshis: (x, y) = point self.scene.addEllipse(x - rad, y - rad, rad * 2.0, rad * 2.0, QPen(), QBrush(Qt.SolidPattern)) def updatePosition(self): """ sets the colors for all stones in self.pos according to the status in self.board """ for (x, y) in self.pos: color = self.game.currentBoard.getPosition(x, y) self.pos[(x, y)].setMark(None) self.pos[(x, y)].setColor(color) lastMove = self.game.currentBoard.lastMove if lastMove: self.pos[lastMove].setMark(GoMarks.circel) ko = self.game.currentBoard.ko if ko: self.pos[ko].setMark(GoMarks.square) def createPosition(self): """ Creates the self.pos dictionary containing all possible stones on the board initialized as empty stones also connects a signal form each stone to ??? """ self.pos = {} radius = self.stoneScale * self.baseWidth for row in range(self.board.size): for col in range(self.board.size): (x, y) = self.grid[row][col] newStone = Stone(x, y, radius) self.pos[(row, col)] = newStone self.scene.addItem(newStone) self.updatePosition() self.connecting() def connecting(self): for key in self.pos: self.pos[key].clicked.connect(lambda key=key: self.resend(key)) def resend(self, pos): """ emits the captured signal again, with (int, in) parameter for stone clicked """ self.stoneClicked.emit(pos)
class Ui_MainWindow(QtWidgets.QMainWindow, Ui_MainWindowBase): def __init__(self): super(Ui_MainWindow, self).__init__() self.setupUi(self) self.videoPlaybackInit() self.imgInit() self.menuInit() self.df = None self.trackingPathGroup = None self.drawingFlag = False self.handInputSystem = None self.handInputSystem = HandInputSystem() self.handInputSystem.setRect(self.inputScene.sceneRect()) self.inputScene.addItem(self.handInputSystem) self.handInputSystem.addNewDataFrame() self.currentFrameNo = 0 self.colors = [] self.circleCheckBox.stateChanged.connect(self.polyLineCheckBoxStateChanged) self.lineCheckBox.stateChanged.connect(self.polyLineCheckBoxStateChanged) self.overlayCheckBox.stateChanged.connect(self.overlayCheckBoxStateChanged) self.radiusSpinBox.valueChanged.connect(self.radiusSpinBoxValueChanged) self.frameNoSpinBox.valueChanged.connect(self.frameNoSpinBoxValueChanged) self.groupBox_2.hide() self.inputGraphicsView.viewport().setCursor(QtCore.Qt.ArrowCursor) # self.optionViewButton.pressed.connect(self.optionViewButtonPressed) self.zoomedGraphicsView.hide() self.dataFrameWidget.dataFrameChanged.connect(self.dataFrameChanged) self.dataFrameWidget.hide() self.handInputSystem.setColor(self.dataFrameWidget.getColor()) #self.processDropedFile("/Users/ymnk/temp/Dast/2016/01/hoge.avi") #self.processDropedFile("./a.csv") def dataFrameChanged(self,addedFrameFlag,editingNo,color): if addedFrameFlag: self.handInputSystem.addNewDataFrame() self.handInputSystem.setEditingNo(editingNo) self.handInputSystem.setColor(color) print(addedFrameFlag,color,editingNo) def optionViewButtonPressed(self): if self.groupBox_2.isVisible(): self.optionViewButton.setText("<") self.groupBox_2.hide() else: self.optionViewButton.setText(">") self.groupBox_2.show() def overlayCheckBoxStateChanged(self, s): if self.overlayCheckBox.isChecked(): self.frameBufferItemGroup.show() else: self.frameBufferItemGroup.hide() self.updateInputGraphicsView() def polyLineCheckBoxStateChanged(self, s): overlayFrameNo = self.frameNoSpinBox.value() min_value = max(self.currentFrameNo-overlayFrameNo,0) current_pos = self.currentFrameNo - min_value if self.handInputSystem is not None: self.handInputSystem.setDrawItem(current_pos, self.circleCheckBox.isChecked()) self.handInputSystem.setDrawLine(self.lineCheckBox.isChecked()) self.updateInputGraphicsView() def radiusSpinBoxValueChanged(self, value): if self.handInputSystem is not None: self.handInputSystem.setRadius(self.radiusSpinBox.value()) self.updateInputGraphicsView() def frameNoSpinBoxValueChanged(self, value): if self.handInputSystem is not None: self.handInputSystem.setOverlayFrameNo(self.frameNoSpinBox.value()) self.updateInputGraphicsView() def dragEnterEvent(self,event): event.acceptProposedAction() def dropEvent(self,event): # event.setDropAction(QtCore.Qt.MoveAction) mime = event.mimeData() if mime.hasUrls(): urls = mime.urls() if len(urls) > 0: self.processDropedFile(urls[0].toLocalFile()) event.acceptProposedAction() def processDropedFile(self,filePath): root,ext = os.path.splitext(filePath) if ext == ".filter": # Read Filter self.openFilterFile(filePath=filePath) return elif ext == ".csv": self.openCSVFile(filePath=filePath) elif self.openImageFile(filePath=filePath): return elif self.openVideoFile(filePath=filePath): return def videoPlaybackInit(self): self.videoPlaybackWidget.hide() self.videoPlaybackWidget.frameChanged.connect(self.setFrame, Qt.QueuedConnection) def setFrame(self, frame, frameNo): if frame is not None: self.cv_img = frame self.currentFrameNo = frameNo self.updateInputGraphicsView() if self.videoInitialFlag == True: self.graphicsViewResized() self.videoInitialFlag = False self.evaluate() def imgInit(self): self.cv_img = cv2.imread(os.path.join(sampleDataPath,"color_filter_test.png")) self.frameBuffer = Queue() self.frameBufferItemGroup = QGraphicsItemGroup() self.frameBufferItemGroup.hide() self.inputPixmapRenderScene = QGraphicsScene() self.inputPixmapRenderScene.addItem(self.frameBufferItemGroup) self.inputScene = QGraphicsScene() self.inputGraphicsView.setScene(self.inputScene) self.inputGraphicsView.resizeEvent = self.graphicsViewResized # self.inputScene.addItem(self.frameBufferItemGroup) qimg = misc.cvMatToQImage(self.cv_img) self.inputPixmap = QPixmap.fromImage(qimg) self.inputPixmapItem = QGraphicsPixmapItem(self.inputPixmap) self.inputScene.addItem(self.inputPixmapItem) self.inputGraphicsView.mousePressEvent = self.inputGraphicsViewMousePressEvent self.inputGraphicsView.mouseMoveEvent = self.inputGraphicsViewMouseMoveEvent self.inputGraphicsView.mouseReleaseEvent = self.inputGraphicsViewMouseReleaseEvent self.inputGraphicsView.keyPressEvent = self.inputGraphicsViewKeyPressEvent self.inputGraphicsView.keyReleaseEvent = self.inputGraphicsViewKeyReleaseEvent self.inputGraphicsView.wheelEvent = self.inputGraphicsViewwheelEvent #self.inputGraphicsView.focusInEvent = self.inputGraphicsViewfocusInEvent self.inputGraphicsView.viewport().installEventFilter(self) self.inputGraphicsView.setMouseTracking(True) self.overlayScene = QGraphicsScene() self.inputGraphicsView.setOverlayScene(self.overlayScene) def inputGraphicsViewfocusInEvent(self,event): # QGraphicsView.focusInEvent(self.inputGraphicsView, event) def inputGraphicsViewMousePressEvent(self, event): if event.modifiers() == QtCore.Qt.ShiftModifier: # Comment out to permit the view for sending the event to the child scene. QGraphicsView.mousePressEvent(self.inputGraphicsView, event) else: self.drawingFlag = True if not self.videoPlaybackWidget.isPlaying(): self.videoPlaybackWidget.playButtonClicked() def inputGraphicsViewMouseMoveEvent(self, event): if event.modifiers() == QtCore.Qt.ShiftModifier: # Comment out to permit the view for sending the event to the child scene. QGraphicsView.mouseMoveEvent(self.inputGraphicsView, event) elif self.drawingFlag == True: pass #self.videoPlaybackWidget.moveNextButtonClicked() #self.handInputSystem.inputMouseMoveEvent(mousePosition,self.currentFrameNo) #print(self.currentFrameNo) #self.positionStack.append(mousePosition) #self.handInputSystem.inputMouseMoveEvent(mousePosition) def inputGraphicsViewMouseReleaseEvent(self, event): if self.drawingFlag == True: self.drawingFlag = False self.videoPlaybackWidget.playButtonClicked() self.handInputSystem.inputMouseReleaseEvent() self.handInputSystem.setPoints() # Comment out to permit the view for sending the event to the child scene. QGraphicsView.mouseReleaseEvent(self.inputGraphicsView, event) self.inputGraphicsView.viewport().setCursor(QtCore.Qt.ArrowCursor) def inputGraphicsViewKeyPressEvent(self,event): mousePosition = QCursor().pos() mousePosition = self.inputGraphicsView.mapFromGlobal(mousePosition) if event.type() == QtCore.QEvent.KeyPress: key = event.key() if key == QtCore.Qt.Key_Space: self.videoPlaybackWidget.playButtonClicked() elif key == QtCore.Qt.Key_A: self.videoPlaybackWidget.movePrevButtonClicked() elif key == QtCore.Qt.Key_D: self.videoPlaybackWidget.moveNextButtonClicked() elif key == QtCore.Qt.Key_Down: self.inputGraphicsViewScaleDown() elif key == QtCore.Qt.Key_Up: self.inputGraphicsViewScaleUp() pass elif key == QtCore.Qt.Key_R: self.graphicsViewResized() elif key == QtCore.Qt.Key_P: pass #self.handInputSystem.nextDataFrame() elif key == QtCore.Qt.Key_O: pass #self.handInputSystem.previousDataFrame() elif key == QtCore.Qt.Key_J: frameNo = self.handInputSystem.getLastInputedFrameIndex() self.videoPlaybackWidget.moveToFrame(frameNo) elif key == QtCore.Qt.Key_S: self.handInputSystem.saveCSV("./a.csv") QGraphicsView.keyPressEvent(self.inputGraphicsView, event) def inputGraphicsViewKeyReleaseEvent(self,event): QGraphicsView.keyReleaseEvent(self.inputGraphicsView, event) def inputGraphicsViewwheelEvent(self,event): scaleFactor = 1.15 if event.delta() > 0: # Zoom in self.inputGraphicsView.scale(scaleFactor, scaleFactor) else: # Zooming out self.inputGraphicsView.scale(1.0 / scaleFactor, 1.0 / scaleFactor) QGraphicsView.wheelEvent(self.inputGraphicsView, event) def inputGraphicsViewScaleDown(self): scaleFactor = 1.15 self.inputGraphicsView.scale(1.0 / scaleFactor, 1.0 / scaleFactor) def inputGraphicsViewScaleUp(self): scaleFactor = 1.15 self.inputGraphicsView.scale(scaleFactor, scaleFactor) def menuInit(self): self.actionSaveCSVFile.triggered.connect(self.saveCSVFile) self.actionOpenCSVFile.triggered.connect(self.openCSVFile) 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 ret = self.videoPlaybackWidget.openVideo(filePath) if ret == False: return False self.videoInitialFlag = True self.videoPlaybackWidget.show() self.dataFrameWidget.show() # self.evaluate() return True else: return False 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.videoPlaybackWidget.hide() self.updateInputGraphicsView() self.evaluate() return True else: return False def openCSVFile(self, activated=False, filePath=None): if filePath is None: filePath, _ = QFileDialog.getOpenFileName(None, 'Open CSV File', userDir, 'CSV files (*.csv)') if len(filePath) is not 0: self.df = pd.read_csv(filePath, index_col=0) if self.handInputSystem is not None: self.inputScene.removeItem(self.handInputSystem) self.handInputSystem = HandInputSystem() self.handInputSystem.setRect(self.inputScene.sceneRect()) self.inputScene.addItem(self.handInputSystem) self.handInputSystem.setDataFrame(self.df) self.handInputSystem.setPoints() self.dataFrameWidget.clear() self.dataFrameWidget.dataFrameNo = self.handInputSystem.dataFrameNo self.dataFrameWidget.editingNo = 0 for item in range(self.handInputSystem.dataFrameNo+1): color = self.handInputSystem.itemList[item].getColor() print(item,color) self.dataFrameWidget.colorList.append(color) self.dataFrameWidget.setUniqueIDLabel() self.evaluate() def saveCSVFile(self, activated=False, filePath = None): #if self.df is not None: if self.handInputSystem.isDataFrame(): filePath, _ = QFileDialog.getSaveFileName(None, 'Save CSV File', userDir, "CSV files (*.csv)") if len(filePath) is not 0: logger.debug("Saving CSV file: {0}".format(filePath)) self.handInputSystem.saveCSV(filePath) def updateInputGraphicsView(self): # print("update") # self.inputScene.clear() self.inputScene.removeItem(self.inputPixmapItem) qimg = misc.cvMatToQImage(self.cv_img) self.inputPixmap = QPixmap.fromImage(qimg) p = QPainter(self.inputPixmap) sourceRect = self.inputPixmapRenderScene.sceneRect() self.inputPixmapRenderScene.render(p, QRectF(sourceRect), QRectF(sourceRect), QtCore.Qt.IgnoreAspectRatio) self.inputPixmapItem = QGraphicsPixmapItem(self.inputPixmap) rect = QtCore.QRectF(self.inputPixmap.rect()) self.inputScene.setSceneRect(rect) self.inputScene.addItem(self.inputPixmapItem) self.inputGraphicsView.viewport().update() # self.graphicsViewResized() def eventFilter(self, obj, event): if obj is self.inputGraphicsView.viewport() and event.type()==QEvent.Wheel: return True else: return False def graphicsViewResized(self, event=None): # print("resize") # print(self.inputScene) self.inputGraphicsView.fitInView(QtCore.QRectF(self.inputPixmap.rect()), QtCore.Qt.KeepAspectRatio) def evaluate(self): if not self.videoPlaybackWidget.isOpened(): return qimg = misc.cvMatToQImage(self.cv_img) pixmapItem = QGraphicsPixmapItem(QPixmap.fromImage(qimg)) pixmapItem.setOpacity(0.2) self.frameBuffer.put(pixmapItem) self.frameBufferItemGroup.addToGroup(pixmapItem) if self.frameBuffer.qsize() > 10: item = self.frameBuffer.get() self.frameBufferItemGroup.removeFromGroup(item) """ if self.trackingPathGroup is not None: self.trackingPathGroup.setPoints(self.currentFrameNo) """ if self.handInputSystem is not None: self.handInputSystem.setPoints(self.currentFrameNo) if self.drawingFlag is True: mousePosition = QCursor().pos() mousePosition = self.inputGraphicsView.mapFromGlobal(mousePosition) mousePosition = self.inputGraphicsView.mapToScene(mousePosition) pos = [mousePosition.x(),mousePosition.y()] self.handInputSystem.appendPosition(pos,self.currentFrameNo)
class AMANDisplay(QGraphicsView): def __init__(self): super(AMANDisplay, self).__init__() self.setGeometry(0, 0, 500, 600) self.setStyleSheet("background-color:#233370") self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.scene = QGraphicsScene(0, 0, 500, 600) # Timeline boundaries pen = QPen(QColor("white")) brush = QBrush(QColor("#233370")) self.scene.addLine(220, 0, 220, 600, pen) self.scene.addLine(280, 0, 280, 600, pen) self.scene.addLine(0, 30, 500, 30, pen) timelinebox = self.scene.addRect(220, 30, 60, 540, pen, brush) timelinebox.setFlag(timelinebox.ItemClipsChildrenToShape, True) # Timeline scale self.timeline = QGraphicsItemGroup() self.timeline.setParentItem(timelinebox) self.timeticks = [] for i in range(40): y = 15 * i w = 6 if i % 5 == 0: w = 10 self.timeticks.append(self.scene.addText("%02d" % (40 - i), QFont("Courier", 10))) self.timeticks[-1].setPos(240, y - 10) self.timeticks[-1].setDefaultTextColor(QColor("white")) self.timeline.addToGroup(self.timeticks[-1]) self.timeline.addToGroup(self.scene.addLine(220, y, 220 + w, y, pen)) self.timeline.addToGroup(self.scene.addLine(280 - w, y, 280, y, pen)) self.lrwy = self.scene.addText("18R", QFont("Arial", 20, 50)) self.lrwy.setPos(1, 1) self.lrwy.setDefaultTextColor(QColor("white")) # Finalize self.setScene(self.scene) self.show() def update(self, simt, data): # data has: ids, iafs, eats, etas, delays, rwys, spdratios # First delete old labels for (key,) in self.aircraft.keys: if key not in data.ids: # del label del self.aircraft[key] for i in len(data.ids): if data.ids[i] not in self.aircraft: # self.aircraft[data.ids[i]] = QLabel() pass # Generate the new label text and position newtext = "<font color=Red>bla</font>" # veranderen lbl = self.aircraft[data.ids[i]] lbl.setText(newtext) lbl.move(posx, posy) # move in pixels
def makeBubbles(self, image): """ helper method for bubblification (contains the actual calculations) :param image: :return: """ self.parent.progressBarBubblify.setVisible(True) self.parent.application.processEvents() minBrightness = self.parent.minBrightnessBubblify.value() maxBrightness = self.parent.maxBrightnessBubblify.value() minCircleRadius = self.parent.minRadiusBubblify.value() maxCircleRadius = self.parent.maxRadiusBubblify.value() invertColors = self.parent.invertColorsBubblify.checkState( ) == Qt.Checked minProbability = self.parent.minProbabilityBubblify.value() maxProbablity = self.parent.maxProbabilityBubblify.value() radiustolerance = self.parent.radiusToleranceBubblify.value() strokeWidth = 1 # remove existing data on this layer self.removeOldGraphicsItems() # first add seeding points print("Seeding points") spots = [] circles = [] for x in range(image.width()): for y in range(image.height()): grayvalue = qGray(image.pixel(x, y)) if invertColors: grayvalue = 255 - grayvalue if minBrightness < grayvalue < maxBrightness: probability = Mapping.linexp(grayvalue, 0, 255, maxProbablity / 100, minProbability / 100) addNow = random() < probability if addNow: spots.append([x, y]) print("Optimizing {0} points".format(len(spots))) # next find out radii we can use that avoid overlap print("Analyzing radii") if len(spots): tree = spatial.KDTree(spots) for center in spots: x = center[0] y = center[1] grayvalue = qGray(image.pixel(x, y)) proposed_radius = Mapping.linexp(grayvalue, minBrightness, maxBrightness, minCircleRadius, maxCircleRadius) nearest_neighbor = tree.query(np.array([[x, y]]), 2) # print("{0} nearest to {1}".format(nearest_neighbor, [x,y])) if nearest_neighbor: try: distance = nearest_neighbor[0][0][1] maxradius = np.floor(distance / 2) minimum = min(proposed_radius, maxradius) # print("Using minimum of proposed {0} and max {1}".format(proposed_radius, maxradius)) if minimum >= proposed_radius * radiustolerance: circles.append((x, y, minimum)) except: print("weird nearest neighbor: ", nearest_neighbor) print("Visualize") # next, visualize group = QGraphicsItemGroup() for c in circles: x = c[0] y = c[1] r = c[2] item = QGraphicsEllipseItem(x - r, y - r, r * 2, r * 2) pen = QPen() pen.setWidth(strokeWidth) item.setPen(pen) group.addToGroup(item) self.addNewGraphicsItems(group) self.parent.progressBarBubblify.setVisible(False)
class CursorGraphicsView(QGraphicsView): coords = None def __init__(self, *__args): super().__init__(*__args) self.num = -1 self.scale = QPointF(1, 1) def mouseReleaseEvent(self, event): if not self.scene(): return # the event's position is relative to the CursorGraphicsView, but we need it relative to the image pos_x = event.x() - (self.width() - self.scene().width() - 1) / 2 pos_y = event.y() - (self.height() - self.scene().height() - 1) / 2 # if the position of the click event is on the image, we convert the pixel position on screen to a voxel # position in the image, and then update all CursorGraphicsViews to show the corresponding slice as well as a # cursor pointing at the clicked voxel if pos_x >= 0 and pos_x < self.scene().width( ) and pos_y >= 0 and pos_y < self.scene().height(): slider_values = [ floor(pos_x / self.scale.x()), floor((self.scene().height() - pos_y) / self.scale.y()) ] CursorGraphicsView.coords = self.get_coords(slider_values) for i, slider in enumerate(self.sliders): slider.setValue(self.coords[i]) for viewer in self.viewers: viewer.show_cursor(self.coords) def set_num(self, num: int): self.num = num def set_scale(self, scale: float): self.scale = scale def set_viewers(self, viewers): self.viewers = viewers def set_sliders(self, sliders): self.sliders = sliders def get_coords(self, pos): return [(s.value() if i == self.num else pos.pop(0)) for i, s in enumerate(self.sliders)] def make_cursor(self): pen = QPen(QColor(0, 255, 0)) h_line = QGraphicsLineItem(-10, 0, 10, 0) v_line = QGraphicsLineItem(0, -10, 0, 10) pen.setWidth(1) h_line.setPen(pen) v_line.setPen(pen) self.point_cursor = QGraphicsItemGroup() self.point_cursor.addToGroup(h_line) self.point_cursor.addToGroup(v_line) self.point_cursor.setZValue(1) self.point_cursor.setVisible(False) self.scene().addItem(self.point_cursor) def show_cursor(self, values): pos = values.copy() pos.pop(self.num) self.point_cursor.setVisible(True) self.point_cursor.setPos( pos[0] * self.scale.x(), self.scene().height() - pos[1] * self.scale.y())
class CircleMethod(object): """ class to represent how an lsystem overlayed on a bitmap is converted to a list of circles """ def __init__(self, minBrightness, maxBrightness, minRadius, maxRadius, minStepSize, maxStepSize, clipToBitmap, strokeWidth, imageWidth, imageHeight): self.group = QGraphicsItemGroup() self.minBrightness = minBrightness self.maxBrightness = maxBrightness self.minRadius = minRadius self.maxRadius = maxRadius self.minStepSize = minStepSize self.maxStepSize = maxStepSize self.clipToBitmap = clipToBitmap self.strokeWidth = strokeWidth self.width = imageWidth self.height = imageHeight def step(self, x, y, direction, brightness): """ step is called many times while iterating over the loaded bitmap in each step we calculate a circle based on position x,y with given brightness in the bitmap. direction is a direction vector indicating what direction we are moving in. calculate a new circle in the circle generation process :param x: x pos in bitmap that calculation should be based on :param y: y pos in bitmap that calculation should be based on :param direction: in what direction are we moving? :param brightness: gray value in the bitmap at x,y :return: potentially modified step size """ r = Mapping.linexp(brightness, self.minBrightness, self.maxBrightness, self.maxRadius, self.minRadius) if not r: r = self.minRadius stepsize = int( Mapping.linlin(brightness, self.minBrightness, self.maxBrightness, self.minStepSize, self.maxStepSize)) if not self.clipToBitmap or (self.clipToBitmap and not Circle( x, y, r).edges(self.width, self.height)): item = QGraphicsEllipseItem(x - r, y - r, r * 2, r * 2) pen = QPen() pen.setWidth(self.strokeWidth) item.setPen(pen) self.group.addToGroup(item) return max(int(stepsize), 1) def skip(self, x, y, direction, brightness): """ similar to step, but explicitly asking to skip generation of a circle (e.g. because brightness constraints are not met) this allows the method to update its internal state to keep track of what is happening :param x: x pos in bitmap that the calculation should be based on :param y: x pos in bitmap that the calculation should be based on :param direction: direction we were moving in :param brightness: gray value of x,y in bitmap :return: potentially modified step size """ stepsize = int( Mapping.linlin(brightness, self.minBrightness, self.maxBrightness, self.minStepSize, self.maxStepSize)) return max(int(stepsize), 1) def finish(self): """ return the wrapped up result of the calculations :return: qgraphicsitemgroup """ return self.group
def randomWalk(self, image): """ actual calculations :param image: bitmap to squigglify :return: """ self.removeOldGraphicsItems() group = QGraphicsItemGroup() no_of_walks = self.parent.noOfWalksWalkify.value() coordinates = {} self.applyThreshold(image) for w in range(no_of_walks): x, y = self.find_darkest(image) x, y, color = self.find_darkest_neighbor(image, x, y) coordinates[w] = np.array([[x, y]]) no_of_line_segments = self.parent.noOfLineSegmentsWalkify.value() adjustbrightness = self.parent.localBrightnessAdjustmentWalkify.value( ) stroke_width = self.parent.lineWidthWalkify.value() for s in range(0, no_of_line_segments): dx, dy, dc = self.find_darkest_neighbor(image, x, y) self.lighten_area_around(image, adjustbrightness, dx, dy) x, y = dx, dy coordinates[w] = np.append(coordinates[w], [[x, y]], axis=0) for w in range(no_of_walks): coordinates[w] = simplify_coords( coordinates[w], self.parent.polylineSimplificationToleranceWalkify.value()) for w in range(no_of_walks): path = QPainterPath() in_the_middle_of_a_quad = False for idx, c in enumerate(coordinates[w]): quad = self.parent.useSmootherShapesWalkify.checkState( ) == Qt.Checked if not quad: if idx == 0: path.moveTo(coordinates[w][idx][0], coordinates[w][idx][1]) else: path.lineTo(coordinates[w][idx][0], coordinates[w][idx][1]) else: if idx == 0: path.moveTo(coordinates[w][idx][0], coordinates[w][idx][1]) elif idx % 2 == 1: middlex, middley = coordinates[w][idx][0], coordinates[ w][idx][1] in_the_middle_of_a_quad = True else: path.quadTo(middlex, middley, coordinates[w][idx][0], coordinates[w][idx][1]) in_the_middle_of_a_quad = False if in_the_middle_of_a_quad: path.lineTo(middlex, middley) item = QGraphicsPathItem(path) pen = QPen() pen.setWidth(stroke_width) item.setPen(pen) group.addToGroup(item) self.addNewGraphicsItems(group)
class SquiggleMethod(object): """ class to represent how to convert LSystem overlayed on bitmap to squiggles """ def __init__(self, minBrightness, maxBrightness, strength, detail, minStepSize, maxStepSize, clipToBitmap, strokeWidth, imageWidth, imageHeight): self.group = QGraphicsItemGroup() self.path = QPainterPath() self.minBrightness = minBrightness self.maxBrightness = maxBrightness self.strength = strength self.detail = detail self.minStepSize = minStepSize self.maxStepSize = maxStepSize self.clipToBitmap = clipToBitmap self.strokeWidth = strokeWidth self.width = imageWidth self.height = imageHeight self.prevPos = None self.disturbance_direction = 1 self.previous_stepsize = 1 def step(self, x, y, direction, brightness): """ step is called many times while iterating over the loaded bitmap in each step we calculate a squiggle based on position x,y with given brightness in the bitmap. direction is a direction vector indicating what direction we are moving in. calculate a new squiggle in the circle generation process :param x: x pos in bitmap that calculation should be based on :param y: y pos in bitmap that calculation should be based on :param direction: in what direction are we moving? :param brightness: gray value in the bitmap at x,y :return: potentially modified step size """ stepSize = Mapping.linexp(brightness, 0, 255, self.minStepSize, self.maxStepSize) stepSize = Mapping.linlin(stepSize, 1, 10, 1, 10 / self.detail) self.previous_stepsize = stepSize amplitudeSize = Mapping.linlin(brightness, 0, 255, self.strength, 0) if self.prevPos is None: self.path = QPainterPath() self.path.moveTo(x, y) self.prevPos = np.array([[ x, ], [ y, ]]) else: newPos = np.array([[ x, ], [ y, ]]) dirx = direction[0][0] diry = direction[1][0] ortho_dir = np.array([[-diry], [dirx] ]) * self.disturbance_direction disturbance = ortho_dir * amplitudeSize disturbedPos = (self.prevPos + newPos) / 2 + disturbance if not self.clipToBitmap or (self.clipToBitmap and not Circle( x, y, amplitudeSize).edges(self.width, self.height)): self.path.quadTo(disturbedPos[0][0], disturbedPos[1][0], newPos[0][0], newPos[1][0]) else: self.path.moveTo(newPos[0][0], newPos[1][0]) self.prevPos = newPos self.disturbance_direction = -self.disturbance_direction return max(int(stepSize), 1) def skip(self, x, y, direction, brightness): """ similar to step, but explicitly asking to skip generation of a squiggle (e.g. because brightness constraints are not met) this allows the method to update its internal state to keep track of what is happening :param x: x pos in bitmap that the calculation should be based on :param y: x pos in bitmap that the calculation should be based on :param direction: direction we were moving in :param brightness: gray value of x,y in bitmap :return: potentially modified step size """ if self.prevPos is None: self.path = QPainterPath() self.path.moveTo(x, y) else: self.path.moveTo(x, y) self.prevPos = np.array([[ x, ], [ y, ]]) return int(self.previous_stepsize) def finish(self): """ return the wrapped up result of the calculations :return: qgraphicsitemgroup """ item = QGraphicsPathItem(self.path) pen = QPen() pen.setWidth(self.strokeWidth) item.setPen(pen) self.group.addToGroup(item) self.prevPos = None return self.group
class Ui_MainWindow(QtWidgets.QMainWindow, Ui_MainWindowBase): def __init__(self): super(Ui_MainWindow, self).__init__() self.setupUi(self) self.videoPlaybackInit() self.imgInit() self.menuInit() self.df = {} self.trackingPathGroup = None self.movableArrowGroup = None self.line_data_dict = {} self.line_item_dict = {} self.file_name_dict = {} self.currentFrameNo = 0 self.colors = None self.overlayCheckBox.stateChanged.connect( self.overlayCheckBoxStateChanged) self.radiusSpinBox.valueChanged.connect(self.radiusSpinBoxValueChanged) self.frameNoSpinBox.valueChanged.connect( self.frameNoSpinBoxValueChanged) self.markDeltaSpinBox.valueChanged.connect( self.markDeltaSpinBoxValueChanged) def overlayCheckBoxStateChanged(self, s): if self.overlayCheckBox.isChecked(): self.frameBufferItemGroup.show() else: self.frameBufferItemGroup.hide() self.updateInputGraphicsView() def markDeltaSpinBoxValueChanged(self, value): if self.trackingPathGroup is not None: self.trackingPathGroup.setMarkDelta(self.markDeltaSpinBox.value()) self.updateInputGraphicsView() def radiusSpinBoxValueChanged(self, value): if self.trackingPathGroup is not None: self.trackingPathGroup.setRadius(self.radiusSpinBox.value()) self.updateInputGraphicsView() def frameNoSpinBoxValueChanged(self, value): if self.trackingPathGroup is not None: self.trackingPathGroup.setOverlayFrameNo( self.frameNoSpinBox.value()) self.updateInputGraphicsView() def dragEnterEvent(self, event): event.acceptProposedAction() def dropEvent(self, event): # event.setDropAction(QtCore.Qt.MoveAction) mime = event.mimeData() if mime.hasUrls(): urls = mime.urls() if len(urls) > 0: self.processDropedFile(urls[0].toLocalFile()) event.acceptProposedAction() def processDropedFile(self, filePath): root, ext = os.path.splitext(filePath) if ext == ".filter": # Read Filter self.openFilterFile(filePath=filePath) return elif ext == ".csv": self.openCSVFile(filePath=filePath) elif ext == ".json": self.openJSONFile(filePath=filePath) elif ext == ".color": self.openColorFile(filePath=filePath) elif self.openImageFile(filePath=filePath): return elif self.openVideoFile(filePath=filePath): return def videoPlaybackInit(self): self.videoPlaybackWidget.hide() self.videoPlaybackWidget.frameChanged.connect(self.setFrame, Qt.QueuedConnection) def setFrame(self, frame, frameNo): if frame is not None: self.cv_img = frame self.currentFrameNo = frameNo self.updateInputGraphicsView() self.evaluate() def imgInit(self): self.cv_img = cv2.imread( os.path.join(sampleDataPath, "color_filter_test.png")) self.frameBuffer = Queue() self.frameBufferItemGroup = QGraphicsItemGroup() self.frameBufferItemGroup.hide() self.inputPixmapRenderScene = QGraphicsScene() self.inputPixmapRenderScene.addItem(self.frameBufferItemGroup) self.inputScene = QGraphicsScene() self.inputGraphicsView.setScene(self.inputScene) self.inputGraphicsView.resizeEvent = self.graphicsViewResized # self.inputScene.addItem(self.frameBufferItemGroup) qimg = misc.cvMatToQImage(self.cv_img) self.inputPixmap = QPixmap.fromImage(qimg) self.inputPixmapItem = QGraphicsPixmapItem(self.inputPixmap) self.inputScene.addItem(self.inputPixmapItem) self.rubberBand = QtWidgets.QRubberBand( QtWidgets.QRubberBand.Rectangle, self.inputGraphicsView) self.inputGraphicsView.mousePressEvent = self.inputGraphicsViewMousePressEvent self.inputGraphicsView.mouseMoveEvent = self.inputGraphicsViewMouseMoveEvent self.inputGraphicsView.mouseReleaseEvent = self.inputGraphicsViewMouseReleaseEvent self.inputGraphicsView.viewport().installEventFilter(self) self.inputGraphicsView.setMouseTracking(True) self.overlayScene = QGraphicsScene() self.inputGraphicsView.setOverlayScene(self.overlayScene) self.zoomedGraphicsView.setScene(self.inputScene) self.zoomedGraphicsView.setOverlayScene(self.overlayScene) def inputGraphicsViewMousePressEvent(self, event): self.origin = QPoint(event.pos()) self.rubberBand.setGeometry(QtCore.QRect(self.origin, QtCore.QSize())) self.rubberBand.show() # Comment out to permit the view for sending the event to the child scene. # QGraphicsView.mousePressEvent(self.inputGraphicsView, event) def inputGraphicsViewMouseMoveEvent(self, event): if self.rubberBand.isVisible(): self.rubberBand.setGeometry( QtCore.QRect(self.origin, event.pos()).normalized()) # Comment out to permit the view for sending the event to the child scene. # QGraphicsView.mouseMoveEvent(self.inputGraphicsView, event) def inputGraphicsViewMouseReleaseEvent(self, event): if self.rubberBand.isVisible(): self.rubberBand.hide() rect = self.rubberBand.geometry() sceneRect = self.inputGraphicsView.mapToScene(rect).boundingRect() self.zoomedGraphicsView.fitInView(QRectF(sceneRect)) self.zoomedGraphicsView.viewport().update() # Comment out to permit the view for sending the event to the child scene. self.inputGraphicsView.viewport().update() # QGraphicsView.mouseReleaseEvent(self.inputGraphicsView, event) def menuInit(self): self.actionSaveDataFiles.triggered.connect(self.saveDataFiles) self.actionOpenCSVFile.triggered.connect(self.openCSVFile) self.actionOpenCSVFile.triggered.connect(self.openJSONFile) self.actionOpenCSVFile.triggered.connect(self.openJSONFile) self.actionPath.triggered.connect(self.actionPathTriggered) self.actionCircle.triggered.connect(self.actionCircleTriggered) self.actionIntervalMark.triggered.connect( self.actionIntervalMarkTriggered) self.actionShape.triggered.connect(self.actionShapeTriggered) self.actionSkeleton.triggered.connect(self.actionSkeletonTriggered) self.actionArrow.triggered.connect(self.actionArrowTriggered) self.actionChangeOrderOfNum.triggered.connect( self.actionChangeOrderOfNumTriggered) self.actionTrackingPathColor.triggered.connect( self.openTrackingPathColorSelectorDialog) def actionPathTriggered(self, checked): if self.trackingPathGroup is not None: self.trackingPathGroup.setDrawLine(checked) if not checked or self.actionIntervalMark.isChecked(): self.trackingPathGroup.setDrawMarkItem(checked) self.updateInputGraphicsView() def actionCircleTriggered(self, checked): if self.trackingPathGroup is not None: self.trackingPathGroup.setDrawItem(checked) self.updateInputGraphicsView() def actionIntervalMarkTriggered(self, checked): if self.trackingPathGroup is not None: self.trackingPathGroup.setDrawMarkItem(checked) self.updateInputGraphicsView() def actionShapeTriggered(self, checked): if 'shape' in self.line_item_dict.keys(): line_item = self.line_item_dict['shape'] if checked: line_item.show() else: line_item.hide() def actionSkeletonTriggered(self, checked): if 'skeleton' in self.line_item_dict.keys(): line_item = self.line_item_dict['skeleton'] if checked: line_item.show() else: line_item.hide() def actionArrowTriggered(self, checked): if self.movableArrowGroup is not None: if checked: self.movableArrowGroup.show() else: self.movableArrowGroup.hide() def actionChangeOrderOfNumTriggered(self, checked): if len(self.df.keys()) != 0 or len(self.line_data_dict.keys()) != 0: self.videoPlaybackWidget.stop() dialog = DataSwapDialog(self) dialog.setWindowModality(Qt.WindowModal) dialog.setData(self.df, self.line_data_dict) dialog.swapAccepted.connect(self.evaluate) res = dialog.exec() def openTrackingPathColorSelectorDialog(self, activated=False): if self.trackingPathGroup is not None: self.trackingPathGroup.openColorSelectorDialog(self) 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 ret = self.videoPlaybackWidget.openVideo(filePath) if ret == False: return False self.videoPlaybackWidget.show() self.cv_img = self.videoPlaybackWidget.getCurrentFrame() self.initialize() return True else: return False 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.videoPlaybackWidget.hide() self.updateInputGraphicsView() self.evaluate() return True else: return False def openCSVFile(self, activated=False, filePath=None): if filePath is None: filePath, _ = QFileDialog.getOpenFileName(None, 'Open CSV File', userDir, 'CSV files (*.csv)') if len(filePath) is not 0: df = pd.read_csv(filePath, index_col=0) name = df.index.name if name is None: name = 'position' self.df[name] = df self.file_name_dict[name] = filePath if name is None or name == 'position': if self.trackingPathGroup is not None: self.inputScene.removeItem(self.trackingPathGroup) self.trackingPathGroup = TrackingPathGroup() self.trackingPathGroup.setRect(self.inputScene.sceneRect()) self.inputScene.addItem(self.trackingPathGroup) self.trackingPathGroup.setDrawLine(self.actionPath.isChecked()) self.trackingPathGroup.setDrawItem( self.actionCircle.isChecked()) self.trackingPathGroup.setDrawMarkItem( self.actionIntervalMark.isChecked()) shape = self.df['position'].shape self.num_items = int(shape[1] / 2) index = (np.repeat(range(self.num_items), 2).tolist(), [0, 1] * self.num_items) self.df['position'].columns = pd.MultiIndex.from_tuples( tuple(zip(*index))) self.trackingPathGroup.setDataFrame(self.df['position']) delta = self.df['position'].index[1] - self.df[ 'position'].index[0] self.videoPlaybackWidget.setPlaybackDelta(delta) self.videoPlaybackWidget.setMaxTickableFrameNo( self.df['position'].index[-1]) elif name == 'arrow': if self.movableArrowGroup is not None: self.inputScene.removeItem(self.movableArrowGroup) self.movableArrowGroup = MovableArrowGroup() self.inputScene.addItem(self.movableArrowGroup) self.movableArrowGroup.edited.connect(self.arrowEdited) if not self.actionArrow.isChecked(): self.movableArrowGroup.hide() if 'arrow' in self.df.keys() and 'position' in self.df.keys(): self.movableArrowGroup.setDataFrame(self.df['arrow'], self.df['position']) self.initialize() def openColorFile(self, activated=False, filePath=None): if filePath is None: filePath, _ = QFileDialog.getOpenFileName(None, 'Open Color File', userDir, 'Color files (*.color)') if len(filePath) is not 0: self.colors = pd.read_csv(filePath, index_col=0).values.tolist() self.colors = [QColor(*rgb) for rgb in self.colors] self.setColorsToGraphicsObjects() def openJSONFile(self, activated=False, filePath=None): if filePath is None: filePath, _ = QFileDialog.getOpenFileName(None, 'Open JSON File', userDir, 'JSON files (*.json)') if len(filePath) is not 0: with open(filePath) as f_p: data = json.load(f_p) name = data['name'] self.line_data_dict[name] = data self.file_name_dict[name] = filePath if name in self.line_item_dict.keys(): self.inputScene.removeItem(self.line_item_dict[name]) lines = MovableLineGroup() lines.setData(data) lines.setRect(self.inputScene.sceneRect()) if name == 'shape' and not self.actionShape.isChecked(): lines.hide() if name == 'skeleton' and not self.actionSkeleton.isChecked(): lines.hide() self.line_item_dict[name] = lines self.inputScene.addItem(lines) self.initialize() def saveDataFiles(self, activated=False, filePath=None): if len(self.df.keys()) != 0: for k, v in self.df.items(): f_name, f_ext = os.path.splitext(self.file_name_dict[k]) candidate_file_path = '{0}-fixed{1}'.format(f_name, f_ext) filePath, _ = QFileDialog.getSaveFileName( None, 'Save CSV File', candidate_file_path, "CSV files (*.csv)") if len(filePath) is not 0: logger.debug("Saving CSV file: {0}".format(filePath)) df = v.copy() col_n = df.values.shape[1] / 2 col_names = np.array([('x{0}'.format(i), 'y{0}'.format(i)) for i in range(int(round(col_n))) ]).flatten() df.columns = pd.Index(col_names) df.index.name = k df.to_csv(filePath) for k, v in self.line_data_dict.items(): f_name, f_ext = os.path.splitext(self.file_name_dict[k]) candidate_file_path = '{0}-fixed{1}'.format(f_name, f_ext) filePath, _ = QFileDialog.getSaveFileName(None, 'Save JSON File', candidate_file_path, "JSON files (*.json)") if len(filePath) is not 0: logger.debug("Saving JSON file: {0}".format(filePath)) with open(filePath, 'w') as f_p: json.dump(v, f_p) def updateInputGraphicsView(self): self.inputScene.removeItem(self.inputPixmapItem) qimg = misc.cvMatToQImage(self.cv_img) self.inputPixmap = QPixmap.fromImage(qimg) p = QPainter(self.inputPixmap) sourceRect = self.inputPixmapRenderScene.sceneRect() self.inputPixmapRenderScene.render(p, QRectF(sourceRect), QRectF(sourceRect), QtCore.Qt.IgnoreAspectRatio) self.inputPixmapItem = QGraphicsPixmapItem(self.inputPixmap) rect = QtCore.QRectF(self.inputPixmap.rect()) self.inputScene.setSceneRect(rect) self.inputScene.addItem(self.inputPixmapItem) self.inputGraphicsView.viewport().update() self.graphicsViewResized() def eventFilter(self, obj, event): if event.type() == QEvent.Wheel: self.videoPlaybackWidget.wheelEvent(event) return True if event.type() == QEvent.KeyPress: if Qt.Key_Home <= event.key() <= Qt.Key_PageDown: self.videoPlaybackWidget.keyPressEvent(event) return True return False def graphicsViewResized(self, event=None): self.inputGraphicsView.fitInView( QtCore.QRectF(self.inputPixmap.rect()), QtCore.Qt.KeepAspectRatio) def setColorsToGraphicsObjects(self): # FIXME: データセットと色リストのサイズ整合性チェックが必要 if self.colors is not None: if self.trackingPathGroup is not None: self.trackingPathGroup.setColors(self.colors) for k, v in self.line_item_dict.items(): v.setColors(self.colors) def initialize(self): if not self.videoPlaybackWidget.isOpened(): return if self.trackingPathGroup is not None: r = self.trackingPathGroup.autoAdjustRadius(self.cv_img.shape) self.radiusSpinBox.setValue(r) self.trackingPathGroup.autoAdjustLineWidth(self.cv_img.shape) self.trackingPathGroup.setItemsAreMovable(True) if self.movableArrowGroup is not None: pass for k, v in self.line_item_dict.items(): v.autoAdjustLineWidth(self.cv_img.shape) v.autoAdjustMarkSize(self.cv_img.shape) self.setColorsToGraphicsObjects() self.evaluate() def evaluate(self): if not self.videoPlaybackWidget.isOpened(): return qimg = misc.cvMatToQImage(self.cv_img) pixmapItem = QGraphicsPixmapItem(QPixmap.fromImage(qimg)) pixmapItem.setOpacity(0.2) self.frameBuffer.put(pixmapItem) self.frameBufferItemGroup.addToGroup(pixmapItem) if self.frameBuffer.qsize() > 10: item = self.frameBuffer.get() self.frameBufferItemGroup.removeFromGroup(item) if self.trackingPathGroup is not None: self.trackingPathGroup.setPoints(self.currentFrameNo) if self.movableArrowGroup is not None: self.movableArrowGroup.setPositions(self.currentFrameNo) for k, v in self.line_item_dict.items(): v.setPolyline(self.currentFrameNo) @pyqtSlot(object) def arrowEdited(self, name): # TODO: 方向の再推定機能の実装 # quit_msg = "Arrow {} edited.\nRe-estimate the direction in following frames?".format(name) # reply = QtWidgets.QMessageBox.question( # self, # 'Question', # quit_msg, # QtWidgets.QMessageBox.Yes, # QtWidgets.QMessageBox.No # ) # # if reply == QtWidgets.QMessageBox.Yes: # pass # else: # pass pass
class NodeItem(QGraphicsItem): def __init__ (self, nodeobj, parent=None, view=None, state=1): super().__init__() self.edge = None self.linkIDs = None self.children = None self.childpos = None self.nodeobj = nodeobj self.style = FlGlob.mainwindow.style self.view = weakref.proxy(view) self.refID = parent.realid() if parent is not None else None self.state = state self.setrank(parent) self.setCursor(Qt.ArrowCursor) self.yoffset = 0 self.graphicsetup() self.setstate(state) def id (self): return (self.refID, self.nodeobj.ID) def realid (self): return self.nodeobj.ID def childlist (self, generate=False): ID = self.nodeobj.ID itemtable = self.view.itemtable if self.state == 1 and ID in itemtable and not self.iscollapsed(): if self.children and self.nodeobj.linkIDs == self.linkIDs and None not in [c() for c in self.children]: ret = self.children else: children = [] for child in self.nodeobj.linkIDs: if child in itemtable[ID]: item = itemtable[ID][child] else: continue children.append(weakref.ref(item)) self.linkIDs = self.nodeobj.linkIDs.copy() self.children = children ret = children else: ret = [] if generate: x = self.x() y = self.y() self.childpos = [] for target in ret: t = target() self.childpos.append((t.x()+t.boundingRect().left()-self.style.activemargin-x, t.y()-y)) if self.edge: if self.childpos != self.edge.childpos: self.edge.prepareGeometryChange() self.edge.sourceright = self.boundingRect().right() self.edge.update(self.edge.boundingRect()) return ret def setedge (self, edge): self.edge = edge edge.setX(self.x()) def setactive (self, active): if active: self.activebox.show() self.mainbox.setBrush(QBrush(self.altcolor)) else: self.activebox.hide() self.mainbox.setBrush(QBrush(self.maincolor)) def setselected (self, selected): if selected: self.selectbox.show() else: self.selectbox.hide() def setstate (self, state): self.state = state if state == 1: # normal self.show() self.graphgroup.setOpacity(1) self.shadowbox.show() elif state == 0: # ghost self.show() self.graphgroup.setOpacity(0.7) self.shadowbox.hide() elif state == -1: # hidden self.hide() def setplaymode (self, playmode): if playmode: self.setOpacity(0.5) else: self.setOpacity(1) def setY (self, y): parent = self.view.itembyID(self.refID) y += self.getyoffset() if self.edge is not None: self.edge.setY(y) super().setY(y) def setrank (self, parent): if parent is None: return if self.issubnode(): x = parent.x() self.setX(x) else: x = parent.x()+self.style.rankwidth self.setX(x) self.nudgechildren() if self.edge is not None: self.edge.setX(x) def nudgechildren (self): for child in self.childlist(): child().setrank(self) def getyoffset (self): if self.nodeobj.nodebank == -1: return self.yoffset else: return self.view.itembyID(self.refID).getyoffset() + self.yoffset def hide (self): super().hide() if self.edge: self.edge.hide() def show (self): super().show() if self.edge: self.edge.show() def issubnode (self): return self.nodeobj.nodebank is not -1 def isghost (self): return not self.state def realnode (self): return self.view.itembyID(self.nodeobj.ID) def isactive (self): return self.view.activenode is self def isselected (self): return self.view.selectednode is self def iscollapsed (self): return self.id() in self.view.collapsednodes def y_top (self): return self.y() - self.boundingRect().height()//2 def y_bottom (self): return self.y() + self.boundingRect().height()//2 def bulkshift (self, children, diff): self.setY(self.y() + diff) if children is None: children = [c() for c in self.childlist()] for child in children: child.bulkshift(None, diff) def treeposition (self, ranks=None): if ranks is None: ranks = dict() localranks = dict() children = [c() for c in self.childlist()] for child in children: localranks = child.treeposition(localranks) rank = self.x() // self.style.rankwidth if children: top = children[0].y_top() bottom = children[-1].y_bottom() self.setY((top+bottom)//2) localranks[rank] = [self.y_top, self.y_bottom] streeshift = None for r in localranks: if r in ranks: rankshift = ranks[r][1]() + self.style.rowgap - localranks[r][0]() if streeshift is None or rankshift > streeshift: streeshift = rankshift ranks[r][1] = localranks[r][1] else: ranks[r] = localranks[r] if streeshift: self.bulkshift(children, streeshift) return ranks def siblings (self): if self.refID is None: return None parent = self.view.nodecontainer.nodes[self.refID] if self.issubnode(): return parent.subnodes else: return parent.linkIDs def siblingabove (self): sibs = self.siblings() if sibs is None or self.nodeobj.ID not in sibs: return None myindex = sibs.index(self.nodeobj.ID) if myindex: sibID = (self.refID, sibs[myindex-1]) return self.view.itembyfullID(sibID) else: return None def siblingbelow (self): sibs = self.siblings() if sibs is None or self.nodeobj.ID not in sibs: return None myindex = sibs.index(self.nodeobj.ID) if len(sibs) > myindex+1: sibID = (self.refID, sibs[myindex+1]) return self.view.itembyfullID(sibID) else: return None def subtreesize (self, depth=-1): """Find vertical extents of a subtree. Returns min/max y coordinates up to given depth (negative depth means whole subtree).""" # calculate child positions for EgdeItem only once when calculating scenerect if depth<0: generate = True else: generate = False children = [c() for c in self.childlist(generate=generate)] maxdepth = abs(depth) if children and depth: nextdepth = depth-1 ymin = self.y_top() ymax = self.y_bottom() for child in children: top, bottom, depth = child.subtreesize(nextdepth) ymin = min(ymin, top) ymax = max(ymax, bottom) maxdepth = max(maxdepth, depth) else: ymin = self.y_top() ymax = self.y_bottom() return ymin, ymax, maxdepth def boundingRect (self): return self.rect def paint (self, painter, style, widget): pass def pixmap (self, path): return QPixmap(path).scaledToWidth(self.style.boldheight, Qt.SmoothTransformation) def graphicsetup (self): lightbrush = QBrush(FlPalette.light) mainbrush = QBrush(self.maincolor) altbrush = QBrush(self.altcolor) nopen = QPen(0) viewport = self.view.viewport() self.graphgroup = QGraphicsItemGroup(self) self.fggroup = QGraphicsItemGroup(self) self.shadowbox = QGraphicsRectItem(self) self.shadowbox.setCacheMode(QGraphicsItem.DeviceCoordinateCache) self.shadowbox.setBrush(FlPalette.dark) self.shadowbox.setPen(nopen) self.shadowbox.setPos(*(self.style.shadowoffset,)*2) self.graphgroup.addToGroup(self.shadowbox) self.activebox = QGraphicsRectItem(self) self.activebox.setCacheMode(QGraphicsItem.DeviceCoordinateCache) activepen = QPen(self.maincolor, self.style.selectmargin, join=Qt.MiterJoin) self.activebox.setPen(activepen) self.activebox.hide() self.graphgroup.addToGroup(self.activebox) self.selectbox = QGraphicsRectItem(self) self.selectbox.setCacheMode(QGraphicsItem.DeviceCoordinateCache) selectpen = QPen(FlPalette.light, self.style.selectmargin, join=Qt.MiterJoin) self.selectbox.setPen(selectpen) self.selectbox.hide() self.graphgroup.addToGroup(self.selectbox) self.mainbox = QGraphicsRectItem(self) self.mainbox.setCacheMode(QGraphicsItem.DeviceCoordinateCache) self.mainbox.setBrush(mainbrush) self.mainbox.setPen(nopen) self.graphgroup.addToGroup(self.mainbox) self.nodelabel = QGraphicsSimpleTextItemCond(self, viewport) self.nodelabel.setBrush(lightbrush) self.nodelabel.setFont(self.style.boldfont) self.nodelabel.setText(self.label % self.realid()) self.nodelabel.setPos(self.style.itemmargin, self.style.itemmargin) self.fggroup.addToGroup(self.nodelabel) self.icon = self.pixmap("images/blank.png") self.iwidth = self.icon.width() self.iconx = self.style.nodetextwidth self.condicon = QGraphicsPixmapItemCond(self.icon, self, viewport) self.condicon.setPos(self.iconx-self.iwidth, self.style.itemmargin) self.iconx = self.condicon.x() self.fggroup.addToGroup(self.condicon) self.randicon = QGraphicsPixmapItemCond(self.icon, self, viewport) self.randicon.setPos(self.iconx-self.style.itemmargin-self.iwidth, self.style.itemmargin) self.iconx = self.randicon.x() self.fggroup.addToGroup(self.randicon) self.exiticon = QGraphicsPixmapItemCond(self.icon, self, viewport) self.exiticon.setPos(self.iconx-self.style.itemmargin-self.iwidth, self.style.itemmargin) self.iconx = self.exiticon.x() self.fggroup.addToGroup(self.exiticon) self.entericon = QGraphicsPixmapItemCond(self.icon, self, viewport) self.entericon.setPos(self.iconx-self.style.itemmargin-self.iwidth, self.style.itemmargin) self.iconx = self.entericon.x() self.fggroup.addToGroup(self.entericon) self.persisticon = QGraphicsPixmapItemCond(self.icon, self, viewport) self.persisticon.setPos(self.iconx-self.style.itemmargin-self.iwidth, self.style.itemmargin) self.iconx = self.persisticon.x() self.fggroup.addToGroup(self.persisticon) self.comment = QGraphicsTextItemCond(self, viewport) self.comment.setTextWidth(self.style.nodetextwidth) self.comment.setDefaultTextColor(FlPalette.light) self.comment.setPos(0, self.nodelabel.y()+self.nodelabel.boundingRect().height()+self.style.itemmargin) self.fggroup.addToGroup(self.comment) self.graphgroup.addToGroup(self.fggroup) self.view.nodedocs[self.realid()]["comment"].contentsChanged.connect(self.updatecomment) self.updatecondition() self.updateenterscripts() self.updateexitscripts() self.updaterandweight() self.updatepersistence() # Never call updatelayout() from here (or any inheritable reimplementation)! def collapse (self, collapse): for item in self.fggroup.childItems(): if item is not self.nodelabel: if collapse: item.hide() else: item.show() self.updatelayout() def updatecondition (self): icons = {True: "key", False: "blank"} pixmap = self.pixmap("images/%s.png" % icons[self.nodeobj.hascond()]) self.condicon.setPixmap(pixmap) if self.nodeobj.hascond(): self.condicon.setToolTip("Condition") else: self.condicon.setToolTip("") def updateenterscripts (self): icons = {True: "script-enter", False: "blank"} pixmap = self.pixmap("images/%s.png" % icons[self.nodeobj.hasenterscripts()]) self.entericon.setPixmap(pixmap) if self.nodeobj.hasenterscripts(): self.entericon.setToolTip("Enter Scripts") else: self.entericon.setToolTip("") def updateexitscripts (self): icons = {True: "script-exit", False: "blank"} pixmap = self.pixmap("images/%s.png" % icons[self.nodeobj.hasexitscripts()]) self.exiticon.setPixmap(pixmap) if self.nodeobj.hasexitscripts(): self.exiticon.setToolTip("Exit Scripts") else: self.exiticon.setToolTip("") def updaterandweight (self): icons = {True: "dice", False: "blank"} pixmap = self.pixmap("images/%s.png" % icons[bool(self.nodeobj.randweight)]) self.randicon.setPixmap(pixmap) if self.nodeobj.randweight: self.randicon.setToolTip("Random Weight: %s" % self.nodeobj.randweight) else: self.randicon.setToolTip("") def updatepersistence (self): icons = {"Mark": "mark", "OncePerConv": "once", "OnceEver": "onceever", "": "blank"} pixmap = self.pixmap("images/%s.png" % icons[self.nodeobj.persistence]) self.persisticon.setPixmap(pixmap) if self.nodeobj.persistence: self.persisticon.setToolTip("Persistence: %s" % self.nodeobj.persistence) else: self.persisticon.setToolTip("") def updatecomment (self): self.fggroup.removeFromGroup(self.comment) contents = self.view.nodedocs[self.realid()]["comment"].toPlainText() if not contents: self.comment.hide() else: self.comment.show() self.comment.setPlainText(contents) self.fggroup.addToGroup(self.comment) self.updatelayout() def updatelayout (self): if self.iscollapsed(): rect = self.nodelabel.mapRectToParent(self.nodelabel.boundingRect()) else: rect = self.fggroup.childrenBoundingRect() mainrect = rect.marginsAdded(self.style.nodemargins) self.mainbox.setRect(mainrect) self.shadowbox.setRect(mainrect) self.selectbox.setRect(mainrect.marginsAdded(self.style.selectmargins)) activerect = mainrect.marginsAdded(self.style.activemargins) self.activebox.setRect(activerect) self.graphgroup.setPos(-activerect.width()//2-activerect.x(), -activerect.height()//2-activerect.y()) self.prepareGeometryChange() self.rect = self.graphgroup.mapRectToParent(mainrect) self.view.updatelayout() def mouseDoubleClickEvent (self, event): super().mouseDoubleClickEvent(event) event.accept() if event.button() == Qt.LeftButton: self.view.setactivenode(self) def mousePressEvent (self, event): super().mousePressEvent(event) if event.button() & (Qt.LeftButton | Qt.RightButton) : self.view.setselectednode(self) event.accept() def __repr__ (self): return "<%s %s>" % (type(self).__name__, self.id())
class MapWidget(QDialog): def __init__(self): QDialog.__init__(self) self.__mapWidgetUi = Ui_MapWidget() self.__mapWidgetUi.setupUi(self) self.__view = self.__mapWidgetUi.graphicsView self.__view.setObjectName("ACS_Map_View") self.__scene = QGraphicsScene() self.__view.setScene(self.__scene) self.__current_lat = 35.720428 self.__current_lon = -120.769924 self.__current_ground_width = 41000000. #meters(start w/ view of whole earth) #TODO: don't hard code location self.__tiler = acs_map_tiler.ACS_MapTiler(35.720428, -120.769924) self.__current_detail_layer = 0 #corresponds to "zoom" in map_tiler module self.__detail_layers = [] self.__rect_tiles = OrderedDict() #see rectKey method for how key works #detail layers are various levels of raster detail for the map. #0 is lowest level of detail, 20 highest. 0 loads fast and the #entire world can fit on a single tile. 20 loads slow, and it is unwise #to try to show the entire world due to the number of tiles required #(higher numbered detail layers are intended for "zooming in") self.setupDetailLayers() self.__plane_layer = QGraphicsItemGroup() self.__scene.addItem(self.__plane_layer) self.__plane_icons = {} self.__plane_labels = {} self.__plane_icon_pixmaps = {} img_bytes = pkg_resources.resource_stream("acs_dashboards", "data/images/flyingWingTiny.png").read() self.__plane_icon_pixmaps[0] = QPixmap() self.__plane_icon_pixmaps[0].loadFromData(img_bytes) img_bytes2 = pkg_resources.resource_stream("acs_dashboards", "data/images/flyingWingTiny2.png").read() self.__plane_icon_pixmaps[1] = QPixmap() self.__plane_icon_pixmaps[1].loadFromData(img_bytes2) #for drawing waypoints: self.__mission_layer = QGraphicsItemGroup() self.__scene.addItem(self.__mission_layer) self.__wp_diameter = 0.0001 self.__prev_drawn_nav_wp = None #needed when drawing lines between wps self.__wp_loiter_radius = None #NOTE: this is in meters; the map itself #is in degrees #for drawing fence: self.__fence_layer = QGraphicsItemGroup() self.__scene.addItem(self.__fence_layer) #slots self.__view.just_zoomed.connect(self.onZoom) self.__mapWidgetUi.zoom_sb.valueChanged.connect(self.onZoomSBValueChanged) self.__view.just_panned.connect(self.onPan) def getView(self): return self.__view def rectKey(self, x, y): '''rect_tiles key''' return (self.__current_detail_layer, x, y) #returns (min_lat, max_lat, min_lon, max_lon) as a tuple def extentsOfVisibleWorld(self): topLeft = self.__view.mapToScene(0,0) bottomRight = self.__view.mapToScene(self.__view.width(), self.__view.height()) return (-topLeft.y(), -bottomRight.y(), topLeft.x(), bottomRight.x()) #returns a list of TileInfos that are currently visible def tilesInVisibleWorld(self): (latTop, latBottom, lonLeft, lonRight) = self.extentsOfVisibleWorld() #print("Extents:", latTop, latBottom, lonLeft, lonRight, "\n") tile_info_list = self.__tiler.area_to_tile_list_lat_lon(latTop, latBottom, lonLeft, lonRight, self.__current_detail_layer) return tile_info_list def setupDetailLayers(self): #setup detail layers 0-20 for i in range(0,21): self.__detail_layers.append(QGraphicsItemGroup()) #add layer to scene: self.__scene.addItem(self.__detail_layers[i]) #hide all detail layers until it's time to show one: self.__detail_layers[i].hide() #show only the current detail layer self.setCurrentDetailLayer(0) def setCurrentDetailLayer(self, layerNum): self.__detail_layers[self.__current_detail_layer].hide() self.__detail_layers[layerNum].show() self.__current_detail_layer = layerNum self.__tiler.set_max_zoom(self.__current_detail_layer+1) #self.__tiler.prefetch() self.addTilesToCurrentDetailLayer() def createRectFromTileInfo(self, tile_info): #if Rectangle already exists, don't create it again key = self.rectKey(tile_info.x, tile_info.y) if key in self.__rect_tiles: return self.__rect_tiles[key] (y, x) = tile_info.coord() #TODO: do something about the hard coded 256s (end_y, end_x) = tile_info.coord((256, 256)) #y values need to reflect across the equator due to the origin in scene space #being on the top right (as opposed to bottom left in tile space) y = -y end_y = -end_y #keep things simple at the edges of the map: if y < -85.0: y = -85.0 if end_y > 85.0: end_y = 85.0 width = end_x - x height = end_y - y #create rectangle for the TileInfo and put it into the scene self.__rect_tiles[key] = QGraphicsRectItem(x, y, width, height, self.__detail_layers[self.__current_detail_layer]) #add raster data to the rect tile self.__tiler.load_tile(tile_info) #no border self.__rect_tiles[key].setPen(QPen(Qt.NoPen)) #remember the tiling data self.__rect_tiles[key].setData(0, tile_info) #attempt to add tile texture to rectangle: self.textureRect(self.__rect_tiles[key]) return self.__rect_tiles[key] def addTilesToCurrentDetailLayer(self): tile_info_list = self.tilesInVisibleWorld() for next_tile_info in tile_info_list: next_rect = self.createRectFromTileInfo(next_tile_info) #add rect tile to appropriate detail layer self.__detail_layers[self.__current_detail_layer].addToGroup(next_rect) #returns True if texture successfully applied, False otherwise #depth applies to how many zoom levels (or detail layers) we have traveled #while attempting to get a lower resolution texture def textureRect(self, rect_tile): tile_info = rect_tile.data(0) if tile_info is None: return False pm = QPixmap(self.__tiler.tile_to_path(tile_info)) if pm.width() != 256: #print("Probably didn't get tile:", next_tile_info.x, next_tile_info.y, "\n") #TODO: Attempt to texture with a lower res tile #Bear in mind that you will have to take Mercator projection into #account on the lower res tile. #First Attempt: didn't work #if tile_info.zoom <= self.__tiler.get_min_zoom(): # return False # #find colocated lower res tile #(lat,lon) = tile_info.coord() #tile_info2 = self.__tiler.coord_to_tile(lat,lon, tile_info.zoom-1) #rect_tile.setData(0, tile_info2) #print("prev tile: ", tile_info.tile, tile_info.coord()) #return self.textureRect(rect_tile, depth + 1) #until such time as we can pull lower res tiles and figure out #which area to render on a rectangle, skip: return False topLeft = rect_tile.boundingRect().topLeft() bottomRight = rect_tile.boundingRect().bottomRight() width = bottomRight.x() - topLeft.x() height = bottomRight.y() - topLeft.y() brush_trans = QTransform() brush_trans.translate(topLeft.x(), topLeft.y()) brush_trans.scale(width/256.0, height/256.0) qb = QBrush(pm) qb.setTransform(brush_trans) rect_tile.setBrush(qb) return True def checkForNewTextures(self): #ONLY care about rects in the current view: tile_info_list = self.tilesInVisibleWorld() for next_tile_info in tile_info_list: key = self.rectKey(next_tile_info.x, next_tile_info.y) # make sure key exists in self.__rect_tiles if key not in self.__rect_tiles: self.createRectFromTileInfo(next_tile_info) if self.__rect_tiles[key].brush().texture().width() != 256: self.textureRect(self.__rect_tiles[key]) #TODO: this code becomes applicable when lower res tiles become #available to higher zoom levels. #if self.__rect_tiles[key].data(0).zoom < self.__current_detail_layer: #lower res in there, try to get higher res #(remove tile info of the lower res tile): # del self.__rect_tiles[key] def clearFencePoints(self): children = self.__fence_layer.childItems() for child in children: self.__fence_layer.removeFromGroup(child) def clearWPs(self): children = self.__mission_layer.childItems() for child in children: self.__mission_layer.removeFromGroup(child) self.__prev_drawn_nav_wp = None def addWP(self, wp): if wp.command in [mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, mavutil.mavlink.MAV_CMD_NAV_LOITER_TO_ALT, mavutil.mavlink.MAV_CMD_NAV_LOITER_TURNS, mavutil.mavlink.MAV_CMD_NAV_LOITER_TIME, mavutil.mavlink.MAV_CMD_NAV_LOITER_UNLIM, mavutil.mavlink.MAV_CMD_NAV_LAND]: #point rad = self.__wp_diameter * 0.5 ellipse = QGraphicsEllipseItem(wp.y - rad, -wp.x - rad, self.__wp_diameter, self.__wp_diameter, self.__mission_layer) ellipse.setBrush(QBrush(QColor(255, 255, 255))) e_pen = QPen(QColor(255, 255, 255)) e_pen.setWidth(0) ellipse.setPen(e_pen) self.__mission_layer.addToGroup(ellipse) #label label = QGraphicsTextItem(str(wp.seq), self.__mission_layer) label.setZValue(2) label.setDefaultTextColor(Qt.white) label.setPos(wp.y + rad, -wp.x - rad) label.setScale(0.00002) #bit hacky -- really should scale based on #current zoom, but I'm in a hurry. self.__mission_layer.addToGroup(label) label.show() #argument is a dictionary of waypoints (keys = ids) def drawNewMission(self, wps): self.clearWPs() self.drawMissionLines(wps) def drawWPLine(self, wp1, wp2): if wp1 is None or wp2 is None: print("Error: Can't draw line for Null endpoint") return rad = self.__wp_diameter * 0.5 mapped_wp1_x = wp1.y - rad mapped_wp1_y = -wp1.x #tangential approach? if (wp1.command == mavutil.mavlink.MAV_CMD_NAV_LOITER_TO_ALT and wp1.param1 == 1.0): l_rad = abs(self.__wp_loiter_radius) if l_rad is not None: dis = acs_math.gps_distance(wp1.x, wp1.y, wp2.x, wp2.y) theta = math.degrees(math.atan(l_rad / dis)) #sign of self.__wp_loiter_radius indicates the direction of the #loiter (negative is counter-clockwise, postive is clockwise) #Also, the waypoint itself can override the default setting #via param2 if ((wp1.param2 == 0 and self.__wp_loiter_radius > 0.0) or wp1.param2 > 0.0): theta = -theta tan_dis = math.sqrt( dis * dis - l_rad * l_rad) bearing = acs_math.gps_bearing(wp2.x, wp2.y, wp1.x, wp1.y) (tan_wp_x, tan_wp_y) = acs_math.gps_newpos(wp2.x, wp2.y, bearing - theta, tan_dis) mapped_wp1_x = tan_wp_y - rad mapped_wp1_y = -tan_wp_x next_line = QGraphicsLineItem(mapped_wp1_x, mapped_wp1_y, wp2.y - rad, -wp2.x, self.__mission_layer) l_pen = QPen(QColor(255, 255, 255)) l_pen.setWidth(0.00002) next_line.setPen(l_pen) self.__mission_layer.addToGroup(next_line) def setWPLoiterRad(self, rad): self.__wp_loiter_radius = rad def drawWPCircle(self, wp): if self.__wp_loiter_radius is None: print("Can't draw WP loiter circles; wp_loiter_radius not set.") return rad_deg = acs_math.gps_meters_to_degrees_lat(abs(self.__wp_loiter_radius), wp.x, wp.y) diameter = rad_deg * 2.0 ellipse = QGraphicsEllipseItem(wp.y - rad_deg, -wp.x - rad_deg, diameter, diameter, self.__mission_layer) #ellipse.setBrush(QBrush(QColor(255, 255, 255))) e_pen = QPen(QColor(255, 255, 255)) e_pen.setWidth(0.00002) ellipse.setPen(e_pen) self.__mission_layer.addToGroup(ellipse) def drawMissionLines(self, wps): for i in range(1, len(wps)): self.addWP(wps[i]) if wps[i].command in [mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, mavutil.mavlink.MAV_CMD_NAV_LOITER_TO_ALT, mavutil.mavlink.MAV_CMD_NAV_LOITER_TURNS, mavutil.mavlink.MAV_CMD_NAV_LOITER_TIME, mavutil.mavlink.MAV_CMD_NAV_LOITER_UNLIM]: if self.__prev_drawn_nav_wp is not None: self.drawWPLine(self.__prev_drawn_nav_wp, wps[i]) if wps[i].command in [mavutil.mavlink.MAV_CMD_NAV_LOITER_UNLIM, mavutil.mavlink.MAV_CMD_NAV_LOITER_TURNS, mavutil.mavlink.MAV_CMD_NAV_LOITER_TIME, mavutil.mavlink.MAV_CMD_NAV_LOITER_TO_ALT]: self.drawWPCircle(wps[i]) self.__prev_drawn_nav_wp = wps[i] elif wps[i].command == mavutil.mavlink.MAV_CMD_DO_JUMP: wp_id = wps[i].param1 if self.__prev_drawn_nav_wp is not None: self.drawWPLine(self.__prev_drawn_nav_wp, wps[wp_id]) self.__prev_drawn_nav_wp = None def drawNewFence(self, fps): self.clearFencePoints() prev_fp = None for i in range(1, len(fps)): if prev_fp is not None: prev_x = prev_fp.lon prev_y = -prev_fp.lat mapped_x = fps[i].lon mapped_y = -fps[i].lat next_line = QGraphicsLineItem(prev_x, prev_y, mapped_x, mapped_y, self.__fence_layer) l_pen = QPen(QColor(0, 255, 0)) l_pen.setWidth(0.1) next_line.setPen(l_pen) self.__fence_layer.addToGroup(next_line) prev_fp = fps[i] def updateIcon(self, id, uav_state, image_num=0): if uav_state.get_lon() == 0.0: #haven't received a Pose message yet return if id not in self.__plane_icons: #make the plane's label first label = QGraphicsTextItem(str(id), self.__plane_layer) label.setZValue(2) label.setDefaultTextColor(Qt.red) self.__plane_layer.addToGroup(label) label.show() self.__plane_labels[id] = label self.__plane_icons[id] = MapGraphicsIcon(id, label, self.__plane_layer) self.__plane_icons[id].centerIconAt(uav_state.get_lon(), -uav_state.get_lat()) self.__plane_icons[id].textureIcon(self.__plane_icon_pixmaps[image_num]) #plane icons need to be drawn on top of map tiles: self.__plane_icons[id].setZValue(1) self.__plane_layer.addToGroup(self.__plane_icons[id]) #key 0 = last update time self.__plane_icons[id].setData(0, 0) #refresh: #HACK: don't know why zooming works to refresh. Couldn't #get scene.invalidate() nor scene.update() to work self.onZoom(self.__current_detail_layer) #end if now = time.time() #if we don't have new pose data, then we don't update the plane icon if (self.__plane_icons[id].data(0) is None or self.__plane_icons[id].data(0) >= uav_state.get_last_pose_update()): return #place icon self.__plane_icons[id].centerIconAt(uav_state.get_lon(), -uav_state.get_lat()) #give correct heading: quat = uav_state.get_quat() heading = acs_math.yaw_from_quat(quat[0], quat[1], quat[2], quat[3]) self.__plane_icons[id].setHeading(heading) #set last update time self.__plane_icons[id].setData(0, now) def zoomTo(self, zoomLevel, lat = 0, lon = 0): self.__view.zoomTo(zoomLevel, lat, lon) def onZoom(self, zoom_level): self.setCurrentDetailLayer(zoom_level) self.__mapWidgetUi.zoom_sb.setValue(zoom_level) for id, nextPlaneIcon in self.__plane_icons.items(): nextPlaneIcon.scaleByViewAndTexture(self.__view) def onZoomSBValueChanged(self, new_zoom): if (int(self.__view.getCurrentZoom()) != new_zoom): self.__view.zoomTo(new_zoom) def onPan(self, new_lat, new_lon): lat_lon_str = str(new_lat) + ", " + str(new_lon) self.__mapWidgetUi.coords_lb.setText(lat_lon_str) def hideUAVIcon(self, id): if id in self.__plane_icons: self.__plane_icons[id].hide() self.__plane_labels[id].hide() def showUAVIcon(self, id): if id in self.__plane_icons: self.__plane_icons[id].show() self.__plane_labels[id].show()
class BoardGUI(QWidget): """cointain the graphical representation of the Board""" # ratio of bordersize compared to the size of one base square borderRatio = 0.8 baseRectRatio = 14/15 # 12/13 for normal ratio but looks weird stoneScale = 0.46 # siganl stoneClicked = pyqtSignal(tuple) def __init__(self, parent, game): super().__init__() self.initUI(game) def initUI(self, game): self.board = game.currentBoard self.game = game self.showCoords = True self.scene = QGraphicsScene() # grid containing coordinates for the scene self.grid = [] self.drawGrid() # initialize and set layout + view self.view = QGraphicsView(self.scene) self.view.setMouseTracking(True) self.view.setViewportUpdateMode(QGraphicsView.FullViewportUpdate) self.setMouseTracking(True) box = QHBoxLayout() box.addWidget(self.view) self.setLayout(box) # stones for all positions are created and listed in self.pos dict self.createPosition() self.makeCoords() # has to be called after drawGrid! def resizeEvent(self, e): self.view.fitInView(self.view.scene().sceneRect(), Qt.KeepAspectRatio) def boardWidth(self): """returns the max width fitting into widget""" width = self.contentsRect().width()*0.95 height = self.contentsRect().height()*0.95 return min(width, height*self.baseRectRatio) def boardHeight(self): """returns the max width fitting into widget """ return self.boardWidth()*(1/self.baseRectRatio) def makeGrid(self): """ returns coords [[(x, y)]] for the Grid according to current window mesures """ # set scenesize to window size self.scene.setSceneRect(0, 0, self.boardWidth(), self.boardHeight()) denom = self.board.size + 2*self.borderRatio baseWidth = self.boardWidth() / denom baseHeight = self.boardHeight() / denom leftOffset = 0.5*baseWidth # (self.contentsRect().width()-self.boardWidth())/2 topOffset = 0 # (self.contentsRect().height()-self.boardHeight())/2 partionWidth = [leftOffset+(self.borderRatio+x)*baseWidth for x in range(self.board.size)] partionHeight = [topOffset+(self.borderRatio+x)*baseHeight for x in range(self.board.size)] grid = [[(x, y) for x in partionWidth] for y in partionHeight] self.grid = grid self.baseWidth = baseWidth def drawGrid(self): """draws the background grid""" self.makeGrid() for line in self.grid: self.scene.addLine(*line[0], *line[-1]) for (pointT, pointB) in zip(self.grid[0], self.grid[-1]): self.scene.addLine(*pointT, *pointB) self.drawHoshis() def makeCoords(self): """ draws Coordinates """ xLabels = "ABCDEFGHIKLMNOPQRSTUVWXYZ" yLabels = list(range(1, 26)) botGrid = [] leftGrid = [] # generate pixel coordinates grids for n in range(self.board.size): (xBot, yBot) = self.grid[self.board.size-1][n] yBot += self.baseWidth*0.4/self.baseRectRatio xBot -= self.baseWidth*0.1 botGrid.append((xBot, yBot)) (xLeft, yLeft) = self.grid[n][0] xLeft -= self.baseWidth*1.2 yLeft -= self.baseWidth*0.3/self.baseRectRatio leftGrid.append((xLeft, yLeft)) # generate Text items and add them to group self.coordGroup = QGraphicsItemGroup() for n in range(self.board.size): leftText = QGraphicsSimpleTextItem(str(yLabels[n])) leftText.setPos(*leftGrid[n]) self.coordGroup.addToGroup(leftText) bottomText = QGraphicsSimpleTextItem(xLabels[n]) bottomText.setPos(*botGrid[n]) self.coordGroup.addToGroup(bottomText) # draw coordinates and update visibility according to self.showCoords self.scene.addItem(self.coordGroup) self.updateCoords() def updateCoords(self): """ slot that updates the visibility os the coordiantes. """ self.coordGroup.setVisible(self.showCoords) def setCoordVis(self, visibility): """ set the self.showCoords boolean """ self.showCoords = visibility self.updateCoords() def drawHoshis(self): """ Draws Hoshi dots""" hoshis = [] rad = self.baseWidth*0.15 for (x, y) in self.board.getHoshis(): hoshis.append(self.grid[x][y]) for point in hoshis: (x, y) = point self.scene.addEllipse(x-rad, y-rad, rad*2.0, rad*2.0, QPen(), QBrush(Qt.SolidPattern)) def updatePosition(self): """ sets the colors for all stones in self.pos according to the status in self.board """ for (x, y) in self.pos: color = self.game.currentBoard.getPosition(x, y) self.pos[(x, y)].setMark(None) self.pos[(x, y)].setColor(color) lastMove = self.game.currentBoard.lastMove if lastMove: self.pos[lastMove].setMark(GoMarks.circel) ko = self.game.currentBoard.ko if ko: self.pos[ko].setMark(GoMarks.square) def createPosition(self): """ Creates the self.pos dictionary containing all possible stones on the board initialized as empty stones also connects a signal form each stone to ??? """ self.pos = {} radius = self.stoneScale*self.baseWidth for row in range(self.board.size): for col in range(self.board.size): (x, y) = self.grid[row][col] newStone = Stone(x, y, radius) self.pos[(row, col)] = newStone self.scene.addItem(newStone) self.updatePosition() self.connecting() def connecting(self): for key in self.pos: self.pos[key].clicked.connect(lambda key=key: self.resend(key)) def resend(self, pos): """ emits the captured signal again, with (int, in) parameter for stone clicked """ self.stoneClicked.emit(pos)
class Image_widget(QWidget): param_user_modified = pyqtSignal(object) # (px1, py1, px2, px2) # zoom_params = ["x", "y", "dx", "xy_ratio"] def __init__(self, parent, view_presenter): # im=None):#, xy_ratio=None): super().__init__(parent) # self.setWindowFlags(Qt.BypassGraphicsProxyWidget) self._model = view_presenter._model self._mapping = view_presenter._mapping self._presenter = view_presenter# model[func_keys] # if xy_ratio is None: # self._im = parent._im # else: # self._im = im # sets graphics scene and view self._scene = QGraphicsScene() self._group = QGraphicsItemGroup() self._view = QGraphicsView() self._scene.addItem(self._group) self._view.setScene(self._scene) self._view.setFrameStyle(QFrame.Box) # # always scrollbars # self._view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) # self._view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn) # special sursor self._view.setCursor(QtGui.QCursor(Qt.CrossCursor)) # sets property widget self._labels = QDict_viewer(self, {"Image metadata": None, "px": None, "py": None, "zoom": None}) # sets layout self._layout = QVBoxLayout(self) self.setLayout(self._layout) self._layout.addWidget(self._view, stretch=1) #self._layout.addStretch(1) self._layout.addWidget(self._labels, stretch=0) # Zoom rectangle disabled self._rect = None self._drawing_rect = False self._dragging_rect = False # Sets Image self._qim = None self.reset_im() # zooms anchors for wheel events - note this is only active # when the self._view.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) self._view.setResizeAnchor(QGraphicsView.AnchorUnderMouse) self._view.setAlignment(Qt.AlignCenter) # events filters self._view.viewport().installEventFilter(self) self._scene.installEventFilter(self) # Publish / subscribe signals with the submodel # self.zoom_user_modified.connect(self._model.) self._model.model_event.connect(self.model_event_slot) # self._view.setContextMenuPolicy(Qt.ActionsContextMenu) # self._scene.customContextMenuRequested.connect(self.useless) # useless_action = QAction("DoNothing", self) # self._scene.addAction(useless_action) # useless_action.triggered.connect(self.useless) def on_context_menu(self, event): menu = QMenu(self) NoAction = QAction("Does nothing", self) menu.addAction(NoAction) NoAction.triggered.connect(self.doesnothing) menu.popup(self._view.viewport().mapToGlobal(event.pos())) return True def doesnothing(self, event): print("voili voilou") @property def zoom(self): view = self._view pc = 100. * math.sqrt(view.transform().determinant()) return "{0:.2f} %".format(pc) @property def xy_ratio(self): return self._presenter["xy_ratio"] # return self.parent().xy_ratio def reset_im(self): image_file = os.path.join((self._presenter["fractal"]).directory, self._presenter["image"] + ".png") valid_image = True try: with PIL.Image.open(image_file) as im: info = im.info nx, ny = im.size # print("info debug", info["debug"]) except FileNotFoundError: valid_image = False info = {"x": None, "y": None, "dx": None, "xy_ratio": None} nx = None ny = None # Storing the "initial" zoom info self._fractal_zoom_init = {k: info[k] for k in ["x", "y", "dx", "xy_ratio"]} self._fractal_zoom_init["nx"] = nx self._fractal_zoom_init["ny"] = ny self.validate() # if self._qim is not None: # self._group.removeFromGroup(self._qim) for item in [self._qim, self._rect]: if item is not None: self._group.removeFromGroup(item) if valid_image: self._qim = QGraphicsPixmapItem(QtGui.QPixmap.fromImage( QtGui.QImage(image_file)))#QtGui.QImage()))#imqt)) # QtGui.QImage(self._im))) self._qim.setAcceptHoverEvents(True) self._group.addToGroup(self._qim) self.fit_image() else: self._qim = None self._rect = None self._drawing_rect = False @staticmethod def cast(val, example): """ Casts value to the same type as example """ return type(example)(val) def check_zoom_init(self): """ Checks if the image 'zoom init' matches the parameters ; otherwise, updates """ ret = 0 for key in ["x", "y", "dx", "xy_ratio"]:#, "dps"]: # TODO : or precision ?? expected = self._presenter[key] value = self._fractal_zoom_init[key] if value is None: ret = 2 else: casted = self.cast(value, expected) # Send a model modification request self._presenter[key] = casted if casted != str(expected) and (ret != 2): ret = 1 self._fractal_zoom_init[key] = casted return ret def validate(self): """ Sets Image metadata message """ self.validated = self.check_zoom_init() message = {0: "OK, matching", 1: "OK, zoom params updated", 2: "No image found"} self._labels.values_update({"Image metadata": message[self.validated]}) def fit_image(self): if self._qim is None: return rect = QtCore.QRectF(self._qim.pixmap().rect()) if not rect.isNull(): # # always scrollbars off self._view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self._view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) view = self._view view.setSceneRect(rect) unity = view.transform().mapRect(QtCore.QRectF(0, 0, 1, 1)) view.scale(1 / unity.width(), 1 / unity.height()) viewrect = view.viewport().rect() scenerect = view.transform().mapRect(rect) factor = min(viewrect.width() / scenerect.width(), viewrect.height() / scenerect.height()) view.scale(factor, factor) self._view.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self._view.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) self._labels.values_update({"zoom": self.zoom}) def eventFilter(self, source, event): # ref: https://doc.qt.io/qt-5/qevent.html if source is self._scene: if type(event) is QtWidgets.QGraphicsSceneMouseEvent: return self.on_viewport_mouse(event) elif type(event) is QtGui.QEnterEvent: return self.on_enter(event) elif (event.type() == QtCore.QEvent.Leave): return self.on_leave(event) elif source is self._view.viewport(): # Catch context menu if type(event) == QtGui.QContextMenuEvent: return self.on_context_menu(event) elif event.type() == QtCore.QEvent.Wheel: return self.on_wheel(event) elif event.type() == QtCore.QEvent.ToolTip: return True return False def on_enter(self, event): # print("enter") return False def on_leave(self, event): # print("leave") return False def on_wheel(self, event): if self._qim is not None: view = self._view if event.angleDelta().y() > 0: factor = 1.25 else: factor = 0.8 view.scale(factor, factor) self._labels.values_update({"zoom": self.zoom}) return True def on_viewport_mouse(self, event): if event.type() == QtCore.QEvent.GraphicsSceneMouseMove: # print("viewport_mouse") self.on_mouse_move(event) return True elif (event.type() == QtCore.QEvent.GraphicsSceneMousePress and event.button() == Qt.LeftButton): self.on_mouse_left_press(event) return True elif (event.type() == QtCore.QEvent.GraphicsSceneMouseRelease and event.button() == Qt.LeftButton): self.on_mouse_left_release(event) return True elif (event.type() == QtCore.QEvent.GraphicsSceneMouseDoubleClick and event.button() == Qt.LeftButton): self.on_mouse_double_left_click(event) return True else: # print("Uncatched mouse event", event.type()) return False def on_mouse_left_press(self, event): self._drawing_rect = True self._dragging_rect = False self._rect_pos0 = event.scenePos() def on_mouse_left_release(self, event): if self._drawing_rect: self._rect_pos1 = event.scenePos() if (self._rect_pos0 == self._rect_pos1): self._group.removeFromGroup(self._rect) self._rect = None print("cancel drawing RECT") self.cancel_drawing_rect() else: print("finish drawing RECT", self._rect_pos0, self._rect_pos1) self.publish_drawing_rect() self._drawing_rect = False def cancel_drawing_rect(self, dclick=False): if self._qim is None: return keys = ["x", "y", "dx"] if dclick: keys = ["x", "y", "dx", "xy_ratio"] # resets everything except the zoom ratio for key in keys: #, "xy_ratio"]: value = self._fractal_zoom_init[key] if value is not None: # Send a model modification request # TODO: avoid update cancel xy_ratio 1.0 <class 'str'> print("update cancel", key, value, type(value)) self._presenter[key] = value def publish_drawing_rect(self): print("------*----- publish zoom") if self._qim is None: return # print("publish", self._rect_pos0, self._rect_pos1) # print("fractal", self._presenter["fractal"]) # print("fractal", self._presenter["image"]) nx = self._fractal_zoom_init["nx"] ny = self._fractal_zoom_init["ny"] # new center offet in pixel center_off_px = 0.5 * (self._rect_pos0.x() + self._rect_pos1.x() - nx) center_off_py = 0.5 * (ny - self._rect_pos0.y() - self._rect_pos1.y()) dx_pix = abs(self._rect_pos0.x() - self._rect_pos1.x()) # print("center px", center_off_px) # print("center py", center_off_py) ref_zoom = self._fractal_zoom_init.copy() # str -> mpf as needed to_mpf = {k: isinstance(self._fractal_zoom_init[k], str) for k in ["x", "y", "dx"]} # We may need to increase the dps to hold sufficent digits if to_mpf["dx"]: ref_zoom["dx"] = mpmath.mpf(ref_zoom["dx"]) pix = ref_zoom["dx"] / float(ref_zoom["nx"]) with mpmath.workdps(6): # Sets the working dps to 10e-8 x pixel size ref_zoom["dps"] = int(-mpmath.log10(pix * dx_pix / nx) + 8) print("------*----- NEW dps from zoom", ref_zoom["dps"]) # if ref_zoom["dps"] > mpmath.dps: # zoom_dps = max(ref_zoom["dps"], mpmath.mp.dps) with mpmath.workdps(ref_zoom["dps"]): for k in ["x", "y"]: if to_mpf[k]: ref_zoom[k] = mpmath.mpf(ref_zoom[k]) # print("is_mpf", to_mpf, ref_zoom) ref_zoom["x"] += center_off_px * pix ref_zoom["y"] += center_off_py * pix ref_zoom["dx"] = dx_pix * pix # mpf -> str (back) for (k, v) in to_mpf.items(): if v: if k == "dx": ref_zoom[k] = mpmath.nstr(ref_zoom[k], 16) else: ref_zoom[k] = str(ref_zoom[k]) for key in ["x", "y", "dx", "dps"]: self._presenter[key] = ref_zoom[key] # keys = ["x", "y", "dx"] # if dclick: # keys = ["x", "y", "dx", "xy_ratio"] # # resets everything except the zoom ratio # for key in keys: #, "xy_ratio"]: # value = self._fractal_zoom_init[key] # if value is not None: # # Send a model modification request # # TODO: avoid update cancel xy_ratio 1.0 <class 'str'> # print("update cancel", key, value, type(value)) # self._presenter[key] = value def on_mouse_double_left_click(self, event): self.fit_image() self.cancel_drawing_rect(dclick=True) def on_mouse_move(self, event): scene_pos = event.scenePos() self._labels.values_update({"px": scene_pos.x(), "py": scene_pos.y()}) if self._drawing_rect: self._dragging_rect = True self._rect_pos1 = event.scenePos() self.draw_rect(self._rect_pos0, self._rect_pos1) def draw_rect(self, pos0, pos1): """ Draws the selection rectangle """ # Enforce the correct ratio diffx = pos1.x() - pos0.x() diffy = pos1.y() - pos0.y() radius_sq = diffx ** 2 + diffy ** 2 diffx0 = math.sqrt(radius_sq / (1. + self.xy_ratio ** 2)) diffy0 = diffx0 * self.xy_ratio diffx0 = math.copysign(diffx0, diffx) diffy0 = math.copysign(diffy0, diffy) pos1 = QtCore.QPointF(pos0.x() + diffx0, pos0.y() + diffy0) topleft = QtCore.QPointF(min(pos0.x(), pos1.x()), min(pos0.y(), pos1.y())) bottomRight = QtCore.QPointF(max(pos0.x(), pos1.x()), max(pos0.y(), pos1.y())) rectF = QtCore.QRectF(topleft, bottomRight) if self._rect is not None: self._rect.setRect(rectF) else: self._rect = QGraphicsRectItem(rectF) self._rect.setPen(QtGui.QPen(QtGui.QColor("red"), 0, Qt.DashLine)) self._group.addToGroup(self._rect) def model_event_slot(self, keys, val): """ A model item has been modified - will it impact the widget ? """ # Find the mathching "mapping" - None if no match mapped = next((k for k, v in self._mapping.items() if v == keys), None) if mapped in ["image", "fractal"]: self.reset_im() elif mapped in ["x", "y", "dx", "xy_ratio", "dps"]: pass else: if mapped is not None: raise NotImplementedError("Mapping event not implemented: " + "{}".format(mapped))
class IDView(QGraphicsView): """Simple extension of QGraphicsView - containing an image and click-to-zoom/unzoom """ def __init__(self, parent, fnames): QGraphicsView.__init__(self) self.parent = parent self.initUI(fnames) def initUI(self, fnames): # Make QGraphicsScene self.scene = QGraphicsScene() # TODO = handle different image sizes. self.images = {} self.imageGItem = QGraphicsItemGroup() self.scene.addItem(self.imageGItem) self.updateImage(fnames) self.setBackgroundBrush(QBrush(Qt.darkCyan)) self.parent.tool = "zoom" self.boxFlag = False self.originPos = QPointF(0, 0) self.currentPos = self.originPos self.boxItem = QGraphicsRectItem() self.boxItem.setPen(QPen(Qt.darkCyan, 1)) self.boxItem.setBrush(QBrush(QColor(0, 255, 0, 64))) def updateImage(self, fnames): """Update the image with that from filename""" for n in self.images: self.imageGItem.removeFromGroup(self.images[n]) self.images[n].setVisible(False) if fnames is not None: x = 0 n = 0 for fn in fnames: self.images[n] = QGraphicsPixmapItem(QPixmap(fn)) self.images[n].setTransformationMode(Qt.SmoothTransformation) self.images[n].setPos(x, 0) self.images[n].setVisible(True) self.scene.addItem(self.images[n]) x += self.images[n].boundingRect().width() + 10 self.imageGItem.addToGroup(self.images[n]) n += 1 # Set sensible sizes and put into the view, and fit view to the image. br = self.imageGItem.boundingRect() self.scene.setSceneRect( 0, 0, max(1000, br.width()), max(1000, br.height()), ) self.setScene(self.scene) self.fitInView(self.imageGItem, Qt.KeepAspectRatio) def deleteRect(self): if self.boxItem.scene() is None: return self.scene.removeItem(self.boxItem) self.parent.rectangle = None def mousePressEvent(self, event): if self.parent.tool == "rect": self.originPos = self.mapToScene(event.pos()) self.currentPos = self.originPos self.boxItem.setRect(QRectF(self.originPos, self.currentPos)) if self.boxItem.scene() is None: self.scene.addItem(self.boxItem) self.boxFlag = True else: super(IDView, self).mousePressEvent(event) def mouseMoveEvent(self, event): if self.parent.tool == "rect" and self.boxFlag: self.currentPos = self.mapToScene(event.pos()) if self.boxItem is None: return else: self.boxItem.setRect(QRectF(self.originPos, self.currentPos)) else: super(IDView, self).mousePressEvent(event) def mouseReleaseEvent(self, event): if self.boxFlag: self.boxFlag = False self.parent.rectangle = self.boxItem.rect() self.parent.whichFile = self.parent.vTW.currentIndex() return """Left/right click to zoom in and out""" if (event.button() == Qt.RightButton) or ( QGuiApplication.queryKeyboardModifiers() == Qt.ShiftModifier): self.scale(0.8, 0.8) else: self.scale(1.25, 1.25) self.centerOn(event.pos()) def resetView(self): """Reset the view to its reasonable initial state.""" self.fitInView(self.imageGItem, Qt.KeepAspectRatio)
class Ui_MainWindow(QtWidgets.QMainWindow, Ui_MainWindowBase): def __init__(self): super(Ui_MainWindow, self).__init__() self.setupUi(self) self.videoPlaybackInit() self.imgInit() self.menuInit() self.df = {} self.trackingPathGroup = None self.movableArrowGroup = None self.line_data_dict = {} self.line_item_dict = {} self.file_name_dict = {} self.currentFrameNo = 0 self.colors = None self.overlayCheckBox.stateChanged.connect(self.overlayCheckBoxStateChanged) self.radiusSpinBox.valueChanged.connect(self.radiusSpinBoxValueChanged) self.frameNoSpinBox.valueChanged.connect(self.frameNoSpinBoxValueChanged) self.markDeltaSpinBox.valueChanged.connect(self.markDeltaSpinBoxValueChanged) def overlayCheckBoxStateChanged(self, s): if self.overlayCheckBox.isChecked(): self.frameBufferItemGroup.show() else: self.frameBufferItemGroup.hide() self.updateInputGraphicsView() def markDeltaSpinBoxValueChanged(self, value): if self.trackingPathGroup is not None: self.trackingPathGroup.setMarkDelta(self.markDeltaSpinBox.value()) self.updateInputGraphicsView() def radiusSpinBoxValueChanged(self, value): if self.trackingPathGroup is not None: self.trackingPathGroup.setRadius(self.radiusSpinBox.value()) self.updateInputGraphicsView() def frameNoSpinBoxValueChanged(self, value): if self.trackingPathGroup is not None: self.trackingPathGroup.setOverlayFrameNo(self.frameNoSpinBox.value()) self.updateInputGraphicsView() def dragEnterEvent(self,event): event.acceptProposedAction() def dropEvent(self,event): # event.setDropAction(QtCore.Qt.MoveAction) mime = event.mimeData() if mime.hasUrls(): urls = mime.urls() if len(urls) > 0: self.processDropedFile(urls[0].toLocalFile()) event.acceptProposedAction() def processDropedFile(self,filePath): root,ext = os.path.splitext(filePath) if ext == ".filter": # Read Filter self.openFilterFile(filePath=filePath) return elif ext == ".csv": self.openCSVFile(filePath=filePath) elif ext == ".json": self.openJSONFile(filePath=filePath) elif ext == ".color": self.openColorFile(filePath=filePath) elif self.openImageFile(filePath=filePath): return elif self.openVideoFile(filePath=filePath): return def videoPlaybackInit(self): self.videoPlaybackWidget.hide() self.videoPlaybackWidget.frameChanged.connect(self.setFrame, Qt.QueuedConnection) def setFrame(self, frame, frameNo): if frame is not None: self.cv_img = frame self.currentFrameNo = frameNo self.updateInputGraphicsView() self.evaluate() def imgInit(self): self.cv_img = cv2.imread(os.path.join(sampleDataPath,"color_filter_test.png")) self.frameBuffer = Queue() self.frameBufferItemGroup = QGraphicsItemGroup() self.frameBufferItemGroup.hide() self.inputPixmapRenderScene = QGraphicsScene() self.inputPixmapRenderScene.addItem(self.frameBufferItemGroup) self.inputScene = QGraphicsScene() self.inputGraphicsView.setScene(self.inputScene) self.inputGraphicsView.resizeEvent = self.graphicsViewResized # self.inputScene.addItem(self.frameBufferItemGroup) qimg = misc.cvMatToQImage(self.cv_img) self.inputPixmap = QPixmap.fromImage(qimg) self.inputPixmapItem = QGraphicsPixmapItem(self.inputPixmap) self.inputScene.addItem(self.inputPixmapItem) self.rubberBand = QtWidgets.QRubberBand(QtWidgets.QRubberBand.Rectangle, self.inputGraphicsView) self.inputGraphicsView.mousePressEvent = self.inputGraphicsViewMousePressEvent self.inputGraphicsView.mouseMoveEvent = self.inputGraphicsViewMouseMoveEvent self.inputGraphicsView.mouseReleaseEvent = self.inputGraphicsViewMouseReleaseEvent self.inputGraphicsView.viewport().installEventFilter(self) self.inputGraphicsView.setMouseTracking(True) self.overlayScene = QGraphicsScene() self.inputGraphicsView.setOverlayScene(self.overlayScene) self.zoomedGraphicsView.setScene(self.inputScene) self.zoomedGraphicsView.setOverlayScene(self.overlayScene) def inputGraphicsViewMousePressEvent(self, event): self.origin = QPoint(event.pos()) self.rubberBand.setGeometry( QtCore.QRect(self.origin, QtCore.QSize())) self.rubberBand.show() # Comment out to permit the view for sending the event to the child scene. # QGraphicsView.mousePressEvent(self.inputGraphicsView, event) def inputGraphicsViewMouseMoveEvent(self, event): if self.rubberBand.isVisible(): self.rubberBand.setGeometry( QtCore.QRect(self.origin, event.pos()).normalized()) # Comment out to permit the view for sending the event to the child scene. # QGraphicsView.mouseMoveEvent(self.inputGraphicsView, event) def inputGraphicsViewMouseReleaseEvent(self, event): if self.rubberBand.isVisible(): self.rubberBand.hide() rect = self.rubberBand.geometry() sceneRect = self.inputGraphicsView.mapToScene(rect).boundingRect() self.zoomedGraphicsView.fitInView(QRectF(sceneRect)) self.zoomedGraphicsView.viewport().update() # Comment out to permit the view for sending the event to the child scene. self.inputGraphicsView.viewport().update() # QGraphicsView.mouseReleaseEvent(self.inputGraphicsView, event) def menuInit(self): self.actionSaveDataFiles.triggered.connect(self.saveDataFiles) self.actionOpenCSVFile.triggered.connect(self.openCSVFile) self.actionOpenCSVFile.triggered.connect(self.openJSONFile) self.actionOpenCSVFile.triggered.connect(self.openJSONFile) self.actionPath.triggered.connect(self.actionPathTriggered) self.actionCircle.triggered.connect(self.actionCircleTriggered) self.actionIntervalMark.triggered.connect(self.actionIntervalMarkTriggered) self.actionShape.triggered.connect(self.actionShapeTriggered) self.actionSkeleton.triggered.connect(self.actionSkeletonTriggered) self.actionArrow.triggered.connect(self.actionArrowTriggered) self.actionChangeOrderOfNum.triggered.connect(self.actionChangeOrderOfNumTriggered) self.actionTrackingPathColor.triggered.connect(self.openTrackingPathColorSelectorDialog) def actionPathTriggered(self, checked): if self.trackingPathGroup is not None: self.trackingPathGroup.setDrawLine(checked) if not checked or self.actionIntervalMark.isChecked(): self.trackingPathGroup.setDrawMarkItem(checked) self.updateInputGraphicsView() def actionCircleTriggered(self, checked): if self.trackingPathGroup is not None: self.trackingPathGroup.setDrawItem(checked) self.updateInputGraphicsView() def actionIntervalMarkTriggered(self, checked): if self.trackingPathGroup is not None: self.trackingPathGroup.setDrawMarkItem(checked) self.updateInputGraphicsView() def actionShapeTriggered(self, checked): if 'shape' in self.line_item_dict.keys(): line_item = self.line_item_dict['shape'] if checked: line_item.show() else: line_item.hide() def actionSkeletonTriggered(self, checked): if 'skeleton' in self.line_item_dict.keys(): line_item = self.line_item_dict['skeleton'] if checked: line_item.show() else: line_item.hide() def actionArrowTriggered(self, checked): if self.movableArrowGroup is not None: if checked: self.movableArrowGroup.show() else: self.movableArrowGroup.hide() def actionChangeOrderOfNumTriggered(self, checked): if len(self.df.keys())!=0 or len(self.line_data_dict.keys())!=0: self.videoPlaybackWidget.stop() dialog = DataSwapDialog(self) dialog.setWindowModality(Qt.WindowModal) dialog.setData(self.df, self.line_data_dict) dialog.swapAccepted.connect(self.evaluate) res = dialog.exec() def openTrackingPathColorSelectorDialog(self, activated=False): if self.trackingPathGroup is not None: self.trackingPathGroup.openColorSelectorDialog(self) 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 ret = self.videoPlaybackWidget.openVideo(filePath) if ret == False: return False self.videoPlaybackWidget.show() self.cv_img = self.videoPlaybackWidget.getCurrentFrame() self.initialize() return True else: return False 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.videoPlaybackWidget.hide() self.updateInputGraphicsView() self.evaluate() return True else: return False def openCSVFile(self, activated=False, filePath=None): if filePath is None: filePath, _ = QFileDialog.getOpenFileName(None, 'Open CSV File', userDir, 'CSV files (*.csv)') if len(filePath) is not 0: df = pd.read_csv(filePath, index_col=0) name = df.index.name if name is None: name = 'position' self.df[name] = df self.file_name_dict[name] = filePath if name is None or name=='position': if self.trackingPathGroup is not None: self.inputScene.removeItem(self.trackingPathGroup) self.trackingPathGroup = TrackingPathGroup() self.trackingPathGroup.setRect(self.inputScene.sceneRect()) self.inputScene.addItem(self.trackingPathGroup) if not self.actionPath.isChecked(): self.trackingPathGroup.setDrawLine(False) if not self.actionCircle.isChecked(): self.trackingPathGroup.setDrawItem(False) if not self.actionIntervalMark.isChecked(): self.trackingPathGroup.setDrawMarkItem(False) self.trackingPathGroup.setDataFrame(self.df['position']) elif name=='arrow': if self.movableArrowGroup is not None: self.inputScene.removeItem(self.movableArrowGroup) self.movableArrowGroup = MovableArrowGroup() self.inputScene.addItem(self.movableArrowGroup) self.movableArrowGroup.edited.connect(self.arrowEdited) if not self.actionArrow.isChecked(): self.movableArrowGroup.hide() if 'arrow' in self.df.keys() and 'position' in self.df.keys(): self.movableArrowGroup.setDataFrame(self.df['arrow'], self.df['position']) self.initialize() def openColorFile(self, activated=False, filePath=None): if filePath is None: filePath, _ = QFileDialog.getOpenFileName(None, 'Open Color File', userDir, 'Color files (*.color)') if len(filePath) is not 0: self.colors = pd.read_csv(filePath, index_col=0).as_matrix().tolist() self.colors = [QColor(*rgb) for rgb in self.colors] self.setColorsToGraphicsObjects() def openJSONFile(self, activated=False, filePath=None): if filePath is None: filePath, _ = QFileDialog.getOpenFileName(None, 'Open JSON File', userDir, 'JSON files (*.json)') if len(filePath) is not 0: with open(filePath) as f_p: data = json.load(f_p) name = data['name'] self.line_data_dict[name] = data self.file_name_dict[name] = filePath if name in self.line_item_dict.keys(): self.inputScene.removeItem(self.line_item_dict[name]) lines = MovableLineGroup() lines.setData(data) lines.setRect(self.inputScene.sceneRect()) if name=='shape' and not self.actionShape.isChecked(): lines.hide() if name=='skeleton' and not self.actionSkeleton.isChecked(): lines.hide() self.line_item_dict[name] = lines self.inputScene.addItem(lines) self.initialize() def saveDataFiles(self, activated=False, filePath = None): if len(self.df.keys())!=0: for k, v in self.df.items(): f_name, f_ext = os.path.splitext(self.file_name_dict[k]) candidate_file_path = '{0}-fixed{1}'.format(f_name, f_ext) filePath, _ = QFileDialog.getSaveFileName(None, 'Save CSV File', candidate_file_path, "CSV files (*.csv)") if len(filePath) is not 0: logger.debug("Saving CSV file: {0}".format(filePath)) df = v.copy() col_n = df.as_matrix().shape[1]/2 col_names = np.array([('x{0}'.format(i), 'y{0}'.format(i)) for i in range(int(round(col_n)))]).flatten() df.columns = pd.Index(col_names) df.to_csv(filePath) for k, v in self.line_data_dict.items(): f_name, f_ext = os.path.splitext(self.file_name_dict[k]) candidate_file_path = '{0}-fixed{1}'.format(f_name, f_ext) filePath, _ = QFileDialog.getSaveFileName(None, 'Save JSON File', candidate_file_path, "JSON files (*.json)") if len(filePath) is not 0: logger.debug("Saving JSON file: {0}".format(filePath)) with open(filePath, 'w') as f_p: json.dump(v, f_p) def updateInputGraphicsView(self): self.inputScene.removeItem(self.inputPixmapItem) qimg = misc.cvMatToQImage(self.cv_img) self.inputPixmap = QPixmap.fromImage(qimg) p = QPainter(self.inputPixmap) sourceRect = self.inputPixmapRenderScene.sceneRect() self.inputPixmapRenderScene.render(p, QRectF(sourceRect), QRectF(sourceRect), QtCore.Qt.IgnoreAspectRatio) self.inputPixmapItem = QGraphicsPixmapItem(self.inputPixmap) rect = QtCore.QRectF(self.inputPixmap.rect()) self.inputScene.setSceneRect(rect) self.inputScene.addItem(self.inputPixmapItem) self.inputGraphicsView.viewport().update() self.graphicsViewResized() def eventFilter(self, obj, event): if obj is self.inputGraphicsView.viewport() and event.type()==QEvent.Wheel: return True if event.type() == QEvent.KeyPress: if Qt.Key_Home <= event.key() <= Qt.Key_PageDown: self.videoPlaybackWidget.playbackSlider.keyPressEvent(event) return True return False def graphicsViewResized(self, event=None): self.inputGraphicsView.fitInView(QtCore.QRectF(self.inputPixmap.rect()), QtCore.Qt.KeepAspectRatio) def setColorsToGraphicsObjects(self): # FIXME: データセットと色リストのサイズ整合性チェックが必要 if self.colors is not None: if self.trackingPathGroup is not None: self.trackingPathGroup.setColors(self.colors) for k, v in self.line_item_dict.items(): v.setColors(self.colors) def initialize(self): if not self.videoPlaybackWidget.isOpened(): return if self.trackingPathGroup is not None: r = self.trackingPathGroup.autoAdjustRadius(self.cv_img.shape) self.radiusSpinBox.setValue(r) self.trackingPathGroup.autoAdjustLineWidth(self.cv_img.shape) self.trackingPathGroup.setItemsAreMovable(True) if self.movableArrowGroup is not None: pass for k, v in self.line_item_dict.items(): v.autoAdjustLineWidth(self.cv_img.shape) v.autoAdjustMarkSize(self.cv_img.shape) self.setColorsToGraphicsObjects() self.evaluate() def evaluate(self): if not self.videoPlaybackWidget.isOpened(): return qimg = misc.cvMatToQImage(self.cv_img) pixmapItem = QGraphicsPixmapItem(QPixmap.fromImage(qimg)) pixmapItem.setOpacity(0.2) self.frameBuffer.put(pixmapItem) self.frameBufferItemGroup.addToGroup(pixmapItem) if self.frameBuffer.qsize() > 10: item = self.frameBuffer.get() self.frameBufferItemGroup.removeFromGroup(item) if self.trackingPathGroup is not None: self.trackingPathGroup.setPoints(self.currentFrameNo) if self.movableArrowGroup is not None: self.movableArrowGroup.setPositions(self.currentFrameNo) for k, v in self.line_item_dict.items(): v.setPolyline(self.currentFrameNo) @pyqtSlot(object) def arrowEdited(self, name): # TODO: 方向の再推定機能の実装 # quit_msg = "Arrow {} edited.\nRe-estimate the direction in following frames?".format(name) # reply = QtWidgets.QMessageBox.question( # self, # 'Question', # quit_msg, # QtWidgets.QMessageBox.Yes, # QtWidgets.QMessageBox.No # ) # # if reply == QtWidgets.QMessageBox.Yes: # pass # else: # pass pass
class ExamView(QGraphicsView): """Simple extension of QGraphicsView - containing an image and click-to-zoom/unzoom """ def __init__(self, fnames): QGraphicsView.__init__(self) self.initUI(fnames) def initUI(self, fnames): # set background self.setStyleSheet("background: transparent") self.setBackgroundBrush(BackGrid()) self.setRenderHint(QPainter.Antialiasing, True) self.setRenderHint(QPainter.SmoothPixmapTransform, True) # Make QGraphicsScene self.scene = QGraphicsScene() # TODO = handle different image sizes. self.images = {} self.imageGItem = QGraphicsItemGroup() self.scene.addItem(self.imageGItem) self.updateImage(fnames) def updateImage(self, fnames): """Update the image with that from filename""" for n in self.images: self.imageGItem.removeFromGroup(self.images[n]) self.images[n].setVisible(False) if fnames is not None: x = 0 for (n, fn) in enumerate(fnames): pix = QPixmap(fn) self.images[n] = QGraphicsPixmapItem(pix) self.images[n].setTransformationMode(Qt.SmoothTransformation) self.images[n].setPos(x, 0) self.images[n].setVisible(True) sf = float(ScenePixelHeight) / float(pix.height()) self.images[n].setScale(sf) self.scene.addItem(self.images[n]) # x += self.images[n].boundingRect().width() + 10 # TODO: why did this have + 10 but the scene did not? x += sf * (pix.width() - 1.0) # TODO: don't floor here if units of scene are large! x = int(x) self.imageGItem.addToGroup(self.images[n]) # Set sensible sizes and put into the view, and fit view to the image. br = self.imageGItem.boundingRect() self.scene.setSceneRect( 0, 0, max(1000, br.width()), max(1000, br.height()), ) self.setScene(self.scene) self.fitInView(self.imageGItem, Qt.KeepAspectRatio) def mouseReleaseEvent(self, event): """Left/right click to zoom in and out""" if (event.button() == Qt.RightButton) or ( QGuiApplication.queryKeyboardModifiers() == Qt.ShiftModifier): self.scale(0.8, 0.8) else: self.scale(1.25, 1.25) self.centerOn(event.pos()) def resetView(self): """Reset the view to its reasonable initial state.""" self.fitInView(self.imageGItem, Qt.KeepAspectRatio)
class Ui_MainWindow(QtWidgets.QMainWindow, Ui_MainWindowBase): def __init__(self): super(Ui_MainWindow, self).__init__() self.setupUi(self) self.videoPlaybackInit() self.imgInit() self.menuInit() self.df = None self.trackingPathGroup = None self.drawingFlag = False self.handInputSystem = None self.handInputSystem = HandInputSystem() self.handInputSystem.setRect(self.inputScene.sceneRect()) self.inputScene.addItem(self.handInputSystem) self.handInputSystem.addNewDataFrame() self.currentFrameNo = 0 self.colors = [] self.circleCheckBox.stateChanged.connect( self.polyLineCheckBoxStateChanged) self.lineCheckBox.stateChanged.connect( self.polyLineCheckBoxStateChanged) self.overlayCheckBox.stateChanged.connect( self.overlayCheckBoxStateChanged) self.radiusSpinBox.valueChanged.connect(self.radiusSpinBoxValueChanged) self.frameNoSpinBox.valueChanged.connect( self.frameNoSpinBoxValueChanged) self.groupBox_2.hide() self.inputGraphicsView.viewport().setCursor(QtCore.Qt.ArrowCursor) # self.optionViewButton.pressed.connect(self.optionViewButtonPressed) self.zoomedGraphicsView.hide() self.dataFrameWidget.dataFrameChanged.connect(self.dataFrameChanged) self.dataFrameWidget.hide() self.handInputSystem.setColor(self.dataFrameWidget.getColor()) #self.processDropedFile("/Users/ymnk/temp/Dast/2016/01/hoge.avi") #self.processDropedFile("./a.csv") def dataFrameChanged(self, addedFrameFlag, editingNo, color): if addedFrameFlag: self.handInputSystem.addNewDataFrame() self.handInputSystem.setEditingNo(editingNo) self.handInputSystem.setColor(color) print(addedFrameFlag, color, editingNo) def optionViewButtonPressed(self): if self.groupBox_2.isVisible(): self.optionViewButton.setText("<") self.groupBox_2.hide() else: self.optionViewButton.setText(">") self.groupBox_2.show() def overlayCheckBoxStateChanged(self, s): if self.overlayCheckBox.isChecked(): self.frameBufferItemGroup.show() else: self.frameBufferItemGroup.hide() self.updateInputGraphicsView() def polyLineCheckBoxStateChanged(self, s): overlayFrameNo = self.frameNoSpinBox.value() min_value = max(self.currentFrameNo - overlayFrameNo, 0) current_pos = self.currentFrameNo - min_value if self.handInputSystem is not None: self.handInputSystem.setDrawItem(current_pos, self.circleCheckBox.isChecked()) self.handInputSystem.setDrawLine(self.lineCheckBox.isChecked()) self.updateInputGraphicsView() def radiusSpinBoxValueChanged(self, value): if self.handInputSystem is not None: self.handInputSystem.setRadius(self.radiusSpinBox.value()) self.updateInputGraphicsView() def frameNoSpinBoxValueChanged(self, value): if self.handInputSystem is not None: self.handInputSystem.setOverlayFrameNo(self.frameNoSpinBox.value()) self.updateInputGraphicsView() def dragEnterEvent(self, event): event.acceptProposedAction() def dropEvent(self, event): # event.setDropAction(QtCore.Qt.MoveAction) mime = event.mimeData() if mime.hasUrls(): urls = mime.urls() if len(urls) > 0: self.processDropedFile(urls[0].toLocalFile()) event.acceptProposedAction() def processDropedFile(self, filePath): root, ext = os.path.splitext(filePath) if ext == ".filter": # Read Filter self.openFilterFile(filePath=filePath) return elif ext == ".csv": self.openCSVFile(filePath=filePath) elif self.openImageFile(filePath=filePath): return elif self.openVideoFile(filePath=filePath): return def videoPlaybackInit(self): self.videoPlaybackWidget.hide() self.videoPlaybackWidget.frameChanged.connect(self.setFrame, Qt.QueuedConnection) def setFrame(self, frame, frameNo): if frame is not None: self.cv_img = frame self.currentFrameNo = frameNo self.updateInputGraphicsView() if self.videoInitialFlag == True: self.graphicsViewResized() self.videoInitialFlag = False self.evaluate() def imgInit(self): self.cv_img = cv2.imread( os.path.join(sampleDataPath, "color_filter_test.png")) self.frameBuffer = Queue() self.frameBufferItemGroup = QGraphicsItemGroup() self.frameBufferItemGroup.hide() self.inputPixmapRenderScene = QGraphicsScene() self.inputPixmapRenderScene.addItem(self.frameBufferItemGroup) self.inputScene = QGraphicsScene() self.inputGraphicsView.setScene(self.inputScene) self.inputGraphicsView.resizeEvent = self.graphicsViewResized # self.inputScene.addItem(self.frameBufferItemGroup) qimg = misc.cvMatToQImage(self.cv_img) self.inputPixmap = QPixmap.fromImage(qimg) self.inputPixmapItem = QGraphicsPixmapItem(self.inputPixmap) self.inputScene.addItem(self.inputPixmapItem) self.inputGraphicsView.mousePressEvent = self.inputGraphicsViewMousePressEvent self.inputGraphicsView.mouseMoveEvent = self.inputGraphicsViewMouseMoveEvent self.inputGraphicsView.mouseReleaseEvent = self.inputGraphicsViewMouseReleaseEvent self.inputGraphicsView.keyPressEvent = self.inputGraphicsViewKeyPressEvent self.inputGraphicsView.keyReleaseEvent = self.inputGraphicsViewKeyReleaseEvent self.inputGraphicsView.wheelEvent = self.inputGraphicsViewwheelEvent #self.inputGraphicsView.focusInEvent = self.inputGraphicsViewfocusInEvent self.inputGraphicsView.viewport().installEventFilter(self) self.inputGraphicsView.setMouseTracking(True) self.overlayScene = QGraphicsScene() self.inputGraphicsView.setOverlayScene(self.overlayScene) def inputGraphicsViewfocusInEvent(self, event): # QGraphicsView.focusInEvent(self.inputGraphicsView, event) def inputGraphicsViewMousePressEvent(self, event): if event.modifiers() == QtCore.Qt.ShiftModifier: # Comment out to permit the view for sending the event to the child scene. QGraphicsView.mousePressEvent(self.inputGraphicsView, event) else: self.drawingFlag = True if not self.videoPlaybackWidget.isPlaying(): self.videoPlaybackWidget.playButtonClicked() def inputGraphicsViewMouseMoveEvent(self, event): if event.modifiers() == QtCore.Qt.ShiftModifier: # Comment out to permit the view for sending the event to the child scene. QGraphicsView.mouseMoveEvent(self.inputGraphicsView, event) elif self.drawingFlag == True: pass #self.videoPlaybackWidget.moveNextButtonClicked() #self.handInputSystem.inputMouseMoveEvent(mousePosition,self.currentFrameNo) #print(self.currentFrameNo) #self.positionStack.append(mousePosition) #self.handInputSystem.inputMouseMoveEvent(mousePosition) def inputGraphicsViewMouseReleaseEvent(self, event): if self.drawingFlag == True: self.drawingFlag = False self.videoPlaybackWidget.playButtonClicked() self.handInputSystem.inputMouseReleaseEvent() self.handInputSystem.setPoints() # Comment out to permit the view for sending the event to the child scene. QGraphicsView.mouseReleaseEvent(self.inputGraphicsView, event) self.inputGraphicsView.viewport().setCursor(QtCore.Qt.ArrowCursor) def inputGraphicsViewKeyPressEvent(self, event): mousePosition = QCursor().pos() mousePosition = self.inputGraphicsView.mapFromGlobal(mousePosition) if event.type() == QtCore.QEvent.KeyPress: key = event.key() if key == QtCore.Qt.Key_Space: self.videoPlaybackWidget.playButtonClicked() elif key == QtCore.Qt.Key_A: self.videoPlaybackWidget.movePrevButtonClicked() elif key == QtCore.Qt.Key_D: self.videoPlaybackWidget.moveNextButtonClicked() elif key == QtCore.Qt.Key_Down: self.inputGraphicsViewScaleDown() elif key == QtCore.Qt.Key_Up: self.inputGraphicsViewScaleUp() pass elif key == QtCore.Qt.Key_R: self.graphicsViewResized() elif key == QtCore.Qt.Key_P: pass #self.handInputSystem.nextDataFrame() elif key == QtCore.Qt.Key_O: pass #self.handInputSystem.previousDataFrame() elif key == QtCore.Qt.Key_J: frameNo = self.handInputSystem.getLastInputedFrameIndex() self.videoPlaybackWidget.moveToFrame(frameNo) elif key == QtCore.Qt.Key_S: self.handInputSystem.saveCSV("./a.csv") QGraphicsView.keyPressEvent(self.inputGraphicsView, event) def inputGraphicsViewKeyReleaseEvent(self, event): QGraphicsView.keyReleaseEvent(self.inputGraphicsView, event) def inputGraphicsViewwheelEvent(self, event): scaleFactor = 1.15 if event.delta() > 0: # Zoom in self.inputGraphicsView.scale(scaleFactor, scaleFactor) else: # Zooming out self.inputGraphicsView.scale(1.0 / scaleFactor, 1.0 / scaleFactor) QGraphicsView.wheelEvent(self.inputGraphicsView, event) def inputGraphicsViewScaleDown(self): scaleFactor = 1.15 self.inputGraphicsView.scale(1.0 / scaleFactor, 1.0 / scaleFactor) def inputGraphicsViewScaleUp(self): scaleFactor = 1.15 self.inputGraphicsView.scale(scaleFactor, scaleFactor) def menuInit(self): self.actionSaveCSVFile.triggered.connect(self.saveCSVFile) self.actionOpenCSVFile.triggered.connect(self.openCSVFile) 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 ret = self.videoPlaybackWidget.openVideo(filePath) if ret == False: return False self.videoInitialFlag = True self.videoPlaybackWidget.show() self.dataFrameWidget.show() # self.evaluate() return True else: return False 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.videoPlaybackWidget.hide() self.updateInputGraphicsView() self.evaluate() return True else: return False def openCSVFile(self, activated=False, filePath=None): if filePath is None: filePath, _ = QFileDialog.getOpenFileName(None, 'Open CSV File', userDir, 'CSV files (*.csv)') if len(filePath) is not 0: self.df = pd.read_csv(filePath, index_col=0) if self.handInputSystem is not None: self.inputScene.removeItem(self.handInputSystem) self.handInputSystem = HandInputSystem() self.handInputSystem.setRect(self.inputScene.sceneRect()) self.inputScene.addItem(self.handInputSystem) self.handInputSystem.setDataFrame(self.df) self.handInputSystem.setPoints() self.dataFrameWidget.clear() self.dataFrameWidget.dataFrameNo = self.handInputSystem.dataFrameNo self.dataFrameWidget.editingNo = 0 for item in range(self.handInputSystem.dataFrameNo + 1): color = self.handInputSystem.itemList[item].getColor() print(item, color) self.dataFrameWidget.colorList.append(color) self.dataFrameWidget.setUniqueIDLabel() self.evaluate() def saveCSVFile(self, activated=False, filePath=None): #if self.df is not None: if self.handInputSystem.isDataFrame(): filePath, _ = QFileDialog.getSaveFileName(None, 'Save CSV File', userDir, "CSV files (*.csv)") if len(filePath) is not 0: logger.debug("Saving CSV file: {0}".format(filePath)) self.handInputSystem.saveCSV(filePath) def updateInputGraphicsView(self): # print("update") # self.inputScene.clear() self.inputScene.removeItem(self.inputPixmapItem) qimg = misc.cvMatToQImage(self.cv_img) self.inputPixmap = QPixmap.fromImage(qimg) p = QPainter(self.inputPixmap) sourceRect = self.inputPixmapRenderScene.sceneRect() self.inputPixmapRenderScene.render(p, QRectF(sourceRect), QRectF(sourceRect), QtCore.Qt.IgnoreAspectRatio) self.inputPixmapItem = QGraphicsPixmapItem(self.inputPixmap) rect = QtCore.QRectF(self.inputPixmap.rect()) self.inputScene.setSceneRect(rect) self.inputScene.addItem(self.inputPixmapItem) self.inputGraphicsView.viewport().update() # self.graphicsViewResized() def eventFilter(self, obj, event): if obj is self.inputGraphicsView.viewport() and event.type( ) == QEvent.Wheel: return True else: return False def graphicsViewResized(self, event=None): # print("resize") # print(self.inputScene) self.inputGraphicsView.fitInView( QtCore.QRectF(self.inputPixmap.rect()), QtCore.Qt.KeepAspectRatio) def evaluate(self): if not self.videoPlaybackWidget.isOpened(): return qimg = misc.cvMatToQImage(self.cv_img) pixmapItem = QGraphicsPixmapItem(QPixmap.fromImage(qimg)) pixmapItem.setOpacity(0.2) self.frameBuffer.put(pixmapItem) self.frameBufferItemGroup.addToGroup(pixmapItem) if self.frameBuffer.qsize() > 10: item = self.frameBuffer.get() self.frameBufferItemGroup.removeFromGroup(item) """ if self.trackingPathGroup is not None: self.trackingPathGroup.setPoints(self.currentFrameNo) """ if self.handInputSystem is not None: self.handInputSystem.setPoints(self.currentFrameNo) if self.drawingFlag is True: mousePosition = QCursor().pos() mousePosition = self.inputGraphicsView.mapFromGlobal( mousePosition) mousePosition = self.inputGraphicsView.mapToScene( mousePosition) pos = [mousePosition.x(), mousePosition.y()] self.handInputSystem.appendPosition(pos, self.currentFrameNo)
def _load(self): # Get list of all map files for current zone map_file_name = MapData.get_zone_dict()[self.zone.strip().lower()] extensions = ['.txt', '_1.txt', '_2.txt', '_3.txt', '_4.txt', '_5.txt'] maps = [ os.path.join(MAP_FILES_LOCATION, m) for m in [(map_file_name + e) for e in extensions] if os.path.exists(os.path.join(MAP_FILES_LOCATION, m)) ] all_x, all_y, all_z = [], [], [] # TODO: Remove the references to raw # Create Lines and Points for map_file in maps: with open(map_file, 'r') as f: for line in f.readlines(): line_type = line.lower()[0:1] data = [value.strip() for value in line[1:].split(',')] if line_type == 'l': # line x1, y1, z1, x2, y2, z2 = list(map(float, data[0:6])) self.raw['lines'].append( MapLine(x1=x1, y1=y1, z1=z1, x2=x2, y2=y2, z2=z2, color=self.color_transform( QColor(int(data[6]), int(data[7]), int(data[8]))))) all_x.extend((x1, x2)) all_y.extend((y1, y2)) all_z.append(min(z1, z2)) # if abs(z1 - z2) < 2: # if z1 == z2: # all_z.extend((z1, z2)) elif line_type == 'p': # point x, y, z = map(float, data[0:3]) self.raw['poi'].append( MapPoint(x=x, y=y, z=z, size=int(data[6]), text=str(data[7]), color=self.color_transform( QColor(int(data[3]), int(data[4]), int(data[5]))))) # Create Grid Lines lowest_x, highest_x, lowest_y, highest_y, lowest_z, highest_z = min( all_x), max(all_x), min(all_y), max(all_y), min(all_z), max(all_z) left, right = int(math.floor(lowest_x / 1000) * 1000), int( math.ceil(highest_x / 1000) * 1000) top, bottom = int(math.floor(lowest_y / 1000) * 1000), int( math.ceil(highest_y / 1000) * 1000) for number in range(left, right + 1000, 1000): self.raw['grid'].append( MapLine(x1=number, x2=number, y1=top, y2=bottom, z1=0, z2=0, color=QColor(255, 255, 255, 25))) for number in range(top, bottom + 1000, 1000): self.raw['grid'].append( MapLine(y1=number, y2=number, x1=left, x2=right, z1=0, z2=0, color=QColor(255, 255, 255, 25))) self.grid = QGraphicsPathItem() line_path = QPainterPath() for line in self.raw['grid']: line_path.moveTo(line.x1, line.y1) line_path.lineTo(line.x2, line.y2) self.grid.setPath(line_path) self.grid.setPen( QPen(line.color, config.data['maps']['grid_line_width'])) self.grid.setZValue(0) # Get z levels counter = Counter(all_z) # bunch together zgroups based on peaks with floor being low point before rise z_groups = [] last_value = None first_run = True for z in sorted(counter.items(), key=lambda x: x[0]): if last_value is None: last_value = z continue if (abs(last_value[0] - z[0]) < 20) or z[1] < 8: last_value = (last_value[0], last_value[1] + z[1]) else: if first_run: first_run = False if last_value[1] < 40 or abs(last_value[0] - z[0]) < 18: last_value = z continue z_groups.append(last_value[0]) last_value = z # get last iteration if last_value[1] > 50: z_groups.append(last_value[0]) self._z_groups = z_groups # Create QGraphicsPathItem for lines seperately to retain colors temp_dict = {} for l in self.raw['lines']: lz = min(l.z1, l.z2) lz = self.get_closest_z_group(lz) if not temp_dict.get(lz, None): temp_dict[lz] = {'paths': {}} lc = l.color.getRgb() if not temp_dict[lz]['paths'].get(lc, None): path_item = QGraphicsPathItem() path_item.setPen( QPen(l.color, config.data['maps']['line_width'])) temp_dict[lz]['paths'][lc] = path_item path = temp_dict[lz]['paths'][lc].path() path.moveTo(l.x1, l.y1) path.lineTo(l.x2, l.y2) temp_dict[lz]['paths'][lc].setPath(path) # Group QGraphicsPathItems into QGraphicsItemGroups and update self for z in temp_dict.keys(): item_group = QGraphicsItemGroup() for (_, path) in temp_dict[z]['paths'].items(): item_group.addToGroup(path) self[z] = {'paths': None, 'poi': []} self[z]['paths'] = item_group # Create Points of Interest for p in self.raw['poi']: z = self.get_closest_z_group(p.z) self[z]['poi'].append(PointOfInterest(location=p)) self.geometry = MapGeometry( lowest_x=lowest_x, highest_x=highest_x, lowest_y=lowest_y, highest_y=highest_y, lowest_z=lowest_z, highest_z=highest_z, center_x=int(highest_x - (highest_x - lowest_x) / 2), center_y=int(highest_y - (highest_y - lowest_y) / 2), width=int(highest_x - lowest_x), height=int(highest_y - lowest_y), z_groups=z_groups)
class InitMap(): def __init__(self, parent): super().__init__() self.canvas = parent self.scene = parent.scene self.tagZ = 0 self.pathTagZ = 0 ## only by paths self.mapSet = False self.tagSet = False self.pathSet = False self.mapRect = QRectF() self.selections = [] self.pathGroup = None self.tagGroup = None self.pathTagGroup = None self.paths = [] ### -------------------------------------------------------- def addSelectionsFromCanvas(self): if not self.selections: self.mapSelections() if len(self.selections) > 0: self.addMapItem() def mapSelections(self): self.selections = [] rect = QRect(self.canvas.rubberBand.geometry()) for pix in self.scene.items(): if pix.type == 'pix': p = pix.sceneBoundingRect() x = int(p.x() + p.width() / 2) y = int(p.y() + p.height() / 2) if rect.contains(x, y): pix.setSelected(True) self.selections.append(pix.id) elif pix.zValue() <= common["pathZ"]: break def addMapItem(self): self.removeMapItem() self.mapSet = True self.mapRect = self.mapBoundingRects() self.canvas.rubberBand.setGeometry( QRect(self.canvas.origin, QSize(0, 0))) self.map = MapItem(self.mapRect, self) self.map.setZValue(self.toFront(50)) ## higher up than tags self.scene.addItem(self.map) def updateMap(self): self.updatePixItemPos() self.addMapItem() def removeMap(self): self.updatePixItemPos() self.clearMap() def clearMap(self): if self.mapSet: self.removeMapItem() self.mapRect = QRectF() self.selections = [] self.mapSet = False def removeMapItem(self): for pix in self.scene.items(): if pix.type == 'map': self.scene.removeItem(pix) break def mapBoundingRects(self): tx, ty = common["ViewW"], common["ViewH"] bx, by = 0, 0 for pix in self.scene.items(): if pix.type == 'pix' and pix.id in self.selections: p = pix.sceneBoundingRect() x, y, w, h = p.x(), p.y(), p.width(), p.height() if x < tx: ## setting top left tx = x if y < ty: ty = y if x + w > bx: ## setting bottom right bx = x + w if y + h > by: by = y + h elif pix.zValue() <= common["pathZ"]: break return QRectF(tx, ty, bx - tx, by - ty) selections = [] def updatePixItemPos(self): for pix in self.scene.items(): if pix.type == 'pix': p = pix.pos() pix.x = p.x() pix.y = p.y() elif pix.zValue() <= common["pathZ"]: break def toggleMap(self): if self.mapSet == False: self.selections = [] for pix in self.scene.selectedItems(): self.selections.append(pix.id) if self.selections or self.canvas.hasHiddenPix(): self.addMapItem() else: self.removeMap() ### -------------------------------------------------------- def toggleTagItems(self, pid=All): if self.canvas.pathMakerOn: return if self.tagSet: self.clearTagGroup() self.clearPaths() return if self.scene.items(): if self.pathSet: QTimer.singleShot(200, self.clearPaths) self.addTagGroup() k = 0 self.tagSet = False for pix in self.scene.items(): if pix.type == 'pix': k += 1 if pid == All: self.tagIt(pix) elif pid == pix.id: ## single tag self.tagIt(pix) break elif pix.zValue() <= common["pathZ"]: break if k > 0: self.tagSet = True else: self.clearTagGroup() def addTagGroup(self): self.tagZ = self.toFront(20.0) ## otherwise it can be hidden self.tagGroup = QGraphicsItemGroup() self.tagGroup.setZValue(self.tagZ) self.scene.addItem(self.tagGroup) def clearTagGroup(self): if self.tagSet: self.scene.removeItem(self.tagGroup) self.tagSet = False def tagIt(self, pix): p = pix.sceneBoundingRect() x = p.x() + p.width() * .45 y = p.y() + p.height() * .45 if 'frame' in pix.fileName: x, y = common["ViewW"] * .47, common["ViewH"] - 35 pix.tag = "" tag = TagIt(self.canvas.control, pix.tag, '', pix.zValue()) tag.setPos(x, y) tag.setZValue(self.tagZ) self.tagGroup.addToGroup(tag) self.tagSet = True ### -------------------------------------------------------- def togglePaths(self): if self.canvas.pathMakerOn: return if self.pathSet: self.clearPaths() return if self.scene.items(): k = 0 self.pathSet = False ## force clearPaths if fails QTimer.singleShot(200, self.clearTagGroup) ## the other tags self.addPathGroup() self.addPathTagGroup() for pix in self.scene.items(): if pix.type == 'pix': if pix.tag.endswith('.path'): k += self.displayPath(pix) elif pix.anime and pix.anime.state() == 2: ## running pix.anime.pause() elif pix.zValue() <= common["pathZ"]: break if k > 0: self.pathSet = True else: self.clearPaths() def addPathGroup(self): self.pathGroup = QGraphicsItemGroup() self.pathGroup.setZValue(common["pathZ"]) self.scene.addItem(self.pathGroup) def addPathTagGroup(self): ## add pathTags group to keep tags separate and visible self.pathTagZ = self.toFront(25.0) ## otherwise it can be hidden self.pathTagGroup = QGraphicsItemGroup() self.pathTagGroup.setZValue(self.pathTagZ) self.scene.addItem(self.pathTagGroup) def clearPaths(self): if self.pathSet: if self.pathGroup: self.scene.removeItem(self.pathGroup) if self.pathTagGroup: self.scene.removeItem(self.pathTagGroup) for pix in self.scene.items(): if pix.type == 'pix' and not pix.tag.endswith('.path'): if pix.anime and pix.anime.state() == 1: ## paused if self.canvas.control != 'resume': pix.anime.resume() elif pix.zValue() <= common["pathZ"]: break self.pathSet = False self.paths = [] def displayPath(self, pix): tag = pix.tag if 'Random' in tag: tag = tag[7:] ## don't add duplicates - causes performance issues if not tag in self.paths: self.paths.append(tag) self.addPainterPath(tag) return 1 else: return 0 def addPainterPath(self, tag): color = getColorStr() path = sidePath.pathLoader(tag) ## return painter path pathPt = path.pointAtPercent(0.0) ## so its consistent ## use painter path pathItem = QGraphicsPathItem(path) pathItem.setPen(QPen(QColor(color), 3, Qt.DashDotLine)) pathItem.setFlag(QGraphicsPathItem.ItemIsMovable, False) self.pathGroup.addToGroup(pathItem) self.addTag(tag, color, pathPt) def addTag(self, tag, color, pt): ## use same offsets and color as path tag = TagIt('', tag, color) tag.setPos(pt) tag.setZValue(self.pathTagZ) ## use pathTagZ instead of tagZ self.pathTagGroup.addToGroup(tag) def lastZval(self, str): ## finds the lowest pix or bkg zValue last = 100000.0 for itm in self.scene.items(): if itm.type == str and itm.zValue() < last: last = itm.zValue() return last def toFront(self, inc): ## finds the highest pixitem zValue first = 0 ## returns it plus the increment for pix in self.scene.items(): if pix.type == 'pix': first = pix.zValue() break elif pix.zValue() <= common["pathZ"]: break return inc + first def setOriginPt(self, pix): self.updateWidthHeight(pix) op = QPointF(pix.width / 2, pix.height / 2) pix.setTransformOriginPoint(op) def updateWidthHeight(self, pix): brt = pix.boundingRect() pix.width = brt.width() pix.height = brt.height()
class AMANDisplay(QGraphicsView): def __init__(self): super().__init__() self.setGeometry(0, 0, 500, 600) self.setStyleSheet('background-color:#233370') self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.scene = QGraphicsScene(0, 0, 500, 600) # Timeline boundaries pen = QPen(QColor('white')) brush = QBrush(QColor('#233370')) self.scene.addLine(220, 0, 220, 600, pen) self.scene.addLine(280, 0, 280, 600, pen) self.scene.addLine(0, 30, 500, 30, pen) timelinebox = self.scene.addRect(220, 30, 60, 540, pen, brush) timelinebox.setFlag(timelinebox.ItemClipsChildrenToShape, True) # Timeline scale self.timeline = QGraphicsItemGroup() self.timeline.setParentItem(timelinebox) self.timeticks = [] for i in range(40): y = 15 * i w = 6 if i % 5 == 0: w = 10 self.timeticks.append(self.scene.addText('%02d' % (40 - i), QFont('Courier', 10))) self.timeticks[-1].setPos(240, y - 10) self.timeticks[-1].setDefaultTextColor(QColor('white')) self.timeline.addToGroup(self.timeticks[-1]) self.timeline.addToGroup(self.scene.addLine(220, y, 220 + w, y, pen)) self.timeline.addToGroup(self.scene.addLine(280 - w, y, 280, y, pen)) self.lrwy = self.scene.addText('18R', QFont('Arial', 20, 50)) self.lrwy.setPos(1, 1) self.lrwy.setDefaultTextColor(QColor('white')) # Finalize self.setScene(self.scene) self.show() def update(self, simt, data): # data has: ids, iafs, eats, etas, delays, rwys, spdratios # First delete old labels for key, in self.aircraft.keys: if key not in data.ids: # del label del self.aircraft[key] for i in len(data.ids): if data.ids[i] not in self.aircraft: # self.aircraft[data.ids[i]] = QLabel() pass # Generate the new label text and position newtext = '<font color=Red>bla</font>' # veranderen lbl = self.aircraft[data.ids[i]] lbl.setText(newtext) lbl.move(posx, posy) # move in pixels
class Imageobj(QGraphicsView): leftMouseButtonPressed = pyqtSignal(float, float) rightMouseButtonPressed = pyqtSignal(float, float) leftMouseButtonReleased = pyqtSignal(float, float) rightMouseButtonReleased = pyqtSignal(float, float) leftMouseButtonDoubleClicked = pyqtSignal(float, float) rightMouseButtonDoubleClicked = pyqtSignal(float, float) def __init__(self): QGraphicsView.__init__(self) # Image is displayed as a QPixmap in a QGraphicsScene attached to this QGraphicsView. self.scene = QGraphicsScene() self.setScene(self.scene) self.rectgroup = QGraphicsItemGroup() self.linegroup = QGraphicsItemGroup() self._pixmapHandle = None self.canZoom = True self.canPan = True self.zoomStack = [] self.aspectRatioMode = Qt.KeepAspectRatio self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.begin = QPoint() self.end = QPoint() self.helper_bool = False self.helper_bool2 = False self.rect = QGraphicsRectItem() self.line = QGraphicsLineItem() def hasImage(self): """ Returns whether or not the scene contains an image pixmap. """ return self._pixmapHandle is not None 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 loadImageFromFile(self, fileName=""): """ Load an image from file. Without any arguments, loadImageFromFile() will popup a file dialog to choose the image file. With a fileName argument, loadImageFromFile(fileName) will attempt to load the specified image file directly. """ fileDir = os.path.dirname(os.path.realpath('__file__')) results_dir = os.path.join(fileDir, 'results\\200_frames_of_bloodflow_results') if len(fileName) == 0: if QT_VERSION_STR[0] == '4': fileName = QFileDialog.getOpenFileName(self, "Open image file.") elif QT_VERSION_STR[0] == '5': fileName, dummy = QFileDialog.getOpenFileName( self, "Open image file.") if len(fileName) and os.path.isfile(fileName): imageName, file_data = self.create_image(fileName, results_dir) image = QImage(imageName) self.setImage(image) print(fileName) def Extract_image_and_metadata(self, file_data): global file_metadata im2show_path = file_data["im2show_path"] metadata_path = file_data["metadata_path"] # fileName = file_data["fileName"] filepath = file_data["path"] if os.path.isfile(metadata_path): with open(metadata_path, 'r') as fp: file_metadata = json.load(fp) else: with tifffile.TiffFile(filepath) as tif: file_metadata = tif.scanimage_metadata with open(metadata_path, 'w') as fp: json.dump(file_metadata, fp) if not os.path.isfile(im2show_path): tif_original = tifffile.imread(filepath) # first_five = tif_full_original[1:10:2]#selecting 5 image from tif, only vessels tif_original_size = tif_original.shape if len(tif_original_size) == 2: tif = tif_original.copy() arr = tif else: first_five = tif_original[1:10:2].copy() if file_metadata["SI.hScan2D.bidirectional"]: num_im, w, h = first_five.shape tif = np.zeros((num_im, int(h / 2), w)) for i in range(num_im): tif[i] = first_five[i][::2] else: tif = tif_original.copy() arr = tif[0] tif_size = tif.shape print(tif_size) # image5 = (tif[0]/5)+(tif[1]/5)+(tif[2]/5)+(tif[3]/5)+(tif[4]/5) # arr_avg=np.array(np.round(image5),dtype=np.int16) #round the pixels values # arr = tif[0] im2show = Image.fromarray(arr) try: im2show.save(im2show_path) except OSError: im2show = im2show.convert(mode='I') im2show.save(im2show_path) return file_metadata def updateViewer(self): """ Show current zoom (if showing entire image, apply current aspect ratio mode). """ if not self.hasImage(): return if len(self.zoomStack) and self.sceneRect().contains( self.zoomStack[-1]): self.fitInView(self.zoomStack[-1], Qt.IgnoreAspectRatio ) # Show zoomed rect (ignore aspect ratio). else: self.zoomStack = [ ] # Clear the zoom stack (in case we got here because of an invalid zoom). self.fitInView( self.sceneRect(), self.aspectRatioMode ) # Show entire image (use current aspect ratio mode). def resizeEvent(self, event): """ Maintain current zoom on resize. """ self.updateViewer() def mousePressEvent(self, event): """ Start mouse pan or zoom mode. """ scenePos = self.mapToScene(event.pos()) if event.button() == Qt.LeftButton: if self.canPan and self.helper_bool: self.setDragMode(QGraphicsView.RubberBandDrag) elif self.canPan and self.helper_bool2: self.setDragMode(QGraphicsView.ScrollHandDrag) self.start = scenePos #QGraphicsView.mouseMoveEvent(self,event) #self.setMouseTracking(True) self.leftMouseButtonPressed.emit(scenePos.x(), scenePos.y()) # self.cursorStartPosition = self.leftMouseButtonPressed.emit(scenePos.x(), scenePos.y()) # self.start = QPoint(self.cursorStartPosition.x(),self.cursorStartPosition.y()) elif event.button() == Qt.RightButton: if self.canZoom: self.setDragMode(QGraphicsView.RubberBandDrag) self.rightMouseButtonPressed.emit(scenePos.x(), scenePos.y()) QGraphicsView.mousePressEvent(self, event) def mouseReleaseEvent(self, event): """ Stop mouse pan or zoom mode (apply zoom if valid). """ QGraphicsView.mouseReleaseEvent(self, event) scenePos = self.mapToScene(event.pos()) if event.button() == Qt.LeftButton: if self.helper_bool: viewBBox = self.zoomStack[-1] if len( self.zoomStack) else self.sceneRect() selectionBBox = self.scene.selectionArea().boundingRect( ).intersected(viewBBox) if selectionBBox.isValid(): self.rect.setRect(selectionBBox) self.rect.setPen(QPen(Qt.white)) self.scene.addItem(self.rect) elif self.helper_bool2: viewBBox = self.zoomStack[-1] if len( self.zoomStack) else self.sceneRect() self.cursorCurrentPosition = scenePos self.current = QPointF(self.cursorCurrentPosition.x(), self.cursorCurrentPosition.y()) pen = QPen(Qt.red, 1, Qt.SolidLine) self.line.setLine(QLineF(self.start, self.current)) self.line.setPen(pen) self.scene.addItem(self.line) self.setDragMode(QGraphicsView.NoDrag) self.leftMouseButtonReleased.emit(scenePos.x(), scenePos.y()) elif event.button() == Qt.RightButton: if self.canZoom: viewBBox = self.zoomStack[-1] if len( self.zoomStack) else self.sceneRect() selectionBBox = self.scene.selectionArea().boundingRect( ).intersected(viewBBox) self.scene.setSelectionArea( QPainterPath()) # Clear current selection area. if selectionBBox.isValid() and (selectionBBox != viewBBox): self.zoomStack.append(selectionBBox) self.updateViewer() self.setDragMode(QGraphicsView.NoDrag) self.rightMouseButtonReleased.emit(scenePos.x(), scenePos.y()) # self.scene.addItem(self.group) self.updateViewer() def mouseDoubleClickEvent(self, event): """ Show entire image. """ scenePos = self.mapToScene(event.pos()) if event.button() == Qt.LeftButton: self.leftMouseButtonDoubleClicked.emit(scenePos.x(), scenePos.y()) elif event.button() == Qt.RightButton: if self.canZoom: self.zoomStack = [] # Clear zoom stack. self.updateViewer() self.rightMouseButtonDoubleClicked.emit(scenePos.x(), scenePos.y()) QGraphicsView.mouseDoubleClickEvent(self, event) def approve_obj(self): self.scene.removeItem(self.rect) self.scene.removeItem(self.line) viewBBox = self.zoomStack[-1] if len( self.zoomStack) else self.sceneRect() selectionBBox = self.scene.selectionArea().boundingRect().intersected( viewBBox) rect = QGraphicsRectItem() rect.setRect(selectionBBox) rect.setPen(QPen(Qt.green)) self.rectgroup.addToGroup(rect) self.scene.addItem(self.rectgroup) line = QGraphicsLineItem() line.setLine(QLineF(self.start, self.current)) line.setPen(QPen(Qt.green)) self.linegroup.addToGroup(line) self.scene.addItem(self.linegroup) return (selectionBBox, self.start, self.current) def create_fromDB(self, pos_list=[], obj_type=""): if obj_type == "rois": num_rois = len(pos_list) for i in range(num_rois): points = pos_list[i] rect = QGraphicsRectItem() rect.setPen(QPen(Qt.green)) rect.setRect(points[0], points[1], points[2], points[3]) self.rectgroup.addToGroup(rect) self.scene.addItem(self.rectgroup) elif obj_type == "vector": num_vec = len(pos_list) for i in range(num_vec): points = pos_list[i] vec = QGraphicsLineItem() vec.setPen(QPen(Qt.green)) vec.setLine(points[0][0], points[0][1], points[1][0], points[1][1]) self.linegroup.addToGroup(vec) self.scene.addItem(self.linegroup) def mark_item(self, item_num): rect_items = self.rectgroup.childItems() line_items = self.linegroup.childItems() rect_item = rect_items[item_num] line_item = line_items[item_num] rect_item.setPen(QPen(Qt.red)) line_item.setPen(QPen(Qt.red)) rect_items.remove(rect_item) line_items.remove(line_item) for i in rect_items: i.setPen(QPen(Qt.green)) for i in line_items: i.setPen(QPen(Qt.green)) def delete_roi(self, num): self.scene.removeItem(self.rectgroup) self.scene.removeItem(self.linegroup) rect_item = self.rectgroup.childItems()[num] line_item = self.linegroup.childItems()[num] self.rectgroup.removeFromGroup(rect_item) self.linegroup.removeFromGroup(line_item) self.scene.addItem(self.rectgroup) self.scene.addItem(self.linegroup) def restart_obj(self): self.scene.removeItem(self.rectgroup) self.scene.removeItem(self.linegroup) rect_items = self.rectgroup.childItems() line_items = self.linegroup.childItems() for rect_item in rect_items: self.rectgroup.removeFromGroup(rect_item) for line_item in line_items: self.linegroup.removeFromGroup(line_item)