def mappedPolygon( self, polygon, path = None, percent = 0.5 ): """ Maps the inputed polygon to the inputed path \ used when drawing items along the path. If no \ specific path is supplied, then this object's own \ path will be used. It will rotate and move the \ polygon according to the inputed percentage. :param polygon <QPolygonF> :param path <QPainterPath> :param percent <float> :return <QPolygonF> mapped_poly """ translatePerc = percent anglePerc = percent # we don't want to allow the angle percentage greater than 0.85 # or less than 0.05 or we won't get a good rotation angle if ( 0.95 <= anglePerc ): anglePerc = 0.98 elif ( anglePerc <= 0.05 ): anglePerc = 0.05 if ( not path ): path = self.path() if ( not (path and path.length()) ): return QPolygonF() # transform the polygon to the path point = path.pointAtPercent(translatePerc) angle = path.angleAtPercent(anglePerc) # rotate about the 0 axis transform = QTransform().rotate(-angle) polygon = transform.map(polygon) # move to the translation point transform = QTransform().translate(point.x(), point.y()) # create the rotated polygon mapped_poly = transform.map(polygon) self._polygons.append(mapped_poly) return mapped_poly
def _updateLayout(self): rect = self.geometry() n = len(self._items) if not n: return regions = venn_diagram(n, shape=self.shapeType) # The y axis in Qt points downward transform = QTransform().scale(1, -1) regions = list(map(transform.map, regions)) union_brect = reduce(QRectF.united, (path.boundingRect() for path in regions)) scalex = rect.width() / union_brect.width() scaley = rect.height() / union_brect.height() scale = min(scalex, scaley) transform = QTransform().scale(scale, scale) regions = [transform.map(path) for path in regions] center = rect.width() / 2, rect.height() / 2 for item, path in zip(self.items(), regions): item.setPath(path) item.setPos(*center) intersections = venn_intersections(regions) assert len(intersections) == 2 ** n assert len(self.vennareas()) == 2 ** n anchors = [(0, 0)] + subset_anchors(self._items) anchor_transform = QTransform().scale(rect.width(), -rect.height()) for i, area in enumerate(self.vennareas()): area.setPath(intersections[setkey(i, n)]) area.setPos(*center) x, y = anchors[i] anchor = anchor_transform.map(QPointF(x, y)) area.setTextAnchor(anchor) area.setZValue(30) self._updateTextAnchors()
def _updateLayout(self): rect = self.geometry() n = len(self._items) if not n: return regions = venn_diagram(n, shape=self.shapeType) # The y axis in Qt points downward transform = QTransform().scale(1, -1) regions = list(map(transform.map, regions)) union_brect = reduce(QRectF.united, (path.boundingRect() for path in regions)) scalex = rect.width() / union_brect.width() scaley = rect.height() / union_brect.height() scale = min(scalex, scaley) transform = QTransform().scale(scale, scale) regions = [transform.map(path) for path in regions] center = rect.width() / 2, rect.height() / 2 for item, path in zip(self.items(), regions): item.setPath(path) item.setPos(*center) intersections = venn_intersections(regions) assert len(intersections) == 2**n assert len(self.vennareas()) == 2**n anchors = [(0, 0)] + subset_anchors(self._items) anchor_transform = QTransform().scale(rect.width(), -rect.height()) for i, area in enumerate(self.vennareas()): area.setPath(intersections[setkey(i, n)]) area.setPos(*center) x, y = anchors[i] anchor = anchor_transform.map(QPointF(x, y)) area.setTextAnchor(anchor) area.setZValue(30) self._updateTextAnchors()
def ellipse_path(center, a, b, rotation=0): if not isinstance(center, QPointF): center = QPointF(*center) brect = QRectF(-a, -b, 2 * a, 2 * b) path = QPainterPath() path.addEllipse(brect) if rotation != 0: transform = QTransform().rotate(rotation) path = transform.map(path) path.translate(center) return path
def _define_symbols(): """ Add symbol ? to ScatterPlotItemSymbols, reflect the triangle to point upwards """ symbols = pyqtgraph.graphicsItems.ScatterPlotItem.Symbols path = QPainterPath() path.addEllipse(QRectF(-0.35, -0.35, 0.7, 0.7)) path.moveTo(-0.5, 0.5) path.lineTo(0.5, -0.5) path.moveTo(-0.5, -0.5) path.lineTo(0.5, 0.5) symbols["?"] = path tr = QTransform() tr.rotate(180) symbols['t'] = tr.map(symbols['t'])
def overlay_for(pt1, pt2, frequency): # Construct the line-geometry, we'll use this to construct the ellipsoid line = QLineF(pt1, pt2) # Determine the radius for the ellipsoid radius = fresnel_radius(line.length(), frequency) # Draw the ellipsoid zone = QPainterPath() zone.addEllipse(QPointF(0., 0.), line.length() / 2, radius) # Rotate the ellipsoid - same angle as the line transform = QTransform() transform.rotate(-line.angle()) zone = transform.map(zone) # Center the zone over the line lc = QRectF(pt1, pt2).center() zc = zone.boundingRect().center() zone.translate(lc.x() - zc.x(), lc.y() - zc.y()) return line, zone
def run_loader(self): filename = self.result try: self.retryObject = None # First, prepare the data by getting the images and computing how big they # should be f = open(filename) first_line = f.readline() f.close() if first_line.startswith("TRKR_VERSION"): result = Result(None) result.load(self.result, **self._loading_arguments) result_type = "Growth" else: result = TrackingData() result.load(self.result, **self._loading_arguments) result_type = "Data" self.result = result self.result_type = result_type if result_type == "Data": data = result images = data.images_name if data.cells: self.has_cells = True self.has_walls = True else: self.has_cells = False self.has_walls = False self.has_points = bool(data.cell_points) else: data = result.data images = result.images self.has_cells = False self.has_walls = False self.has_points = False self.images = images cache = image_cache.cache self.update_nb_images(len(result)) bbox = QRectF() ms = data.minScale() for i in range(len(result)): img_name = images[i] img_data = data[img_name] img = cache.image(data.image_path(img_name)) matrix = QTransform() matrix = img_data.matrix() sc = QTransform() sc.scale(1.0/ms, 1.0/ms) matrix *= sc r = QRectF(img.rect()) rbox = matrix.map(QPolygonF(r)).boundingRect() bbox |= rbox log_debug("Image '%s':\n\tSize = %gx%g\n\tTransformed = %gx%g %+g %+g\n\tGlobal bbox = %gx%g %+g %+g\n" % (img_name, r.width(), r.height(), rbox.width(), rbox.height(), rbox.left(), rbox.top(), bbox.width(), bbox.height(), bbox.left(), bbox.top())) log_debug("Matrix:\n%g\t%g\t%g\n%g\t%g\t%g\n" % (matrix.m11(), matrix.m12(), matrix.dx(), matrix.m21(), matrix.m22(), matrix.dy())) if result_type == "Growth": if result.cells[i]: self.has_cells = True if result.walls[i]: self.has_walls = True self.has_points = bool(result.data.cell_points) self.nextImage() translate = bbox.topLeft() translate *= -1 self.translate = translate size = bbox.size().toSize() self.img_size = size self._crop = QRect(QPoint(0,0), size) self.finished() self._loading_arguments = {} # All done, we don't need that anymore except RetryTrackingDataException as ex: ex.filename = filename self.retryObject = ex self.finished() return except Exception as ex: _, _, exceptionTraceback = sys.exc_info() self.abort(ex, traceback=exceptionTraceback) raise
msg = object_detect.objects.data if (len(msg)): print("Len: {}".format(len(msg))) j = 0 while j < len(msg): idx = msg[j] objectWidth = msg[j + 1] objectHeight = msg[j + 2] # Find corners Qt qtHomography = QTransform(msg[j + 3], msg[j + 4], msg[j + 5], msg[j + 6], msg[j + 7], msg[j + 8], msg[j + 9], msg[j + 10], msg[j + 11]) qtTopLeft = qtHomography.map(QPointF(0, 0)) qtTopRight = qtHomography.map(QPointF(objectWidth, 0)) qtBottomLeft = qtHomography.map(QPointF(0, objectHeight)) qtBottomRight = qtHomography.map( QPointF(objectWidth, objectHeight)) print( "Object {} detected, Qt corners at ({},{}) ({},{}) ({},{}) ({},{})\n" .format(idx, qtTopLeft.x(), qtTopLeft.y(), qtTopRight.x(), qtTopRight.y(), qtBottomLeft.x(), qtBottomLeft.y(), qtBottomRight.x(), qtBottomRight.y())) topleft = (int(qtTopLeft.x()), int(qtTopLeft.y())) bottomright = (int(qtBottomRight.x()), int(qtBottomRight.y())) cv2.rectangle(cv2_img, topleft, bottomright, (255, 255, 255), 3) #cv2.imshow("Teste", cv2_img)
def paintEvent(self, event): painter = QPainter(self) width = self.width() height = self.height() if DEBUG: painter.fillRect(0, 0, width, height, Qt.blue) else: painter.fillRect(event.rect(), self.plot.canvas_color) y_min_scale = self.plot.y_scale.value_min y_max_scale = self.plot.y_scale.value_max factor_x = float(width) / self.plot.history_length_x factor_y = float(height - 1) / max( y_max_scale - y_min_scale, EPSILON ) # -1 to accommodate the 1px width of the curve if self.plot.x_min != None and self.plot.x_max != None: x_min = self.plot.x_min x_max = self.plot.x_max if self.plot.curve_start == "left": curve_x_offset = 0 else: curve_x_offset = round((self.plot.history_length_x - (x_max - x_min)) * factor_x) transform = QTransform() transform.translate( curve_x_offset, height - 1 + self.plot.curve_y_offset ) # -1 to accommodate the 1px width of the curve transform.scale(factor_x, -factor_y) transform.translate(-x_min, -y_min_scale) if self.plot.curve_motion_granularity > 1: self.plot.partial_update_width = math.ceil(transform.map(QLineF(0, 0, 1.5, 0)).length()) inverted_event_rect = transform.inverted()[0].mapRect(QRectF(event.rect())) painter.save() painter.setTransform(transform) for c in range(len(self.plot.curves_x)): if not self.plot.curves_visible[c]: continue curve_x = self.plot.curves_x[c] curve_y = self.plot.curves_y[c] path = QPainterPath() lineTo = path.lineTo if self.plot.curve_motion_granularity > 1: start = max(min(bisect.bisect_left(curve_x, inverted_event_rect.left()), len(curve_x) - 1) - 1, 0) else: start = 0 path.moveTo(curve_x[start], curve_y[start]) for i in xrange(start + 1, len(curve_x)): lineTo(curve_x[i], curve_y[i]) painter.setPen(self.plot.configs[c][1]) painter.drawPath(path) painter.restore()
def run_loader(self): filename = self.result try: self.retryObject = None # First, prepare the data by getting the images and computing how big they # should be f = open(filename) first_line = f.readline() f.close() if first_line.startswith("TRKR_VERSION"): result = Result(None) result.load(self.result, **self._loading_arguments) result_type = "Growth" else: result = TrackingData() result.load(self.result, **self._loading_arguments) result_type = "Data" self.result = result self.result_type = result_type if result_type == "Data": data = result images = data.images_name if data.cells: self.has_cells = True self.has_walls = True else: self.has_cells = False self.has_walls = False self.has_points = bool(data.cell_points) else: data = result.data images = result.images self.has_cells = False self.has_walls = False self.has_points = False self.images = images cache = image_cache.cache self.update_nb_images(len(result)) bbox = QRectF() ms = data.minScale() for i in range(len(result)): img_name = images[i] img_data = data[img_name] img = cache.image(data.image_path(img_name)) matrix = QTransform() matrix = img_data.matrix() sc = QTransform() sc.scale(1.0 / ms, 1.0 / ms) matrix *= sc r = QRectF(img.rect()) rbox = matrix.map(QPolygonF(r)).boundingRect() bbox |= rbox log_debug( "Image '%s':\n\tSize = %gx%g\n\tTransformed = %gx%g %+g %+g\n\tGlobal bbox = %gx%g %+g %+g\n" % (img_name, r.width(), r.height(), rbox.width(), rbox.height(), rbox.left(), rbox.top(), bbox.width(), bbox.height(), bbox.left(), bbox.top())) log_debug("Matrix:\n%g\t%g\t%g\n%g\t%g\t%g\n" % (matrix.m11(), matrix.m12(), matrix.dx(), matrix.m21(), matrix.m22(), matrix.dy())) if result_type == "Growth": if result.cells[i]: self.has_cells = True if result.walls[i]: self.has_walls = True self.has_points = bool(result.data.cell_points) self.nextImage() translate = bbox.topLeft() translate *= -1 self.translate = translate size = bbox.size().toSize() self.img_size = size self._crop = QRect(QPoint(0, 0), size) self.finished() self._loading_arguments = { } # All done, we don't need that anymore except RetryTrackingDataException as ex: ex.filename = filename self.retryObject = ex self.finished() return except Exception as ex: _, _, exceptionTraceback = sys.exc_info() self.abort(ex, traceback=exceptionTraceback) raise
class TrackingScene(QGraphicsScene): """ Signals: - hasSelection(bool) - realSceneSizeChanged """ hasSelectionChanged = Signal(bool) realSceneSizeChanged = Signal() zoomIn = Signal([], [QPointF]) zoomOut = Signal([], [QPointF]) templatePosChange = Signal(QPointF) Pan = "Pan" Add = "Add" Move = "Move" ZoomIn = "ZoomIn" ZoomOut = "ZoomOut" AddCell = "AddCell" RemoveCell = "RemoveCell" modes = [Pan, Add, Move, AddCell, RemoveCell, ZoomIn, ZoomOut] def __init__(self, undo_stack, delete_act, sel_actions, *args): """ Constructor """ params = parameters.instance QGraphicsScene.__init__(self, *args) self.delete_act = delete_act self.undo_stack = undo_stack self.data_manager = None self._mode = None self.link = None self.image_path = None self.image_name = None self.background_image = None self.template = TemplateItem() self.template.setPos(QPointF(0, 0)) self.template.setVisible(params.show_template) self.show_template = False self.points = {} self.cells = {} self._real_scene_rect = QRectF() params.pointParameterChange.connect(self.updatePoints) params.cellParameterChange.connect(self.updateCells) params.searchParameterChange.connect(self.updateTemplate) self.had_selection = None self.selectionChanged.connect(self.updateSelectionActions) self.current_data = None self.back_matrix = QTransform() self.invert_back_matrix = QTransform() self.clear() popup = QMenu("Scene menu") validate_cell_act = popup.addAction("Validate cell", self.validateCell) validate_cell_act.setVisible(False) self._validate_cell_act = validate_cell_act lifespan_act = popup.addAction("Change cell lifespan", self.changeLifespan) lifespan_act.setVisible(False) self.lifespan_act = lifespan_act make_starshape_act = popup.addAction("Make cell star shaped", self.makeCellStarshaped) make_starshape_act.setVisible(False) self.make_starshape_act = make_starshape_act sel = popup.addMenu("Selection") for act in sel_actions: if act == "-": sel.addSeparator() else: sel.addAction(act) popup.addAction(delete_act) self._popup = popup self._sel_rect = None self._sel_first_pt = None self._current_cell = None self._first_point = None self.mode = TrackingScene.Pan def __del__(self): cleanQObject(self) def hasSelection(self): """ Returns true if any item is selected """ for pt in self.items(): if isinstance(pt, PointItem) and pt.isSelected(): return True return False def updateSelectionActions(self): """ Slot called when the selection changed. May emit the signal `hasSelection(bool)` """ try: value = self.hasSelection() if value != self.had_selection: self.had_selection = value self.hasSelectionChanged.emit(value) except: pass @property def has_current_cell(self): return self._current_cell is not None @property def current_cell(self): """ Currently edited cell. If needed the cell will be created when accessed. """ if self.selected_cell is None: self._current_cell = self.data_manager.createNewCell() return self._current_cell @current_cell.setter def current_cell(self, value): if value != self._current_cell and self._current_cell in self.cells: self.cells[self._current_cell].setCurrent(False) if value in self.cells: self._current_cell = value self.cells[value].setCurrent() @current_cell.deleter def current_cell(self): if self._current_cell in self.cells: self.cells[self._current_cell].setCurrent(False) self._current_cell = None @property def selected_cell(self): """ Currently selected cell. This is the same as the current cell, but doesn't create one if requested. """ if self._current_cell is not None and self._current_cell not in self.cells: self._current_cell = None return self._current_cell @selected_cell.setter def selected_cell(self, value): self.current_cell = value @selected_cell.deleter def selected_cell(self): del self.current_cell def updatePoints(self): for p in self.items(): if isinstance(p, PointItem): p.setGeometry() self.update() def updateCells(self): for c in self.cells.values(): c.setGeometry() c.update() self.update() def selectedPoints(self): return [it for it in self.selectedItems() if isinstance(it, PointItem)] def selectedCells(self): return [it for it in self.selectedItems() if isinstance(it, CellItem)] def mousePressEvent(self, event): if event.buttons() == Qt.LeftButton: global current_id current_id += 1 if self.mode == TrackingScene.Add: event.accept() if self.image_name is not None: pos = event.scenePos()*self.min_scale self.planAddPoints(None, [pos]) elif self.mode == TrackingScene.ZoomOut: event.accept() self.zoomOut[QPointF].emit(event.scenePos()) elif self.mode == TrackingScene.ZoomIn: event.accept() self.zoomIn[QPointF].emit(event.scenePos()) elif self.mode == TrackingScene.AddCell: for item in self.items(event.scenePos()): if isinstance(item, CellItem): if item.hover: if self.has_current_cell and item.cell_id == self.current_cell: del self.current_cell else: self.current_cell = item.cell_id event.accept() return QGraphicsScene.mousePressEvent(self, event) elif self.mode == TrackingScene.RemoveCell: remove_cell = None for item in self.items(event.scenePos()): if isinstance(item, CellItem): remove_cell = item.cell_id break if remove_cell is not None: self.planRemoveCells([remove_cell]) else: QGraphicsScene.mousePressEvent(self, event) else: QGraphicsScene.mousePressEvent(self, event) def contextMenuEvent(self, event): cell_under = None for it in self.items(event.scenePos()): if isinstance(it, CellItem): cell_under = it.cell_id break self._cell_under = cell_under if cell_under is not None: self.make_starshape_act.setVisible(True) self.lifespan_act.setVisible(True) else: self.make_starshape_act.setVisible(False) self.lifespan_act.setVisible(False) self._popup.popup(event.screenPos()) def planAddPoints(self, pt_ids, poss): self.undo_stack.push(AddPoints(self.data_manager, self.image_name, pt_ids, poss)) def planMovePoints(self, pt_ids, new_poss, starts=None): self.undo_stack.push(MovePoints(self.data_manager, self.image_name, pt_ids, new_poss, starts=starts)) def planRemovePoints(self, pt_ids): self.undo_stack.push(RemovePoints(self.data_manager, self.image_name, pt_ids)) def planAddCell(self, cell_id, pt_ids): log_debug("Planning adding cell %d" % cell_id) self.undo_stack.push(AddCellCommand(self.data_manager, cell_id, pt_ids)) def planChangeCell(self, cell_id, pt_ids, lifespan=None): log_debug("Planning change cell %d" % cell_id) self.undo_stack.push(ChangeCellCommand(self.data_manager, cell_id, pt_ids, lifespan)) def planInsertPointInWall(self, new_pt, wall): log_debug("Planning insert point %d in wall (%d,%d)" % ((new_pt,)+wall)) self.undo_stack.push(InsertPointInWallCommand(self.data_manager, new_pt, wall)) def planDivideCell(self, cell_id, cid1, cid2, p1, p2): log_debug("Planning divide cell %d into %d and %d" % (cell_id, cid1, cid2)) self.undo_stack.push(DivideCellCommand(self.data_manager, self.image_name, cell_id, cid1, cid2, p1, p2)) def planRemoveCells(self, cell_ids): log_debug("Planning remove cells %s" % ", ".join("%d" % c for c in cell_ids)) self.undo_stack.push(RemoveCellsCommand(self.data_manager, cell_ids)) def mouseReleaseEvent(self, event): items = self.getSelected() if items: starts = [] ends = [] moved_ids = [] data = self.current_data #pt_scale = (self.scale[0]/self.img_scale[0], self.scale[1]/self.scale[1]) for item in items: pos = item.pos()*self.min_scale old_pos = data[item.pt_id] if pos != old_pos: moved_ids.append(item.pt_id) starts.append(old_pos) ends.append(pos) if moved_ids: self.planMovePoints(moved_ids, ends, starts) elif self.mode == TrackingScene.AddCell: QGraphicsScene.mouseReleaseEvent(self, event) if event.isAccepted(): return items = self.items(event.scenePos()) if items: pt = items[0] if isinstance(pt, PointItem): pt_id = pt.pt_id cells = self.current_data.cells if self.has_current_cell: cid = self.current_cell cell_shape = list(cells[cid]) if pt_id in cell_shape: cell_shape.remove(pt_id) self.planChangeCell(cid, cell_shape) else: cell_shape.append(pt_id) self.planChangeCell(cid, cell_shape) else: cid = self.current_cell cell_shape = [pt_id] self.planAddCell(cid, cell_shape) return QGraphicsScene.mouseReleaseEvent(self, event) def setPointCellSelection(self, region): add_pts = [] remove_pts = [] items = [p.pt_id for p in self.items(region) if isinstance(p, PointItem)] if items: #print "New cell with: %s" % (items,) cells = self.current_data.cells cell = self.current_cell cell_points = [] if cell in cells: cell_points = list(cells[cell]) for pt_id in items: if pt_id in cell_points: remove_pts.append(pt_id) else: add_pts.append(pt_id) for pt_id in remove_pts: cell_points.remove(pt_id) cell_points += add_pts cell_points = makeStarShaped(cell_points, self.current_data) if cell in cells: self.planChangeCell(cell, cell_points) else: #print "Adding cell %d with %s" % (cell, cell_points) self.planAddCell(cell, cell_points) def setDivisionLine(self, first_point, second_point): dm = self.data_manager cid1 = dm.createNewCell() cid2 = dm.createNewCell() self.planDivideCell(self.current_cell, cid1, cid2, first_point.pt_id, second_point.pt_id) def changeLifespan(self): cid = self._cell_under ls = self.data_manager.lifespan(cid) dlg = createForm("lifespan.ui", None) self.lifespan_dlg = dlg images = list(self.data_manager.images_name) images << "End Of Time" dlg.images = images assert ls.end < len(images) or ls.end == EndOfTime() dlg.start_index = ls.start if ls.end == EndOfTime(): dlg.end_index = -1 else: dlg.end_index = ls.end - ls.start dlg.startImages.addItems(images[:ls.end]) dlg.endImages.addItems(images[ls.start:]) dlg.startImages.setCurrentIndex(ls.start) if dlg.end_index != -1: dlg.endImages.setCurrentIndex(dlg.end_index) else: dlg.endImages.setCurrentIndex(dlg.endImages.count()-1) dlg.startImages.currentIndexChanged[int].connect(self.updateLifepsanEndImages) dlg.endImages.currentIndexChanged[int].connect(self.updateLifepsanStartImages) if ls.parent is not None: dlg.created.setChecked(True) if ls.daughters is not None: dlg.divides.setChecked(True) if dlg.exec_() == QDialog.Accepted: new_ls = ls.copy() new_ls.start = dlg.start_index if dlg.end_index == -1: new_ls.end = EndOfTime() else: new_ls.end = dlg.end_index + dlg.start_index log_debug("Change lifespan of cell %d to %s" % (cid, new_ls)) self.planChangeCell(cid, self.data_manager.cells[cid], new_ls) @Slot(int) def updateLifepsanEndImages(self, new_idx): dlg = self.lifespan_dlg start_idx = dlg.start_index if start_idx != new_idx: dlg.endImages.currentIndexChanged[int].disconnect(self.updateLifepsanStartImages) dlg.endImages.clear() dlg.endImages.addItems(dlg.images[new_idx:]) if dlg.end_index != -1: dlg.end_index += start_idx - new_idx dlg.endImages.setCurrentIndex(dlg.end_index) else: dlg.endImages.setCurrentIndex(dlg.endImages.count()-1) dlg.start_index = new_idx dlg.endImages.currentIndexChanged[int].connect(self.updateLifepsanStartImages) @Slot(int) def updateLifepsanStartImages(self, new_idx): dlg = self.lifespan_dlg start_idx = dlg.start_index end_idx = dlg.end_index if end_idx == -1: end_idx = dlg.endImages.count()-1 if new_idx != end_idx: dlg.startImages.currentIndexChanged[int].disconnect(self.updateLifepsanEndImages) dlg.startImages.clear() dlg.startImages.addItems(dlg.images[:new_idx+start_idx]) dlg.startImages.setCurrentIndex(dlg.start_index) if new_idx == dlg.endImages.count()-1: dlg.end_index = -1 else: dlg.end_index = new_idx dlg.startImages.currentIndexChanged[int].connect(self.updateLifepsanEndImages) def makeCellStarshaped(self): cid = self._cell_under pts = self.current_data.cells[cid] #pts = self.makeStarShaped(pts) pts = makeStarShaped(pts, self.current_data) self.planChangeCell(cid, pts) #def makeStarShaped(self, pts): # if len(pts) > 2: # points = self.points # coords = [ points[pt_id].pos() for pt_id in pts ] # center = sum(coords, QPointF())/len(coords) # ref = coords[0] - center # angles = [ angle(ref, p-center) for p in coords ] # to_sort = range(len(angles)) # to_sort.sort(key=lambda k:angles[k]) # return [ pts[i] for i in to_sort ] # else: # return pts def addPointToCell(self, cid, side, pt): pts = [p.pt_id for p in self.items(pt) if isinstance(p, PointItem)] if pts: data = self.data_manager pt_id = pts[0] #print "Add point %d to cell %d in side %d" % (pt_id, cid, side) cell_points = list(self.current_data.cells[cid]) prev_pt = cell_points[side-1] next_pt = cell_points[side] self.planInsertPointInWall(pt_id, data.wallId(prev_pt, next_pt)) def clearItems(self): for it in self.items(): if isinstance(it, PointItem) or isinstance(it, OldPointItem): it.removePoint() elif isinstance(it, ArrowItem): it.removeArrow() else: self.removeItem(it) self.points.clear() self.cells.clear() self.addItem(self.template) def clear(self): self.clearItems() if self.data_manager is not None: data_manager = self.data_manager data_manager.pointsAdded.disconnect(self.addPoints) data_manager.pointsMoved.disconnect(self.movePoints) data_manager.pointsDeleted.disconnect(self.delPoints) data_manager.imageMoved.disconnect(self.moveImage) data_manager.dataChanged.disconnect(self.dataChanged) data_manager.cellsAdded.disconnect(self.addCells) data_manager.cellsRemoved.disconnect(self.removeCells) data_manager.cellsChanged.disconnect(self.changeCells) self.current_data = None self.data_manager = None self.image_path = None def changeDataManager(self, data_manager): self.clear() self.data_manager = data_manager self.min_scale = 1.0 self.scale = (1.0, 1.0) data_manager.pointsAdded.connect(self.addPoints) data_manager.pointsMoved.connect(self.movePoints) data_manager.pointsDeleted.connect(self.delPoints) data_manager.dataChanged.connect(self.dataChanged) data_manager.imageMoved.connect(self.moveImage) data_manager.cellsAdded.connect(self.addCells) data_manager.cellsRemoved.connect(self.removeCells) data_manager.cellsChanged.connect(self.changeCells) def moveImage(self, image_name, scale, pos, angle): if image_name == self.image_name: self.setImageMove(scale, pos, angle) self.updateElements() self.invalidate() self.update() def updateElements(self): for pt in self.items(): pt.scale = self.img_scale pt.setGeometry() def setImageMove(self, scale, pos, angle): log_debug("New scale = %s" % (scale,)) self.scale = scale self.min_scale = self.data_manager.minScale() self.img_scale = (scale[0]/self.min_scale, scale[1]/self.min_scale) back_matrix = QTransform() back_matrix.scale(*self.img_scale) back_matrix.translate(pos.x(), pos.y()) back_matrix.rotate(angle) self.back_matrix = back_matrix rect = back_matrix.mapRect(QRectF(self.background_image.rect())) inv, ok = back_matrix.inverted() if not ok: raise ValueError("The movement is not invertible !?!") self.invert_back_matrix = inv self.real_scene_rect = rect @property def real_scene_rect(self): '''Real size of the scene''' return self._real_scene_rect @real_scene_rect.setter def real_scene_rect(self, value): if self._real_scene_rect != value: self._real_scene_rect = value self.realSceneSizeChanged.emit() def changeImage(self, image_path): log_debug("Changed image to {0}".format(image_path)) if image_path is None: image_path = self.image_path if image_path is None: return image_name = image_path.basename() self.image_name = image_name self.current_data = self.data_manager[image_name] current_data = self.current_data self.clearItems() self.image_path = image_path img = image_cache.cache.image(image_path) self.background_image = img pos = current_data.shift[0] angle = current_data.shift[1] scale = current_data.scale log_debug('Scale of image "%s": %s' % (image_name, scale)) self.setImageMove(scale, pos, angle) self.invalidate() for pt_id in current_data: self.addPoint(pt_id, current_data[pt_id], new=False) cells = self.current_data.cells log_debug("Found {0} cells".format(len(cells))) if cells: self.addCells(list(cells.keys())) del self.current_cell self.setTemplatePos() def dataChanged(self, image_name): if image_name == self.image_name: self.current_data = self.data_manager[image_name] def drawBackground(self, painter, rect): painter.fillRect(rect, QBrush(QColor(0, 0, 0))) if self.background_image: #bm = self.back_matrix #log_debug("m = [%g %g ; %g %g ]" % (bm.m11(), bm.m12(), bm.m21(), bm.m22())) painter.setWorldTransform(self.back_matrix, True) #real_rect = self.invert_back_matrix.mapRect(rect) #rect = self.back_matrix.mapRect(real_rect) #painter.drawImage(rect,self.background_image, real_rect) painter.drawImage(QPointF(0, 0), self.background_image) def drawForeground(self, painter, rect): QGraphicsScene.drawForeground(self, painter, rect) def _addPoint(self, pt_id, pos, new): point = PointItem(self.img_scale, pt_id, new=new) point.setSelected(new) self.addItem(point) self.points[pt_id] = point point.setPos(QPointF(pos.x()/self.min_scale, pos.y()/self.min_scale)) return point def addPoint(self, pt_id, pos, new=True): point = self._addPoint(pt_id, pos, new) if self.link is not None and pt_id in self.link.points: self.link.linkPoint(point, self.link.points[pt_id]) cell_points = self.data_manager.cell_points cells = self.cells cs = [cells[cid] for cid in cell_points[pt_id] if cid in cells] point.setCells(cs) return point def addPoints(self, image_name, pt_ids): #print "TrackingScene - Adding points [%s]" % ','.join('%d' % c for c in pt_ids) if image_name == self.image_name: #print "... in this image!" data = self.current_data dm = self.data_manager cells = self.cells for pt_id in pt_ids: pt = self.addPoint(pt_id, data[pt_id], new=True) pt.setCells([cells[cid] for cid in dm.cell_points[pt_id] if cid in cells]) cids = set(cid for pt_id in pt_ids for cid in dm.cell_points[pt_id]) cells_to_add = [] for cid in cids: if cid in cells: cells[cid].setGeometry() else: cells_to_add.append(cid) if cells_to_add: self.addCells(cells_to_add) def delPoint(self, point): del self.points[point.pt_id] point.removePoint() def delPoints(self, image_name, pt_ids): if image_name == self.image_name: dm = self.data_manager cells = self.cells for pt_id in pt_ids: self.delPoint(self.points[pt_id]) for cid in dm.cell_points[pt_id]: cell = cells.get(cid, None) if cell is not None: cells[cid].setGeometry() def movePoints(self, image_name, pt_ids): if image_name == self.image_name: data = self.current_data dm = self.data_manager points = self.points cells = self.cells for pt_id in pt_ids: pos = data[pt_id] pos = QPointF(pos.x() / self.min_scale, pos.y() / self.min_scale) points[pt_id].setPos(pos) for cid in dm.cell_points[pt_id]: cell = cells.get(cid, None) if cell is not None and cell.isVisible(): cell.setGeometry() def addCells(self, cell_ids, image_list=None): log_debug("addCell signal with images: (%s,%s)" % (cell_ids, image_list)) if image_list is not None: used_ids = [] used_il = [] for cid, il in zip(cell_ids, image_list): if il is None or self.image_name in il: used_ids.append(cid) used_il = il if not used_ids: log_debug("Current image is: '%s' and is not in any of the lists" % self.image_name) return cell_ids = used_ids image_list = used_il log_debug("Adding cells %s to image %s" % (','.join("%d" % c for c in cell_ids), self.image_name)) data = self.data_manager current_data = self.current_data cell_ids = [cid for cid in cell_ids if cid in current_data.cells] log_debug("cell_ids = %s" % (cell_ids,)) points = self.points cells = self.cells cell_points = data.cell_points for cid in cell_ids: if cid in cells or not [pid for pid in current_data.cells[cid] if pid in current_data]: continue log_debug("-- Add cell %d with points %s" % (cid, current_data.cells[cid])) ci = CellItem(self.img_scale, self.min_scale, cid, current_data.cells[cid], points, current_data.walls) self.addItem(ci) cells[cid] = ci ci.setEditable(self.mode == TrackingScene.AddCell) if self.has_current_cell and cid == self.current_cell: ci.setCurrent() pid = data.cells_lifespan[cid].parent if pid is not None: ls = data.cells_lifespan[pid] if data.images_name[ls.end] == self.image_name: div_line = ls.division ci.setDivisionLine(div_line[0], div_line[1]) for cid in cell_ids: for pid in current_data.cells[cid]: if pid in points: pt = points[pid] pt.setCells(cells[i] for i in cell_points[pid] if i in cells) def removeCells(self, cell_ids, image_list=None): log_debug("removeCells signal with images: (%s,%s)" % (cell_ids, image_list)) if image_list is not None: used_ids = [] used_il = [] for cid, il in zip(cell_ids, image_list): if il is None or self.image_name in il: used_ids.append(cid) used_il = il if not used_ids: log_debug("Current image is: '%s' and is not in any of the lists" % self.image_name) return cell_ids = used_ids image_list = used_il log_debug("Removing cells %s to image %s" % (','.join("%d" % c for c in cell_ids), self.image_name)) if self.has_current_cell and self.current_cell in cell_ids: del self.current_cell cells = self.cells for cid in cell_ids: cell = cells.get(cid, None) if cell is not None: self.removeItem(cell) del self.cells[cid] def changeCells(self, cell_ids): #print "TrackingScene - Changing cells: [%s]" % ','.join("%d" % c for c in cell_ids) log_debug("Change cells %s in image %s" % (','.join("%d" % c for c in cell_ids), self.image_name)) data = self.data_manager current_data = self.current_data cell_ids = [cid for cid in cell_ids if cid in current_data.cells] points = self.points cells = self.cells for cid in cell_ids: ci = cells.get(cid, None) if ci is not None: ci.changePoints(current_data.cells[cid]) for pid in current_data.cells[cid]: if pid in points: pt = points[pid] pt.setCells(cells[i] for i in data.cell_points[pid] if i in cells) pid = data.cells_lifespan[cid].parent if pid is not None: ls = data.cells_lifespan[pid] if data.images_name[ls.end] == self.image_name: div_line = ls.division ci.setDivisionLine(div_line[0], div_line[1]) def pointMoved(self, pt_id, start_pos, end_pos): self.planMovePoints([pt_id], [end_pos], starts=[start_pos]) def selectNew(self): for it in self.points.values(): it.setSelected(it.new) def selectAll(self): for it in self.points.values(): it.setSelected(True) def selectNone(self): for it in self.points.values(): it.setSelected(False) def selectInvert(self): for it in self.points.values(): it.setSelected(not it.isSelected()) def selectNonAssociated(self): for it in self.points.values(): if it.arrow is None and it.link is None: it.setSelected(True) else: it.setSelected(False) def selectAssociated(self): for it in self.points.values(): if it.arrow is None and it.link is None: it.setSelected(False) else: it.setSelected(True) def getSelected(self): return [pt for pt in self.points.values() if pt.isSelected()] def getSelectedIds(self): return [pt.pt_id for pt in self.points.values() if pt.isSelected()] def getAllItems(self): return self.points.values() def getAllIds(self): return self.points.keys() def _set_pan_view(self, view): view.setInteractive(True) view.setCursor(Qt.ArrowCursor) view.setDragMode(QGraphicsView.ScrollHandDrag) def _set_select_view(self, view): view.setInteractive(True) view.setDragMode(QGraphicsView.RubberBandDrag) view.setCursor(Qt.PointingHandCursor) def _set_add_view(self, view): view.setInteractive(True) view.setDragMode(QGraphicsView.NoDrag) view.setCursor(Qt.CrossCursor) def _set_zoomin_view(self, view): view.setInteractive(True) view.setDragMode(QGraphicsView.NoDrag) view.setCursor(QCursor(QPixmap(":/icons/gtk-zoom-in.png"))) def _set_zoomout_view(self, view): view.setInteractive(True) view.setDragMode(QGraphicsView.NoDrag) view.setCursor(QCursor(QPixmap(":/icons/gtk-zoom-out.png"))) def _set_pan(self): params = parameters.instance del self.current_cell self._validate_cell_act.setVisible(False) params.is_point_selectable = False params.is_point_editable = False params.is_cell_editable = False def _set_normal(self): params = parameters.instance del self.current_cell self._validate_cell_act.setVisible(False) params.is_point_selectable = True params.is_point_editable = True params.is_cell_editable = False def _set_cell_view(self, view): view.setInteractive(True) view.setCursor(Qt.ArrowCursor) view.setDragMode(QGraphicsView.NoDrag) def _set_add_cell(self): params = parameters.instance self._validate_cell_act.setVisible(True) params.is_point_selectable = True params.is_point_editable = False params.is_cell_editable = True def _set_remove_cell(self): params = parameters.instance del self.current_cell self._validate_cell_act.setVisible(False) params.is_point_selectable = False params.is_point_editable = False params.is_cell_editable = False _init_view = { Pan: (_set_pan_view, _set_pan), Move: (_set_select_view, _set_normal), Add: (_set_add_view, _set_normal), AddCell: (_set_cell_view, _set_add_cell), RemoveCell: (_set_cell_view, _set_remove_cell), ZoomIn: (_set_zoomin_view, _set_normal), ZoomOut: (_set_zoomout_view, _set_normal) } @property def mode(self): """ Mouse interaction mode """ return self._mode @mode.setter def mode(self, new_mode): if new_mode in TrackingScene.modes: if new_mode != self._mode: log_debug("Changed mode to %s" % new_mode) self._mode = new_mode fct_view, fct = self._init_view[new_mode] fct(self) for v in self.views(): fct_view(self, v) def validateCell(self): del self.current_cell def keyPressEvent(self, event): if event.matches(QKeySequence.Delete): if self.mode == TrackingScene.RemoveCell: c_ids = [] for item in self.selectedCells(): c_ids = item.cell_id if c_ids: self.planRemoveCells(c_ids) elif self.mode != TrackingScene.AddCell: pt_ids = [] for item in self.selectedPoints(): pt_ids.append(item.pt_id) if pt_ids: self.planRemovePoints(pt_ids) elif event.key() == Qt.Key_Delete and event.modifiers() | Qt.ShiftModifier: self.delete_act.trigger() elif event.matches(QKeySequence.ZoomIn): self.zoomIn.emit() elif event.matches(QKeySequence.ZoomOut): self.zoomOut.emit() elif event.matches(QKeySequence.SelectAll): path = QPainterPath() path.addRect(self.sceneRect()) self.setSelectionArea(path) def setSelectedIds(self, ids): for it in self.points.values(): it.setSelected(False) for id in ids: it = self.points.get(id) if it: it.setSelected(True) def deleteInAllImages(self): if self.mode == TrackingScene.RemoveCell: c_ids = [] for item in self.selectedCells(): c_ids.append(item.cell_id) if c_ids: self.planRemoveCells(c_ids) else: pt_ids = [] for item in self.selectedPoints(): pt_ids.append(item.pt_id) if pt_ids: self.undo_stack.push(RemovePointsInAllImages(self.data_manager, self.image_name, pt_ids)) def deleteFromImage(self): if self.mode == TrackingScene.RemoveCell: c_ids = [] for item in self.selectedCells(): c_ids.append(item.cell_id) if c_ids: self.planRemoveCells(c_ids) else: pt_ids = [] for item in self.selectedPoints(): pt_ids.append(item.pt_id) if pt_ids: self.undo_stack.push(RemovePointsFromImage(self.data_manager, self.image_name, pt_ids)) def deleteToImage(self): if self.mode == TrackingScene.RemoveCell: c_ids = [] for item in self.selectedCells(): c_ids.append(item.cell_id) if c_ids: self.planRemoveCells(c_ids) else: pt_ids = [] for item in self.selectedPoints(): pt_ids.append(item.pt_id) if pt_ids: self.undo_stack.push(RemovePointsToImage(self.data_manager, self.image_name, pt_ids)) def findPoint(self, im1, im2, other, point): params = parameters.instance ppos = self.current_data[point.pt_id] pos = self.invert_back_matrix.map(ppos) npos = other.invert_back_matrix.map(ppos) pos = (int(pos.x()), int(pos.y())) npos = (int(npos.x()), int(npos.y())) size = (params.template_size, params.template_size) search_size = (params.search_size, params.search_size) new_pos, value = findTemplate(im1, pos, size, npos, search_size, im2) if value < 0.5: return ppos p = QPointF(new_pos[0], new_pos[1])*self.min_scale return other.back_matrix.map(p) def transferPoints(self, other): params = parameters.instance current_data = self.current_data items = self.selectedItems() if len(items) == 0: items = [it for it in self.points.values() if it.arrow is None and it.link is None] new_pt_ids = [] new_pt_pos = [] move_pt_ids = [] move_pt_new_pos = [] if params.estimate: progress = QProgressDialog("Estimating position of the points...", "Abort", 0, len(items), self.parent()) progress.setMinimumDuration(1) size = (params.filter_size, params.filter_size) im1 = image_cache.cache.numpy_array(self.image_path, size) im2 = image_cache.cache.numpy_array(other.image_path, size) for i, it in enumerate(items): pos = self.findPoint(im1, im2, other, it) id = it.pt_id if id in other.points: move_pt_ids.append(id) move_pt_new_pos.append(pos) else: new_pt_ids.append(id) new_pt_pos.append(pos) progress.setValue(i+1) if progress.wasCanceled(): progress.hide() break else: for it in items: id = it.pt_id pos = current_data[id] if id in other.points: move_pt_ids.append(id) move_pt_new_pos.append(pos) else: new_pt_ids.append(id) new_pt_pos.append(pos) if new_pt_ids or move_pt_ids: self.undo_stack.beginMacro("Transfer point(s) from %s to %s" % (self.image_name, other.image_name)) if new_pt_ids: other.planAddPoints(new_pt_ids, new_pt_pos) if move_pt_ids: other.planMovePoints(move_pt_ids, move_pt_new_pos) self.undo_stack.endMacro() def copyToLinked(self, linked): self.transferPoints(linked) def setTemplatePos(self, pos=None): if pos is None: views = self.views() if len(views) > 0: view = views[0] pos = view.mapToScene(view.rect().center()) if pos is not None: self.template.setPos(pos) def showTemplates(self, value=True): params = parameters.instance self.show_template = value if not params.show_template: if value: self.template.setGeometry() self.template.setVisible(True) self.setTemplatePos() else: self.template.setVisible(False) def updateTemplate(self): params = parameters.instance if params.show_template or self.show_template: self.template.setGeometry() if not self.template.isVisible(): self.template.setVisible(True) self.setTemplatePos() else: self.template.setVisible(False) self.update() def resetNewPoints(self): for items in self.points.values(): items.new = False self.update()
def paintEvent(self, event): painter = QPainter(self) width = self.width() height = self.height() if DEBUG: painter.fillRect(0, 0, width, height, Qt.blue) else: painter.fillRect(event.rect(), self.plot.canvas_color) y_min_scale = self.plot.y_scale.value_min y_max_scale = self.plot.y_scale.value_max factor_x = float(width) / self.plot.x_diff factor_y = float(height - 1) / max( y_max_scale - y_min_scale, EPSILON) # -1 to accommodate the 1px width of the curve if self.plot.x_min != None and self.plot.x_max != None: x_min = self.plot.x_min x_max = self.plot.x_max if self.plot.curve_start == 'left': curve_x_offset = 0 else: curve_x_offset = round( (self.plot.x_diff - (x_max - x_min)) * factor_x) transform = QTransform() transform.translate( curve_x_offset, height - 1 + self.plot.curve_y_offset ) # -1 to accommodate the 1px width of the curve transform.scale(factor_x, -factor_y) transform.translate(-x_min, -y_min_scale) if self.plot.curve_motion_granularity > 1: self.plot.partial_update_width = math.ceil( transform.map(QLineF(0, 0, 1.5, 0)).length()) inverted_event_rect = transform.inverted()[0].mapRect( QRectF(event.rect())) painter.save() painter.setTransform(transform) if False and self.plot.curves_visible[0]: # Currently unused support for bar graphs. # If we need this later on we should add an option to the # PlotWidget for it. # I tested this for the Sound Pressure Level Bricklet and it works, # but it didnt't look good. curve_x = self.plot.curves_x[0] curve_y = self.plot.curves_y[0] t = time.time() if self.max_points == None: self.max_points = [] for y in curve_y: self.max_points.append((t, y)) else: for i in range(len(curve_y)): if (curve_y[i] > self.max_points[i][1]) or ( (t - self.max_points[i][0]) > 5): self.max_points[i] = (t, curve_y[i]) for i in range(len(self.plot.curves_x[0])): painter.setPen(self.plot.curve_configs[0].color) painter.drawLine(QPoint(curve_x[i], 0), QPoint(curve_x[i], curve_y[i])) painter.setPen(Qt.white) painter.drawLine(QPoint(curve_x[i], curve_y[i]), QPoint(curve_x[i], y_max_scale)) painter.setPen(Qt.darkGreen) painter.drawPoint(QPoint(curve_x[i], self.max_points[i][1])) else: for c in range(len(self.plot.curves_x)): if not self.plot.curves_visible[c]: continue curve_x = self.plot.curves_x[c] curve_y = self.plot.curves_y[c] path = QPainterPath() lineTo = path.lineTo if self.plot.curve_motion_granularity > 1: start = max( min( bisect.bisect_left(curve_x, inverted_event_rect.left()), len(curve_x) - 1) - 1, 0) else: start = 0 path.moveTo(curve_x[start], curve_y[start]) for i in xrange(start + 1, len(curve_x)): lineTo(curve_x[i], curve_y[i]) painter.setPen(self.plot.curve_configs[c].color) painter.drawPath(path) painter.restore()