def paintEvent(self, event): if self._flag_1: qp = QPainter() qp.begin(self) qp.setBrush(QColor(255, 237, 0)) # задаем желтый цвет для рамки выбора qp.drawRect(self._col * 40 + 15, self._activ_pic * 50, 50, 50) # задаем положение и размер рамки выбора for i in range(self._col): for j in range(self._row): qp.setBrush(QColor(50, 50, 50)) qp.drawRect(i * 40, j * 40, 40, 40) qp.drawPixmap(i * 40, j * 40, self._elem_map[ self._sp_map[j][i]]) # рисуем картинками из elem_map for i in range(PIC): qp.drawPixmap(self._col * 40 + 20, i * 50 + 5, self._elem_map[i]) if self._mouse_x < self._col * 40 and self._mouse_y < self._row * 40: qp.drawPixmap(self._mouse_x - 30, self._mouse_y - 30, self._elem_map[self._activ_pic]) qp.end()
def paintEvent(self, e): if self.img: painter = QPainter() painter.begin(self) painter.scale(self.scale, self.scale) painter.drawPixmap(self.point, self.img) painter.end()
def paintEvent(self, event): painter = QPainter() painter.begin(self) painter.setPen(Qt.QPen(Qt.QColor('#3d3c3c'))) painter.setFont(QFont("MS Shell Dlg 2", 16)) if self.move_mode_open: painter.fillRect(Qt.QRectF(0, 0, 1280, 80), Qt.QColor('#d6ffdd')) else: painter.fillRect(Qt.QRectF(0, 0, 1280, 80), QtCore.Qt.white) if self.alarm or self.inform: self.alarm_button.resize(640, 560) self.alarm_button.move(0, 160) self.inform_button.resize(640, 560) self.inform_button.move(640, 160) else: self.alarm_button.resize(640, 640) self.alarm_button.move(0, 80) self.inform_button.resize(640, 640) self.inform_button.move(640, 80) if self.alarm: painter.fillRect(Qt.QRectF(0, 80, 1280, 80), Qt.QColor('#ffbfbc')) painter.drawText(Qt.QRectF(0, 80, 1280, 80), QtCore.Qt.AlignCenter, 'opiekun jest alarmowany') elif self.inform: painter.fillRect(Qt.QRectF(0, 80, 1280, 80), Qt.QColor('#cceeff')) painter.drawText(Qt.QRectF(0, 80, 1280, 80), QtCore.Qt.AlignCenter, 'opiekun jest powiadamiany') painter.drawText( Qt.QRectF(0, 0, 1280, 80), QtCore.Qt.AlignCenter, 'sterowanie kursorem jest ' + ('włączone' if self.move_mode_open else 'wyłączone')) painter.end()
def paintEvent(self, event): if self.flag: qp = QPainter() qp.begin(self) qp.setBrush( QColor(random.randrange(255), random.randrange(255), random.randrange(255))) a = random.randrange(1, 351) qp.drawEllipse(100, 100, a, a) qp.end()
def paintEvent(self, e): """ receive paint events :param e: QPaintEvent :return: """ if self.scaled_img: painter = QPainter() painter.begin(self) painter.scale(self.scale, self.scale) painter.drawPixmap(self.point, self.scaled_img) painter.end()
class PaintBoard(QWidget): def __init__(self, parent=None): super().__init__(parent) self.__InitData() self.__InitView() def __InitData(self): self.__size = QSize(280, 280) self.__board = QPixmap(self.__size) self.__board.fill(Qt.black) self.__isEmpty = True self.__lastPose = QPoint(0, 0) self.__currentPose = QPoint(0, 0) self.__painter = QPainter() self.__thickness = 20 self.__penColor = QColor('white') def __InitView(self): self.setFixedSize(self.__size) def paintEvent(self, paintEvent): self.__painter.begin(self) self.__painter.drawPixmap(0, 0, self.__board) self.__painter.end() def mousePressEvent(self, mouseEvent): self.__currentPose = mouseEvent.pos() self.__lastPose = self.__currentPose def mouseMoveEvent(self, mouseEvent): self.__currentPose = mouseEvent.pos() self.__painter.begin(self.__board) self.__painter.setPen(QPen(self.__penColor, self.__thickness)) self.__painter.drawLine(self.__lastPose, self.__currentPose) self.__painter.end() self.__lastPose = self.__currentPose self.update() def mouseReleaseEvent(self, mouseEvent): self.__isEmpty = False def clear(self): self.__board.fill(Qt.black) self.update() self.__isEmpty = True def isEmpty(self): return self.__isEmpty def getImage(self): image = self.__board.toImage() return image
def paintEvent(self, event): qp = QPainter() qp.begin(self) if self._flag_1: for i in range(self.map.get_col()): for j in range(self.map.get_row()): qp.drawPixmap( i * 40, j * 40 + 40, self.map.get_elem_xy( i, j).get_pic()) # рисуем картинками из elem_map qp.drawPixmap(self.hero.get_x() * 40, self.hero.get_y() * 40 + 40, self.hero.get_pic()) for enemy in self.enemies: qp.drawPixmap(enemy.get_x() * 40, enemy.get_y() * 40 + 40, enemy.get_pic()) for i in range(game.hero.get_lifes()): qp.drawPixmap(280 + i * 40, 0, self.hero._pic[self.hero._STOP][0]) txt = "00000" + str(self._score) self.lable_score.setText(txt[len(txt) - 5:len(txt)]) qp.end()
class PaintBoard(QWidget): def __init__(self, Parent=None): ''' Constructor ''' super().__init__(Parent) self.__InitData() #先初始化数据,再初始化界面 self.__InitView() def __InitView(self): self.setFixedSize(self.__size) def __InitData(self): self.__size = QSize(1600,1200) self.__board = QPixmap(self.__size) #新建QPixmap作为画板,宽350px,高250px self.__board.fill(Qt.white) #用白色填充画板 self.__IsEmpty = True #默认为空画板 self.EraserMode = False #默认为禁用橡皮擦模式 self.__lastPos = QPoint(0,0) self.__currentPos = QPoint(0,0) self.__painter = QPainter() self.__thickness = 10 #默认画笔粗细为10px self.__penColor = QColor("black") #设置默认画笔颜色为黑色 self.__colorList = QColor.colorNames() #获取颜色列表 def Clear(self): #清空画板 self.__board.fill(Qt.white) self.update() self.__IsEmpty = True def ChangePenColor(self, color="black"): #改变画笔颜色 self.__penColor = QColor(color) def ChangePenThickness(self, thickness=10): #改变画笔粗细 self.__thickness = thickness def IsEmpty(self): #返回画板是否为空 return self.__IsEmpty def GetContentAsQImage(self): #获取画板内容(返回QImage) image = self.__board.toImage() return image def paintEvent(self, paintEvent): self.__painter.begin(self) self.__painter.drawPixmap(0,0,self.__board) self.__painter.end() def mousePressEvent(self, mouseEvent): self.__currentPos = mouseEvent.pos() self.__lastPos = self.__currentPos def mouseMoveEvent(self, mouseEvent): self.__currentPos = mouseEvent.pos() self.__painter.begin(self.__board) if self.EraserMode == False: #非橡皮擦模式 self.__painter.setPen(QPen(self.__penColor,self.__thickness)) #设置画笔颜色,粗细 else: #橡皮擦模式下画笔为纯白色,粗细为10 self.__painter.setPen(QPen(Qt.white,10)) self.__painter.drawLine(self.__lastPos, self.__currentPos) self.__painter.end() self.__lastPos = self.__currentPos self.update() #更新显示 def mouseReleaseEvent(self, mouseEvent): self.__IsEmpty = False #画板不再为空
class PaintBoard(QWidget): def __init__(self, parent=None): super().__init__(parent) self.__size = QSize(350, 350) # 新建画板,尺寸为__size self.__board = QPixmap(self.__size) self.__board.fill(Qt.white) # 用白色填充画板 self.__painter = QPainter() # 新建绘图工具 self.eraser_mode = False # 默认为禁用橡皮擦模式 self.__thickness = 6 # 默认画笔粗细为10px self.__lastPos = QPoint(0, 0) # 上一次鼠标位置 self.__currentPos = QPoint(0, 0) # 当前的鼠标位置 self.__undo_num = 0 self.__redo_num = 0 self.__undo_list = [] self.__redo_list = [] self.__undo_list.append(self.__board.toImage()) # 设置界面的尺寸为__size self.setFixedSize(self.__size) def clear(self): self.__board.fill(Qt.white) # 清空画板 self.update() self.__undo_list.append(self.__board.toImage()) self.__redo_list = [] self.__undo_num += 1 self.__redo_num = 0 def up(self, image): self.__board = image # 清空画板 self.update() self.__undo_list.append(self.__board.toImage()) self.__redo_list = [] self.__undo_num += 1 self.__redo_num = 0 def undo(self): if self.__undo_num > 0: image = self.__undo_list[self.__undo_num - 1] self.__board = QPixmap.fromImage(image) self.update() self.__redo_list.append(self.__undo_list.pop()) self.__redo_num += 1 self.__undo_num -= 1 def redo(self): if self.__redo_num > 0: image = self.__redo_list[self.__redo_num - 1] self.__board = QPixmap(image) self.update() self.__undo_list.append(self.__redo_list.pop()) self.__redo_num -= 1 self.__undo_num += 1 def change_pen_thickness(self, thickness=10): # 改变画笔粗细 self.__thickness = thickness def get_content_as_image(self): # 获取画板内容(返回QImage) image = self.__board.toImage() return image def paintEvent(self, paint_event): # 绘图事件 # 绘图时必须使用QPainter的实例,此处为__painter # 绘图在begin()函数与end()函数间进行 # begin(param)的参数要指定绘图设备,即把图画在哪里 self.__painter.begin(self) # 0,0为绘图的左上角起点的坐标,__board即要绘制的图 self.__painter.drawPixmap(0, 0, self.__board) self.__painter.end() def mouse_press_event(self, mouse_event): # 鼠标按下时,获取鼠标的当前位置保存为上一次位置 # self.__currentPos = mouse_event.pos() self.__currentPos.setX(mouse_event.pos().x() - 803) self.__currentPos.setY(mouse_event.pos().y() - 147) self.__lastPos = self.__currentPos def mouse_move_event(self, mouse_event): # self.__currentPos = mouse_event.pos() # 鼠标移动时,更新当前位置,并在上一个位置和当前位置间画线 self.__currentPos.setX(mouse_event.pos().x() - 803) self.__currentPos.setY(mouse_event.pos().y() - 147) self.__painter.begin(self.__board) if not self.eraser_mode: # 非橡皮擦模式 self.__painter.setPen(QPen(Qt.black, self.__thickness)) # 设置画笔颜色,粗细 else: # 橡皮擦模式下画笔为纯白色,粗细为10 self.__painter.setPen(QPen(Qt.white, self.__thickness)) # 画线 self.__painter.drawLine(self.__lastPos, self.__currentPos) self.__painter.end() self.__lastPos = self.__currentPos self.update() # 更新显示 def mouse_release_event(self, mouse_event): self.__undo_list.append(self.__board.toImage()) self.__redo_list = [] self.__undo_num += 1 self.__redo_num = 0
class PaintBoard(QWidget): set_paint = pyqtSignal(bool) def __init__(self, signals: ClientSignal, Parent=None): ''' Constructor ''' super().__init__(Parent) self.Signals = signals # 是否是本玩家在画图 # 判断是否需要发送画图信息 self.Painting = False self.BoardSize = QSize(*board_resolution) # 新建QPixmap作为画板,尺寸为size self.Board = QPixmap(self.BoardSize) self.Board.fill(Qt.white) # 用白色填充画板 self.IsEmpty = True # 默认为空画板 self.EraserMode = False # 默认为禁用橡皮擦模式 self.LastPos = QPoint(0, 0) # 上一次鼠标位置 self.CurrentPos = QPoint(0, 0) # 当前的鼠标位置 self.Painter = QPainter() # 新建绘图工具 self.Thickness = default_thickness # 默认画笔粗细为10px self.PenColor = QColor(default_color) # 设置默认画笔颜色为黑色 self.ColorList = QColor.colorNames() # 获取颜色列表 self.set_paint.connect(self.set_painting) self.PaintPoints = [] self.init_view() def init_view(self): # 设置界面的尺寸为size self.setFixedSize(self.BoardSize) def set_painting(self, painting): # print('seting painting to', painting) self.Painting = painting def set_pen_thickness(self, thickness): self.Thickness = int(thickness) def set_pen_color(self, color): self.PenColor = QColor(color) def set_eraser(self, e): self.EraserMode = e if self.Painting: self.Signals.EraserChangeSignal.emit(e) # self.EraserSender.emit(e) def clear(self): if self.Painting: self.Signals.ClearSignal.emit() # self.ClearSender.emit() # 清空画板 self.Board.fill(Qt.white) self.repaint()#update() self.IsEmpty = True def change_pen_color(self, color="black"): print('color changed:', color) if self.Painting: self.Signals.ColorChangeSignal.emit(color) # self.ColorSender.emit(color) # 改变画笔颜色 self.PenColor = QColor(color) def change_pen_thickness(self, thickness=default_thickness): if self.Painting: self.Signals.ThicknessChangeSignal.emit(thickness) # self.ThicknessSender.emit(thickness) # 改变画笔粗细 self.Thickness = thickness # print('thickness:',type(self.thickness), self.thickness) # 返回画板是否为空 def is_empty(self): return self.IsEmpty def get_content_as_QImage(self): # 获取画板内容(返回QImage) image = self.Board.toImage() return image def paintEvent(self, paintEvent): # 绘图事件 # 绘图时必须使用QPainter的实例,此处为painter # 绘图在begin()函数与end()函数间进行 # begin(param)的参数要指定绘图设备,即把图画在哪里 # drawPixmap用于绘制QPixmap类型的对象 self.Painter.begin(self) # 0,0为绘图的左上角起点的坐标,board即要绘制的图 self.Painter.drawPixmap(0, 0, self.Board) self.Painter.end() def mousePressEvent(self, mouseEvent): # 鼠标按下时,获取鼠标的当前位置保存为上一次位置 self.CurrentPos = mouseEvent.pos() self.LastPos = self.CurrentPos if self.Painting: self.Signals.ClickPointSignal.emit(mouseEvent.pos()) # self.click_point_sender.emit(mouseEvent.pos()) def mouseMoveEvent(self, mouseEvent): # print('moving! painting=', self.Painting) if self.Painting: # 鼠标移动时,更新当前位置,并在上一个位置和当前位置间画线 self.CurrentPos = mouseEvent.pos() self.paint_point() # print('painting...') self.repaint() # print('complete painting...') self.LastPos = self.CurrentPos # self.paint_points.append([self.currentPos.x(), self.currentPos.y()]) # self.paint_point_sender.emit(mouseEvent.pos()) self.Signals.PaintPointSignal.emit(mouseEvent.pos()) def mouseReleaseEvent(self, mouseEvent): self.IsEmpty = False # 画板不再为空 if self.Painting: self.Signals.ReleasePointSignal.emit() # self.release_point_sender.emit() # self.paint_points.clear() def paint_point(self): self.Painter.begin(self.Board) if not self.EraserMode: # 非橡皮擦模式 self.Painter.setPen(QPen(self.PenColor, self.Thickness)) # 设置画笔颜色,粗细 else: # 橡皮擦模式下画笔为纯白色,粗细为10 self.Painter.setPen(QPen(Qt.white, 10)) # 画线 self.Painter.drawLine(self.LastPos, self.CurrentPos) self.Painter.end() def extern_click(self, x, y): self.LastPos = QPoint(x, y) self.CurrentPos = QPoint(x, y) def extern_paint(self, ps): for x,y in ps: self.CurrentPos = QPoint(x, y) self.paint_point() self.LastPos = self.CurrentPos self.repaint() def reset_last_point(self, x, y): self.LastPos = QPoint(x, y) self.CurrentPos = QPoint(x, y)
class PaintBoard(QWidget): def __init__(self, Parent=None, fpath=None): ''' Constructor ''' super().__init__(Parent) self.pos_xy = [] #保存鼠标移动过的点 self._InitData(fpath) #先初始化数据,再初始化界面 self.__InitView() def __InitView(self): self.setFixedSize(self.__size) def _InitData(self,fpath=None): self.__size = QSize(280,280) if fpath is None: self.__board = QPixmap(self.__size) #新建QPixmap作为画板,宽350px,高250px self.__board.fill(Qt.white) #用白色填充画板 else: self.__board = QPixmap(fpath).scaled(280,280) def paintEvent(self, event): self.__painter = QPainter() self.__painter.begin(self) self.__painter.drawPixmap(0,0,self.__board) pen = QPen(Qt.black, 30, Qt.SolidLine) self.__painter.setPen(pen) if len(self.pos_xy) > 1: point_start = self.pos_xy[0] for pos_tmp in self.pos_xy: point_end = pos_tmp if point_end == (-1, -1): point_start = (-1, -1) continue if point_start == (-1, -1): point_start = point_end continue self.__painter.drawLine(point_start[0], point_start[1], point_end[0], point_end[1]) point_start = point_end self.__painter.end() def mouseMoveEvent(self, event): ''' 按住鼠标移动事件:将当前点添加到pos_xy列表中 ''' #中间变量pos_tmp提取当前点 pos_tmp = (event.pos().x(), event.pos().y()) #pos_tmp添加到self.pos_xy中 self.pos_xy.append(pos_tmp) self.update() def mouseReleaseEvent(self, event): ''' 重写鼠标按住后松开的事件 在每次松开后向pos_xy列表中添加一个断点(-1, -1) ''' pos_test = (-1, -1) self.pos_xy.append(pos_test) self.update() def Clear(self): pass
class PaintBoard(QWidget): # Define virtual panel coordinates for different shapes/regions VPCoord_Start = [316, 332] #LeftTopX, Y VPCoord_Circle = [316, 332, 336, 363] #LeftTopX, Y, RightBotX, Y VPCoord_Rect = [336, 332, 356, 363] #LeftTopX, Y, RightBotX, Y VPCoord_Tri = [316, 363, 336, 395] #LeftTopX, Y, RightBotX, Y VPCoord_Line = [336, 363, 356, 395] #LeftTopX, Y, RightBotX, Y # A flag to check if the user is currently using the virtual panel usingVP = False def __init__(self, sizeX, sizeY, Parent=None): ''' Constructor ''' super().__init__(Parent) self.__InitData(sizeX, sizeY) #Initialize Data first, then interface/view self.__InitView() print("Init PaintBoard") def __InitView(self): self.setFixedSize(self.__size) def __InitData(self, sizeX, sizeY): self.__size = QSize(sizeX, sizeY) self.__board = QPixmap( self.__size) #Make a new QPixmap as paint board,350px * 250px self.__board.fill(Qt.white) #Fill the paint board with white self.__IsEmpty = True #board is empty by default self.EraserMode = False #eraser mode is disabled by default self.__lastPos = None self.__currentPos = QPoint(0, 0) self.__painter = QPainter() self.__thickness = 1 #default pen thickness is 1 self.__penColor = QColor("black") #default color is black self.__colorList = QColor.colorNames() #get the list of colors def Clear(self): #Clear the board self.__board.fill(Qt.white) self.update() self.__IsEmpty = True def ChangePenColor(self, color="black"): self.__penColor = QColor(color) def ChangePenThickness(self, thickness=1): self.__thickness = thickness def IsEmpty(self): #Is the board empty return self.__IsEmpty def GetContentAsQImage(self): #return the content of the board (return QImage) image = self.__board.toImage() return image def paintEvent(self, paintEvent): self.__painter.begin(self) self.__painter.drawPixmap(0, 0, self.__board) self.__painter.end() # print("inside paintEvent") def penPressEvent(self, pos): self.__currentPos = QPoint(pos[0], pos[1]) self.__lastPos = self.__currentPos def penMoveEvent(self, pos, pressure): pen_x = pos[0] pen_y = pos[1] pen_pressure = pressure if self.__lastPos is None: self.__lastPos = QPoint(pen_x, pen_y) elif (abs(pen_x - self.__lastPos.x()) > 21 or abs(pen_y - self.__lastPos.y()) > 21): self.__lastPos = QPoint(pen_x, pen_y) self.__currentPos = QPoint(pen_x, pen_y) self.__painter.begin(self.__board) if self.EraserMode == False: #Non-Eraser mode self.__painter.setPen(QPen( self.__penColor, self.__thickness)) #Set pen color, thickness else: #Eraser mode: pen color is white, thickness is 6 self.__painter.setPen(QPen(Qt.white, 6)) self.__painter.drawLine(self.__lastPos, self.__currentPos) self.__painter.end() self.__lastPos = self.__currentPos self.update() #Show updates def penVPEvent(self, pos, pressure): pass ''' # Check if the pressure is over 500 if(pen_pressure > 400): # Check which region the pen is in and prepare to draw shape accordingly if(pen_x < self.VPCoord_Circle[2] and pen_y < self.VPCoord_Circle[3]): print("A") elif(pen_x < self.VPCoord_Rect[2] and pen_y < self.VPCoord_Rect[3]): print("B") elif(pen_x < self.VPCoord_Tri[2] and pen_y < self.VPCoord_Tri[3]): print("C") elif(pen_x < self.VPCoord_Line[2] and pen_y < self.VPCoord_Line[3]): print("D") ''' def penReleaseEvent(self, pos): self.__IsEmpty = False #board is not empty def paintEllipse(self, center_x, center_y, radias1, radias2): self.__painter.begin(self.__board) self.__painter.setPen(QPen(self.__penColor, self.__thickness)) self.__painter.drawEllipse(QPoint(center_x, center_y), radias1, radias2) self.__painter.end() self.update() #Show updates def paintRect(self, center_x, center_y, upper_left_x, upper_left_y): width = abs(2 * (center_x - upper_left_x)) height = abs(2 * (center_y - upper_left_y)) self.__painter.begin(self.__board) self.__painter.setPen(QPen(self.__penColor, self.__thickness)) self.__painter.drawRect(upper_left_x, upper_left_y, width, height) self.__painter.end() self.update() #Show updates def paintTriangle(self, points): self.__painter.begin(self.__board) self.__painter.setPen(QPen(self.__penColor, self.__thickness)) self.__painter.drawPolygon(points) self.__painter.end() self.update() #Show updates def paintLine(self, P1_x, P1_y, P2_x, P2_y): P1 = QPoint(P1_x, P1_y) P2 = QPoint(P2_x, P2_y) self.__painter.begin(self.__board) self.__painter.drawLine(P1, P2) self.__painter.end() self.update() #Show updates
class QChessBoard(QWidget): square_size = 72 board_edge = 8 board_width = board_edge + square_size * 9 + board_edge board_height = board_edge + square_size * 10 + board_edge pc_str = ('K', 'A', 'B', 'N', 'R', 'C', 'P', '', 'RK', 'RA', 'RB', 'RN', 'RR', 'RC', 'RP', '', 'BK', 'BA', 'BB', 'BN', 'BR', 'BC', 'BP', '') selected_str = ('', 'S') pc_path = 'images\\IMAGES_X\\COMIC\\' def __init__(self, parent=None): super().__init__(parent) self.board_jpg = QtGui.QPixmap('images\\IMAGES_X\\WOOD.JPG') self.oos_gif = QtGui.QPixmap('images\\IMAGES_X\\COMIC\\OOS.GIF') self.painter = QPainter() self.agent = None self.is_flipped = False # self.game_state = None self.sq_selected = (-1, -1) self.mv_cur = (-1, -1, -1, -1) self.mv_last = (-1, -1, -1, -1) def set_agent(self, agent: AlphaZeroAgent): self.agent = agent def mousePressEvent(self, e: QtGui.QMouseEvent): super().mousePressEvent(e) x, y = e.x(), e.y() x = round((x - 40) / self.square_size) y = round((y - 40) / self.square_size) agent = self.agent env = agent.env player = env.player pc = env.board[y][x] self_side = side_tag(player) if is_self_piece_by_tag(pc, self_side): self.sq_selected = (x, y) self.repaint() return if self.sq_selected != (-1, -1) and not is_self_piece_by_tag( pc, self_side): if not is_legalmove(env.board, self.sq_selected[0], self.sq_selected[1], x, y, player): self.sq_selected = (-1, -1) return """ 玩家走子 """ action = (dict_mv[mv_to_str(self.sq_selected[0], self.sq_selected[1], x, y)], ) env.step(action) self.mv_last = self.mv_cur self.mv_cur = (self.sq_selected[0], self.sq_selected[1], x, y) self.sq_selected = (-1, -1) self.repaint() state = (env.board, env.player, env.depth) game_state = env.get_winner(state) if game_state != None: QMessageBox.information(self, '游戏结束!', '游戏结束!') return """ AI走子 """ self.mv_last = self.mv_cur state = (env.board, env.player, env.depth) action = agent.decide(state) env.step(action) self.mv_cur = str_to_mv(labels_mv[action[0]]) self.sq_selected = (-1, -1) self.repaint() state = (env.board, env.player, env.depth) game_state = env.get_winner(state) print(game_state) if game_state != None: QMessageBox.information(self, '游戏结束!', '游戏结束!') return def printBoard(self): self.env.render() def drawOOS(self, x, y): if x == -1 or y == -1: return x = self.board_edge + self.square_size * x y = self.board_edge + self.square_size * y self.painter.drawPixmap(x, y, self.oos_gif) def paintEvent(self, e): super().paintEvent(e) env = self.agent.env board = env.board self.painter.begin(self) self.painter.drawPixmap(0, 0, self.board_jpg) for j in range(env.BOARD_SHAPE[0]): for i in range(env.BOARD_SHAPE[1]): pc = board[j][i] if pc == 0: continue gif_path = f'{self.pc_path}{self.pc_str[pc]}' \ f'{self.selected_str[int(self.sq_selected == (i, j))]}.GIF' gif = QtGui.QPixmap(gif_path) x = i y = j px = self.board_edge + self.square_size * x py = self.board_edge + self.square_size * y self.painter.drawPixmap(px, py, gif) self.drawOOS(self.mv_last[0], self.mv_last[1]) self.drawOOS(self.mv_last[2], self.mv_last[3]) self.drawOOS(self.mv_cur[0], self.mv_cur[1]) self.drawOOS(self.mv_cur[2], self.mv_cur[3]) self.painter.end()
class PaintBoard(QWidget): def __init__(self, Parent=None): super().__init__(Parent) self.__init_data() self.__init_view() def __init_data(self): """ initial the canvas, painter :return: """ self.__size = QSize(420, 420) # create a new canvas by QPixmap, size for self.__size self.__canvas = QPixmap(self.__size) # set the background of the board as white, for better visual effect self.__canvas.fill(Qt.white) # default for none self.__IsEmpty = True # default for no eraser self.EraserMode = False # initial the last mouse position self.__lastPos = QPoint(0, 0) # initial the current mouse position self.__currentPos = QPoint(0, 0) # new a painter for drawing self.__painter = QPainter() # default pen size for 10px self.__thickness = 30 # default pen color for black self.__penColor = QColor("black") # get the color list from library self.colorList = QColor.colorNames() def __init_view(self): """ set the initial size of the canvas :return: """ self.setFixedSize(self.__size) def clear(self): """ clear the canvas :return: """ self.__canvas.fill(Qt.white) self.update() self.__IsEmpty = True def pen_color(self, color="black"): """ set the color of the pen :param color: :return: """ self.__penColor = QColor(color) def pen_size(self, thick=40): """ set the size of the pen :param thick: :return: """ self.__thickness = thick def is_empty(self): """ return the canvas is empty or not :return: """ return self.__IsEmpty def get_current_image(self): """ fet the current content of the canvas, return as an image :return: """ current_image = self.__canvas.toImage() return current_image def paintEvent(self, paintEvent): """ the painter works between begin() and end() - begin(param): parameter--canvas - drawPixmap: paint QPixmap object 0, 0 start :param paintEvent: :return: """ self.__painter.begin(self) self.__painter.drawPixmap(0, 0, self.__canvas) self.__painter.end() def mousePressEvent(self, mouseEvent): """ capture the mouse when pressed :param mouseEvent: :return: """ self.__currentPos = mouseEvent.pos() self.__lastPos = self.__currentPos def mouseMoveEvent(self, mouseEvent): """ when the mouse moves, update the position :param mouseEvent: :return: """ self.__currentPos = mouseEvent.pos() self.__painter.begin(self.__canvas) if self.EraserMode == False: self.__painter.setPen(QPen(self.__penColor, self.__thickness)) else: self.__painter.setPen((QPen(Qt.white, 40))) self.__painter.drawLine(self.__lastPos, self.__currentPos) self.__painter.end() self.__lastPos = self.__currentPos self.update() def mouseReleaseEvent(self, QMouseEvent): """ set the canvas for not empty :param QMouseEvent: :return: """ self.__IsEmpty = False
def drawIconWithShadow(self, icon, rect, painter, iconMode, radius=3, color=QColor(0, 0, 0, 130), offset=QPoint(1, -2)): ''' @brief: Draw a cached pixmap with shadow @param: icon QIcon @param: rect QRect @param: painter QPainter @param: iconMode QIcon.Mode @param: radius int @param: color QColor @param: offset QPoint ''' cache = QPixmap() pixmapName = 'icon %s %s %s' % (icon.cacheKey(), iconMode, rect.height()) cache = QPixmapCache.find(pixmapName) if not cache: px = icon.pixmap(rect.size(), iconMode) px.setDevicePixelRatio(gVar.app.devicePixelRatio()) cache = QPixmap(px.size() + QSize(radius * 2, radius * 2)) cache.setDevicePixelRatio(px.devicePixelRatioF()) cache.fill(Qt.transparent) cachePainter = QPainter(cache) # Draw shadow tmp = QImage(px.size() + QSize(radius * 2, radius * 2 + 1), QImage.Format_ARGB32_Premultiplied) tmp.setDevicePixelRatio(px.devicePixelRatioF()) tmp.fill(Qt.transparent) tmpPainter = QPainter(tmp) tmpPainter.setCompositionMode(QPainter.CompositionMode_Source) tmpPainter.drawPixmap(QPoint(radius, radius), px) tmpPainter.end() # blur the alpha channel blurred = QImage(tmp.size(), QImage.Format_ARGB32_Premultiplied) blurred.fill(Qt.transparent) blurPainter = QPainter(blurred) # TODO: #qt_blurImage(blurPainter, tmp, radius, False, True) blurPainter.end() tmp = blurred # blacken the image... tmpPainter.begin(tmp) tmpPainter.setCompositionMode(QPainter.CompositionMode_SourceIn) tmpPainter.fillRect(tmp.rect(), color) tmpPainter.end() tmpPainter.begin(tmp) tmpPainter.setCompositionMode(QPainter.CompositionMode_SourceIn) tmpPainter.fillRect(tmp.rect(), color) tmpPainter.end() # draw the blurred drop shadow... cachePainter.drawImage( QRect(0, 0, cache.rect().width() / cache.devicePixelRatioF(), cache.rect().height() / cache.devicePixelRatioF()), tmp) # Draw the actual pixmap... cachePainter.drawPixmap(QPoint(radius, radius) + offset, px) if self.usePixmapCache(): QPixmapCache.insert(pixmapName, cache) sip.delete(cachePainter) sip.delete(tmpPainter) sip.delete(blurPainter) targetRect = QRect(cache.rect()) targetRect.setWidth(cache.rect().width() / cache.devicePixelRatioF()) targetRect.setHeight(cache.rect().height() / cache.devicePixelRatioF()) targetRect.moveCenter(rect.center()) painter.drawPixmap(targetRect.topLeft() - offset, cache)
class MainWindow(QMainWindow, Ui_mainWidget): # 为了实现窗口的显示和业务逻辑分离,新建另一个调用窗口的文件 def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.setupUi(self) self.board = QPixmap(865, 485) self.board.fill(Qt.white) self.is_empty = True # 空画板 self.last_pos = QPoint(0, 0) self.current_pos = QPoint(0, 0) self.painter = QPainter() self.painter.setRenderHint(QPainter.Antialiasing) # 反锯齿 self.clearButton.clicked.connect(self.clear) self.uploadButton.clicked.connect(self.upload) self.runButton.clicked.connect(self.run) # 在此处识别,调用算法中的识别函数 def run(self): algorithm = self.algorithmCombo.currentText() target = self.targetCombo.currentText() print(algorithm, target) # 先保存图片然后找到该图片识别 image = self.board.toImage() # 这里可以改图片存储路径 image_save_path = 'images/testImage.jpg' image.save(image_save_path) # 为了方便,识别时直接去存储路径下获取图片 img_path = image_save_path # 由于尚未尝试用除NN外的算法去同时识别数字+字母,所以当选择其他算法时需要输出提示信息 try: # 需要更名选择不同的model,可能会不存在,先load下来看是否报错 model_path = model_path_dic[algorithm][target_sub[target]] if algorithm == "SVM" or algorithm == "KNN": model = joblib.load(model_path) else: model = load_model(model_path) except: # 如果图片路径下没有相应的图片或是模型路径下没有相应的模型,报错 QMessageBox.about(self, "提示", "暂不支持") self.resultLineEdit.setText("") self.board.fill(Qt.white) else: # 运行并返回预测结果 prediction = run(img_path, model_path, algorithmName_sub[algorithm], target_sub[target]) prediction = ' '.join([str(x) for x in prediction]) print(prediction) self.resultLineEdit.setText(prediction) # 将结果存放在LineEdit中 self.board.load("result.png") self.update() def upload(self): filename = QFileDialog.getOpenFileName(None, 'open', ".") self.board.load(filename[0]) self.update() def clear(self): self.board.fill(Qt.white) self.update() self.is_empty = True self.resultLineEdit.setText("") def paintEvent(self, paintEvent): self.painter.begin(self) self.painter.drawPixmap(0, 0, self.board) self.painter.end() def mouseReleaseEvent(self, QMouseEvent): self.is_empty = False def mousePressEvent(self, QMouseEvent): self.current_pos = QMouseEvent.pos() self.last_pos = self.current_pos def mouseMoveEvent(self, QMouseEvent): self.current_pos = QMouseEvent.pos() self.painter.begin(self.board) self.painter.setPen(QPen(Qt.black, 6)) self.painter.drawLine(self.last_pos, self.current_pos) self.painter.end() self.last_pos = self.current_pos self.update()
class PaintBoard(QWidget): def __init__(self): QWidget.__init__(self) # self.label = QLabel(self) # self.gridLayout = QGridLayout(self) # self.gridLayout.addWidget(self.label) self.pixmap = QPixmap(1,1) self.pixmap.fill(Qt.white) self.img = QImage(self.pixmap.toImage()) # self.label.setFrameShape(1) # # self.label.setPixmap(self.pixmap) # self.label.setScaledContents(True) # self.label.setVisible(False) self.pen = QPainter() def paintEvent(self, paintEvent): self.pixmap = self.pixmap.scaled(self.width(), self.height()) self.pen.begin(self) # self.pen.drawPixmap(0, 0, self.pixmap) self.img = QImage(self.pixmap.toImage()) self.pen.drawImage(0, 0, self.img) self.pen.end() def drawPoints(self, x, y): # print(self.width(),self.height()) m = int(self.width()/2) + x n = int(self.height()/2) - y self.pen.begin(self.pixmap) self.pen.setPen(QPen(Qt.black,1)) self.pen.drawPoint(m, n) self.pen.end() self.update() # self.repaint() def load_img(self, img): self.pixmap.load(img) self.update() #DDA def drawLine(self, x0, y0, x1, y1): self.Clear() dx = x1 - x0 dy = y1 - y0 if fabs(dx) > fabs(dy): steps = fabs(dx) else: steps = fabs(dy) self.drawPoints(int(x0+0.5), int(y0+0.5)) xInc = dx/steps yInc = dy/steps for i in range(int(steps+0.5)): x0 += xInc y0 += yInc self.drawPoints(int(x0+0.5), int(y0+0.5)) #中点法画圆 def CirclePlot(self, xc, yc, x, y): self.drawPoints(x+xc, y+yc) self.drawPoints(-x+xc, y+yc) self.drawPoints(x+xc, -y+yc) self.drawPoints(-x+xc, -y+yc) self.drawPoints(y+xc, x+yc) self.drawPoints(y+xc, -x+yc) self.drawPoints(-y+xc, x+yc) self.drawPoints(-y+xc, -x+yc) def drawRound(self, xc, yc, r): self.Clear() x = 0 y = r d = 3-2*r self.CirclePlot(xc, yc, x, y) while x<y: if d<0: d = d+4*x+6 else: d = d+4*(x-y)+10 y -= 1 x +=1 self.CirclePlot(xc, yc, x, y) ''' # 边界填充 def fill(self, x, y): w = int(self.width()/2) h = int(self.height()/2) block = deque([(x, y)]) while 1: if len(block) == 0: break else: # print(block) point = block.popleft() m = point[0] n = point[1] # c = self.img.pixel(w+m, h+n) # colors = QColor(c).getRgb() # if colors != (0, 0, 0, 255): self.drawPoints(m, n) # result.append((m,n)) c = self.img.pixel(w+m, h+n-1) colors = QColor(c).getRgb() if colors != (0, 0, 0, 255): if (m,n-1) not in block: block.append((m,n-1)) c = self.img.pixel(w+m, h+n+1) colors = QColor(c).getRgb() if colors != (0, 0, 0, 255): if (m,n+1) not in block: block.append((m,n+1)) c = self.img.pixel(w+m-1, h+n) colors = QColor(c).getRgb() if colors != (0, 0, 0, 255): if (m-1,n) not in block: block.append((m-1,n)) c = self.img.pixel(w+m+1, h+n) colors = QColor(c).getRgb() if colors != (0, 0, 0, 255): if (m+1,n) not in block: block.append((m+1,n)) print(results) ''' #边界填充 #种子边界填充 def fill(self, x, y): w = int(self.width()/2) h = int(self.height()/2) block = deque([(x, y)]) results = [] while 1: if len(block) == 0: break else: point = block.popleft() m = point[0] n = point[1] results.append((m,n)) c = self.img.pixel(w+m, h+n-1) colors = QColor(c).getRgb() if colors != (0, 0, 0, 255): if (m,n-1) not in block: if (m,n-1) not in results: block.append((m,n-1)) c = self.img.pixel(w+m, h+n+1) colors = QColor(c).getRgb() if colors != (0, 0, 0, 255): if (m,n+1) not in block: if (m,n+1) not in results: block.append((m,n+1)) c = self.img.pixel(w+m-1, h+n) colors = QColor(c).getRgb() if colors != (0, 0, 0, 255): if (m-1,n) not in block: if (m-1,n) not in results: block.append((m-1,n)) c = self.img.pixel(w+m+1, h+n) colors = QColor(c).getRgb() if colors != (0, 0, 0, 255): if (m+1,n) not in block: if (m+1,n) not in results: block.append((m+1,n)) for point in results: self.drawPoints(point[0], point[1]) def Clear(self): self.pixmap.fill(Qt.white) self.update()
def paintEvent(self, event): qp = QPainter() qp.begin(self) self.draw(event, qp) qp.end()
class ImageDisplay(QWidget): video_infos = ['vidéo : {}','nb frames : {}','taille : {}','FPS : {}','durée : {:.2f} sec'] video_keys = ['videoname','nframes','size','fps','duration'] algo_traj = ['barycentre','minmax'] def __init__(self, mainWindow): # acall the base class constructor: super().__init__(mainWindow) self.mw = mainWindow # Attributs (objets persistants) self.img_lbl = QLabel(self) # to display the current image self.img_lbl.installEventFilter(self) # filter to catch evenements self.selectTargetRect = None # display a rectangle to show teh target color selection self.rubberBand = QRubberBand(QRubberBand.Line, self) # Boutons pour avancer/reculer self.btn_prev = QPushButton(QIcon("icones/go-prev.png"), "", self) self.btn_next = QPushButton(QIcon("icones/go-next.png"), "", self) self.btn_first = QPushButton(QIcon("icones/go-first.png"), "", self) self.btn_last = QPushButton(QIcon("icones/go-last.png"), "", self) self.btn_traj = QPushButton(QIcon("icones/extract.png"), "Extraire...", self) self.btn_clear = QPushButton(QIcon("icones/clear.png"), "Effacer courbes...", self) self.btn_exportCSV = QPushButton(QIcon("icones/exportCSV.png"), "Export CSV", self) self.btn_algo = QComboBox(self) self.image_index = QLabel(self) # widget QSpinBox self.images_step = QSpinBox(parent=self) self.images_firstRank = QSpinBox(parent=self) self.images_lastRank = QSpinBox(parent=self) # QLabel to display the target color self.target_color_label = QLabel("target color",parent=self) self.picked_color = QLabel(self) self.video_path = None # Chemin de la dernière vidéo self.images_dir = None # Dossier contenant les images self.__img_idx = None # Rang de l'image affichée self.img_path = None # nom du chemin de l'image courante self.nb_img = None # nombre d'images self.video_name = None # nom de la video ("aaaaaa.mp4") self.video_nframes = None # nombre d'images dans la video self.video_size = None # taille (width, height) des images self.video_FPS = None # nombre d'images par seconde self.video_duration = None # durée de la video en secondes self.videoLabels = [] # liste de QLabel contenant les infos vidéo self.dico_video = {} # dictionnaire des méta-données self.dico_unit = {} # dictionary "pixels", "mm" self.scale_pixel = None # nombre de pixels pour conversion en mm self.scale_mm = None # nbre de mm pour scale_pixel self.valid_scale = False # données de l'échelle valides ou pas self.pix_to_mm_coeff= 1. # le coefficient de converion pixels -> mm self.dicoScale = {} # dictionnaire des QWidget d'info scale self.lbl_epsilon = None # label epsilon self.epsi_spin = None # boite de choix de epsilon # créer l'onglet de visualisation image """ self.__initUI() self.scaleInfoVisible(False) self.__epsilonVisible(False) def __initUI(self): # Onglet "Visualisation images" vbox = QVBoxLayout() # Ligne 1 : extraction trajec self.picked_color.setFrameStyle(QFrame.StyledPanel | QFrame.Plain); line1 = QHBoxLayout() line1.addStretch(1) line1.addWidget(self.btn_algo) line1.addWidget(self.btn_traj) line1.addWidget(self.target_color_label) line1.addWidget(self.picked_color) line1.addWidget(self.btn_clear) line1.addWidget(self.btn_exportCSV) line1.addStretch(1) # Ligne 2 : infos video + visu image line2 = QHBoxLayout() # boîte d'infos sur la vidéo infoVBox = QVBoxLayout() for _ in ImageDisplay.video_infos: label = QLabel(self) label.setFrameStyle(QFrame.StyledPanel | QFrame.Plain); infoVBox.addWidget(label) self.videoLabels.append(label) infoVBox.addStretch() widget = QLabel("Conversion pixels -> mm", self) self.dicoScale['Pixels-mm'] = widget infoVBox.addWidget(widget) grid = QGridLayout() infoVBox.addLayout(grid) widget = QLabel("pixels ",self) self.dicoScale['pixels'] = widget grid.addWidget(widget,1,1) self.scale_pixel = QLineEdit(self) self.dicoScale['pixelsForMM'] = self.scale_pixel grid.addWidget(self.scale_pixel,1,2) widget = QLabel("millimètres ",self) self.dicoScale['millimeters'] = widget grid.addWidget(widget,2,1) self.scale_mm = QLineEdit(self) self.dicoScale['mmForPixels'] = self.scale_mm grid.addWidget(self.scale_mm,2,2) self.lbl_epsilon = QLabel("Epsilon ",self) grid.addWidget(self.lbl_epsilon,5,1) self.epsi_spin = QSpinBox(self) self.epsi_spin.setRange(1,50) self.epsi_spin.setSingleStep(1) self.epsi_spin.setValue(10) grid.addWidget(self.epsi_spin,5,2) infoVBox.addStretch() line2.addLayout(infoVBox) line2.addStretch(1) line2.addWidget(self.img_lbl) # le QLabel por afficher l'image line2.addStretch(1) # line 3 : navigation boutons self.image_index.setFrameStyle(QFrame.Panel | QFrame.Sunken) self.image_index.setText(" ") line3 = QHBoxLayout() line3.addStretch(1) line3.addWidget(self.btn_first) line3.addWidget(self.btn_prev) line3.addWidget(self.image_index) line3.addWidget(self.btn_next) line3.addWidget(self.btn_last) line3.addStretch(1) # line 4 : first , step, last image selection line4 = QHBoxLayout() line4.addStretch(1) line4.addWidget(self.images_firstRank) line4.addWidget(self.images_step) line4.addWidget(self.images_lastRank) line4.addStretch(1) vbox.addLayout(line1) vbox.addStretch(1) vbox.addLayout(line2) vbox.addStretch(1) vbox.addLayout(line3) vbox.addLayout(line4) self.setLayout(vbox) self.buttonsState() self.__buttonsConnect() self.__setVideoLabelVisible(False) def __setVideoLabelVisible(self, state): for label in self.videoLabels: label.setVisible(state) def __buttonsConnect(self): self.btn_traj.clicked.connect(self.extract_trajectoire) self.btn_clear.clicked.connect(self.mw.clearPlots) self.btn_exportCSV.clicked.connect(self.mw.ExportCSV) self.btn_prev.clicked.connect(self.prev_image) self.btn_next.clicked.connect(self.next_image) self.btn_first.clicked.connect(self.first_image) self.btn_last.clicked.connect(self.last_image) self.images_step.valueChanged.connect(self.__step_changed) self.images_firstRank.valueChanged.connect(self.__first_rank_changed) self.images_lastRank.valueChanged.connect(self.__last_rank_changed) def buttonsState(self, importCSV=False): self.btn_traj.setEnabled(False) self.picked_color.setText("X") self.picked_color.setEnabled(False) self.btn_traj.setStatusTip('Extrait la trajectoire de la cible'+ 'dont la couleur a été choisie') self.target_color_label.setEnabled(False) self.picked_color.setStyleSheet('background-color : rgb(255, 255, 255)') self.btn_clear.setEnabled(False) self.btn_clear.setStatusTip('Nettoye tous les tracés des onglets'+ '<trajectoire> et <X(t), Y(t)>') self.btn_exportCSV.setEnabled(False) texte = "Export des données dans un fichier CSV" self.btn_exportCSV.setStatusTip(texte) if not importCSV: self.btn_algo.addItems(ImageDisplay.algo_traj) self.btn_algo.setEnabled(False) self.btn_prev.setEnabled(False) self.btn_prev.setStatusTip("affiche l'image précédente") self.btn_next.setEnabled(False) self.btn_next.setStatusTip("affiche l'image suivante") self.btn_first.setEnabled(False) self.btn_first.setStatusTip("affiche la première image à traiter") self.btn_last.setEnabled(False) self.btn_last.setStatusTip("affiche la dernière image à traiter") # SpinBoxes parameters: self.images_step.setRange(1,1000) self.images_step.setSingleStep(1) self.images_step.setValue(1) self.images_step.setPrefix("step: ") self.images_step.setEnabled(False) self.images_step.setStatusTip("Fixe le pas pour passer d'une image à l'autre") self.images_firstRank.setRange(1,1000) self.images_firstRank.setSingleStep(1) self.images_firstRank.setValue(1) self.images_firstRank.setPrefix("first: ") self.images_firstRank.setEnabled(False) self.images_firstRank.setStatusTip("Fixe le rang de la première image à traiter") self.images_lastRank.setRange(1,10000) self.images_lastRank.setSingleStep(1) self.images_lastRank.setValue(1) self.images_lastRank.setPrefix("last: ") self.images_lastRank.setEnabled(False) self.images_lastRank.setStatusTip("Fixe le rang de la dernière image à traiter") def __first_rank_changed(self, val): if self.img_idx is None: return if self.img_idx < val: self.img_idx = val self.show_image() def __last_rank_changed(self, val): if self.img_idx is None: return if self.img_idx > val: self.img_idx = val self.show_image() def __step_changed(self, val): if self.img_idx is None: return def setTextInfoVideoGrid(self): for field, name, key in zip(self.videoLabels, ImageDisplay.video_infos, ImageDisplay.video_keys): mess = name.format(self.dico_video.get(key,'?')) field.setText(mess) self.__setVideoLabelVisible(True) def scaleInfoVisible(self, state): for widget in self.dicoScale.values(): widget.setVisible(state) def __epsilonVisible(self, state): self.lbl_epsilon.setVisible(state) self.epsi_spin.setVisible(state) def open_video(self): '''Lance un sélecteur de fichier pour choisir la vidéo à traiter.''' fname = QFileDialog.getOpenFileName(None, 'Choisir une vidéo', self.mw.cur_dir, 'Fichier vidéo (*.mp4)') if fname[0] != '' : # un fichier vidéo a été chosi : vp = fname[0] if self.video_path == vp : name = os.path.basename(vp) rep = QMessageBox.question(self, # widget parent de QMessageBox 'Question', # texte du bandeau de la fenêtre 'Voulez-vous recharger le fichier video {} ?'.format(name), QMessageBox.Yes | QMessageBox.No, # afficher les boutons Yes et No QMessageBox.No) # bouton No sélectionné par défaut if rep == QMessageBox.No: return # fichier vidéo à traiter => faire le split des images : self.video_path = vp self.extract_images_from_video() def load_images_from_directory(self): '''Charge les images '*.png' contenue dans le répertoire des images choisi avec un sélecteur graphique.''' # Choix du répertoire avec un sélecteur de fichier : dname = QFileDialog.getExistingDirectory(None, 'Choisir un dossier images', self.mw.image_dir) if dname != '' : # un répertoire valide a été choisi : self.video_path = None self.images_dir = dname + "/" try: # Lecture du fichier ascii des méta-données with open(self.images_dir + "metaData.txt", "r") as F: data = F.read() exec('self.dico_video = '+data) except: rep = QMessageBox.critical( None, # widget parent de QMessageBox 'Erreur', # bandeau de la fenêtre 'Pas de fichier de méta-données dans le répertoire'+\ ' <{}>'.format(os.path.basename(dname)), QMessageBox.Ok) return print("méta données :", self.dico_video) self.parse_meta_data() self.setTextInfoVideoGrid() # Mettre à jour l'application avec les nouvelles images chargées : self.update_images() def extract_trajectoire(self): '''Méthode utilisée pour extraire la trajectoire du centre de la cible pour toutes les images de la vidéo.''' # Récupérer l'algorithme de calcul du centre de la cible : algo = self.btn_algo.currentText() # Définition de la liste dans laquelle on va récupérer les coordonnées # du centre cible pour toutes les images : target_pos = [] # Création d'un objet ProgressBar qui va lancer le travail # d'extraction de la cible dans les images tout en affichant une # barre d'avancement : first = self.images_firstRank.value() last = self.images_lastRank.value() step = self.images_step.value() last = last - (last - first) % step first_last_step = (first, last, step) pg = ProgressBar(self.images_dir, self) pg.configure_for_target_extraction(self.mw.target_RGB, algo, self.epsi_spin.value(), target_pos, first_last_step) ret = pg.exec_() # lance la barre et le travail d'extraction... print("retour de pg.exec_() :",ret) if ret != 0: self.mw.target_pos = None return target_pos = np.array(target_pos) width, height = self.video_size # l'axe verticale est retourné et decalé: target_pos[1] = height - target_pos[1] self.scale_XY() self.mw.target_pos = target_pos self.display_plots() # remettre le bouton extraire_trajectoire disabled: self.btn_exportCSV.setEnabled(True) def display_plots(self): self.mw.clearPlots() # Plot trajectory (X(t), Y(t)) : self.mw.onePlot.setEnabled(True) self.mw.onePlot.Plot() # Plot curves X(t) and Y(t) self.mw.twoPlots_xy.setEnabled(True) self.mw.tabs.setCurrentWidget(self.mw.twoPlots_xy) self.mw.twoPlots_xy.Plot() # Plot curves VX(t) and VY(t) self.mw.twoPlots_VxVy.setEnabled(True) self.mw.tabs.setCurrentWidget(self.mw.twoPlots_xy) self.mw.twoPlots_VxVy.Plot() def extract_images_from_video(self) : # name of the video file without path and suffix: videoname = os.path.basename(self.video_path)[:-4] # directory where to put extracted iamges: self.images_dir = self.mw.image_dir + videoname + "/" if os.path.isdir(self.images_dir) : print("Effacement de tous les fichiers de '{}'"\ .format(self.images_dir)) for fn in os.listdir(self.images_dir) : os.remove(self.images_dir+fn) else : os.mkdir(self.images_dir) video = cv2.VideoCapture(self.video_path) self.dico_video['nframes'] = int(video.get(cv2.CAP_PROP_FRAME_COUNT)) self.dico_video['size'] = (int(video.get(cv2.CAP_PROP_FRAME_WIDTH)), int(video.get(cv2.CAP_PROP_FRAME_HEIGHT))) self.dico_video['fps'] = int(video.get(cv2.CAP_PROP_FPS)) self.dico_video['duration'] = video.get(cv2.CAP_PROP_FRAME_COUNT)/video.get(cv2.CAP_PROP_FPS) self.dico_video['videoname'] = os.path.basename(self.video_path) self.parse_meta_data() self.dico_video["videoname"] = videoname+".mp4" self.setTextInfoVideoGrid() # Création d'un objet ProgressBar qui va lancer le travail # d'extraction des images tout en affichant une barre d'avancement : pg = ProgressBar(self.images_dir, self) pg.configure_for_video_extraction(video, self.mw.image_fmt) ret = pg.exec_() print("retour de pg.exec_() :", ret) if ret != 0: return # MAJ de la liste des fichiers images : self.update_images() # écriture des méta-data dans le fichier 'nom_video'.info with open(self.mw.image_dir+videoname+"/metaData.txt", "w") as F: F.write(str(self.dico_video)) def computeTargetColor(self, draw_selection=False): col_min,row_min,col_max,row_max = self.selection.getCoords() print("Pixels selectionnés : lignes [{},{}] colonnes [{},{}]".\ format(row_min, row_max, col_min, col_max)) tab = imread(self.img_path) self.target_pix = tab[row_min:row_max+1, col_min:col_max+1, :] R = round(self.target_pix[:,:,0].mean()) G = round(self.target_pix[:,:,1].mean()) B = round(self.target_pix[:,:,2].mean()) self.mw.target_RGB = np.array([R, G, B], dtype=int) print("RGB sélection dans <{}> :".format(os.path.basename(self.img_path)), self.mw.target_RGB) draw_selection = self.mw.flags["drawTargetSelection"] if draw_selection: self.show_image() print("drawTargetSelection") #if self.selectTargetRect is not None : del self.selectTargetRect # create painter instance with pixmap self.selectTargetRect = QPainter(self.img_lbl.pixmap()) # set rectangle color and thickness self.penRectangle = QPen(QColor(0,0,0)) self.penRectangle.setWidth(2) # draw rectangle on painter self.selectTargetRect.begin(self) self.selectTargetRect.setPen(self.penRectangle) self.selectTargetRect.drawRect(col_min,row_min, col_max-col_min,row_max-row_min) self.selectTargetRect.setOpacity(0.1) self.selectTargetRect.end() #self.show_image() self.btn_traj.setEnabled(True) self.btn_algo.setEnabled(True) self.btn_clear.setEnabled(True) self.target_color_label.setEnabled(True) self.picked_color.setStyleSheet('background-color : rgb({},{},{})'.format(R, G, B)) @property def img_idx(self): return self.__img_idx @img_idx.setter def img_idx(self, index): self.__img_idx = index self.image_index.setText(str(index)) def update_images(self) : '''Méthode à exécuter quand de nouvelles images sont apparues après une extraction d'images depuis une vidéo par exemple. Cette méthode : - met à jour des attributs qui dépendant de la liste des images, - met à jour l'état de certains boutons - fait afficher la première image et un message d'information.''' if self.images_dir is None : self.__img_idx = None #self.btn_prev.setEnabled(False) self.btn_prev.setStatusTip("") #self.btn_next.setEnabled(False) self.btn_next.setStatusTip("") self.images_step.setEnabled(False) self.images_firstRank.setEnabled(False) self.images_lastRank.setEnabled(False) else : self.buttonsState() self.mw.clearPlots() self.mw.twoPlots_VxVy.reset() # liste des noms des fichiers image pour avoir leur nombre : file_names = [ f for f in os.listdir(self.images_dir) \ if f.endswith('.png')] file_names.sort() self.nb_img = len(file_names) # Update spinBox: self.images_step.setEnabled(True) self.images_firstRank.setEnabled(True) self.images_lastRank.setEnabled(True) self.images_firstRank.setValue(1) self.images_step.setValue(1) self.images_lastRank.setValue(self.nb_img) self.images_firstRank.setMaximum(self.nb_img) self.images_lastRank.setMaximum(self.nb_img) self.images_step.setMaximum(self.nb_img) # MAJ des boutons prev et next self.img_idx = self.images_firstRank.value() self.btn_prev.setEnabled(True) self.btn_first.setEnabled(True) self.btn_prev.setStatusTip("charge l'image précédente") self.btn_next.setEnabled(True) self.btn_last.setEnabled(True) self.btn_next.setStatusTip("afficher "+self.mw.image_fmt.format(\ self.img_idx+self.images_step.value())) self.show_image() self.scaleInfoVisible(True) self.__epsilonVisible(True) self.mw.tabs.setCurrentWidget(self) self.scale_mm.clear() self.scale_mm.setText("???") self.scale_pixel.clear() try: text = str(self.video_size[1]) except: text = "" self.scale_pixel.setText(text) self.mw.twoPlots_VxVy.reset() if self.mw.flags["displayInfo"]: rep = QMessageBox.information( None, # widget parent de QMessageBox 'Information', # bandeau de la fenêtre 'Vous pouvez maintenant sélectionner une couleur de cible'+\ 'avec la souris...', QMessageBox.Ok) def show_image(self): '''Affiche l'image dont le numéro est donné par l'attribut 'img_idx'.''' if self.img_idx is None : self.img_path = '' else : self.img_path = self.images_dir+self.mw.image_fmt.format(self.img_idx) pixmap = QPixmap(self.img_path) self.img_lbl.setPixmap(pixmap) self.img_lbl.setStatusTip(os.path.basename(self.img_path)) def first_image(self) : if self.img_idx == None : return self.img_idx = self.images_firstRank.value() self.mw.statusBar().showMessage("") self.show_image() def prev_image(self) : if self.img_idx == None : return if self.img_idx >= self.images_firstRank.value() + self.images_step.value(): self.img_idx -= self.images_step.value() self.mw.statusBar().showMessage("") self.show_image() def last_image(self) : if self.img_idx == None : return self.img_idx = self.images_lastRank.value() # rank of last image to process self.mw.statusBar().showMessage("") self.show_image() def next_image(self) : if self.img_idx == None : return if self.img_idx <= self.images_lastRank.value()-self.images_step.value(): self.img_idx += self.images_step.value() self.mw.statusBar().showMessage("") self.show_image() def parse_meta_data(self): self.video_nframes = self.dico_video.get('nframes', None) self.video_size = self.dico_video.get('size', None) self.video_FPS = self.dico_video.get('fps', None) self.video_duration = self.dico_video.get('duration', None) self.video_name = self.dico_video.get('videoname',"none.mp4") if self.mw.flags["debug"]: info= " nb images : {},\n taille image : {},\n FPS : {} image/sec,\n durée : {.2f} sec." info = info.format(self.video_nframes, self.video_size, self.video_FPS, self.video_duration) QMessageBox.about(None, # widget parent de QMessageBox 'Informations video {}'.format(self.video_name), info) def eventFilter(self, object, event): if object == self.img_lbl : if event.type() == QEvent.MouseButtonPress: self.mousePressInLabel(event) return True elif event.type() == QEvent.MouseButtonRelease: self.mouseReleaseInLabel(event) return True elif event.type() == QEvent.MouseMove: self.mouseMoveInLabel(event) return True return False def mousePressInLabel(self, event): if event.button() == Qt.LeftButton: self.pt1 = event.pos() self.pt1_rect = self.img_lbl.mapTo(self, self.pt1) print("\nCoord. pt1 image :",self.pt1) self.rubberBand.setGeometry(QRect(self.pt1_rect, QSize())) self.rubberBand.show() self.mw.statusBar().showMessage('sélection en cours....') def mouseMoveInLabel(self, event): if not self.pt1.isNull(): pt = self.img_lbl.mapTo(self,event.pos()) self.rubberBand.setGeometry(QRect(self.pt1_rect, pt).normalized()) def mouseReleaseInLabel(self, event): if event.button() == Qt.LeftButton: self.pt2 = event.pos() print("Coord. pt2 image :", self.pt2) self.rubberBand.hide() self.selection = QRect(self.pt1, self.pt2).normalized() print(self.selection) self.computeTargetColor() def scale_XY(self): self.valid_scale = False self.pix_to_mm_coeff = 1. try : pixels = float(self.scale_pixel.text()) mm = float(self.scale_mm.text()) except : if self.mw.flags["displayInfo"]: info = 'Les données de conversion Pixels -> mm n\'ont pas été ' info += 'complétées.. les ordonnées des tracés seront en pixels.' rep = QMessageBox.information(None, # parent de QMessageBox 'Info', # bandeau de la fenêtre info, QMessageBox.Ok) return self.valid_scale = True self.pix_to_mm_coeff = mm/pixels print("valid scale : ", self.pix_to_mm_coeff)
class PaintBoard(QWidget): def __init__(self, Parent=None): super().__init__(Parent) self.__InitData() #先初始化数据,再初始化界面 self.__InitView() def __InitData(self): self.__size = QSize(1024, 512) #新建QPixmap作为画板,尺寸为__size self.__board = QPixmap(self.__size) self.__board.fill(Qt.white) #用白色填充画板 self.__IsEmpty = True #默认为空画板 self.EraserMode = False #默认为禁用橡皮擦模式 self.__lastPos = QPoint(0, 0) #上一次鼠标位置 self.__currentPos = QPoint(0, 0) #当前的鼠标位置 self.__painter = QPainter() #新建绘图工具 self.__thickness = 6 #默认画笔粗细为6px self.__eraser = 20 def __InitView(self): #设置界面的尺寸为__size self.setFixedSize(self.__size) def Clear(self): #清空画板 self.__board.fill(Qt.white) self.update() self.__IsEmpty = True def ChangePenThickness(self, eraser=20): #改变橡皮画笔粗细,默认20px self.__eraser = eraser def IsEmpty(self): #返回画板是否为空 return self.__IsEmpty def GetContentAsQImage(self): #获取画板内容(返回QImage) image = self.__board.toImage() return image def paintEvent(self, paintEvent): #绘图事件 #绘图时必须使用QPainter的实例,此处为__painter #绘图在begin()函数与end()函数间进行 #begin(param)的参数要指定绘图设备,即把图画在哪里 #drawPixmap用于绘制QPixmap类型的对象 self.__painter.begin(self) # 0,0为绘图的左上角起点的坐标,__board即要绘制的图 self.__painter.drawPixmap(0, 0, self.__board) self.__painter.end() def mousePressEvent(self, mouseEvent): #鼠标按下时,获取鼠标的当前位置保存为上一次位置 self.__currentPos = mouseEvent.pos() self.__lastPos = self.__currentPos def mouseMoveEvent(self, mouseEvent): #鼠标移动时,更新当前位置,并在上一个位置和当前位置间画线 self.__currentPos = mouseEvent.pos() self.__painter.begin(self.__board) if self.EraserMode == False: #非橡皮擦模式 self.__painter.setPen( QPen(Qt.red, 6, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) #设置画笔颜色,粗细 else: #橡皮擦模式下画笔为纯白色 self.__painter.setPen( QPen(Qt.white, self.__eraser, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) #画线 self.__painter.drawLine(self.__lastPos, self.__currentPos) self.__painter.end() self.__lastPos = self.__currentPos self.update() #更新显示 def mouseReleaseEvent(self, mouseEvent): self.__IsEmpty = False #画板不再为空
class MyMainWindow(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super(MyMainWindow, self).__init__(parent) self.setupUi(self) self.setMouseTracking(True) self.imglist = [] self.ImgFolder = '' self.CurImg = '' #新建QPixmap作为画板,尺寸为__size self.__board = QPixmap() self.__board.fill(Qt.white) #用白色填充画板 self.__IsEmpty = True # 默认为空画板 self.EraserMode = False # 默认为禁用橡皮擦模式 self.__lastPos = QPoint(0, 0) # 上一次鼠标位置 self.__currentPos = QPoint(0, 0) # 当前的鼠标位置 self.__painter = QPainter() # 新建绘图工具 self.__thickness = 10 # 默认画笔粗细为10px self.__penColor = QColor("black") # 设置默认画笔颜色为黑色 self.__colorList = QColor.colorNames() # 获取颜色列表 # 按键信号与回调函数连接 self.OpenDir.clicked.connect(self.OpenDirBntClicked) self.NextImg.clicked.connect(self.NextImBntClicked) self.LastImg.clicked.connect(self.PreImBntClicked) self.SaveImg.clicked.connect(self.on_btn_Save_Clicked) self.PenThicknessSpinBox.valueChanged.connect(self.on_PenThicknessChange) # self.NextImg.clicked.connect(self.NextImBntClicked) #########选择图片文件夹######### def OpenDirBntClicked(self): self.ImgFolder = QtWidgets.QFileDialog.getExistingDirectory(None, "select folder", DefaultImFolder) # 这个语句有些邪门 if self.ImgFolder != '': ImNameSet = os.listdir(self.ImgFolder) self.imglist = glob.glob(self.ImgFolder + '/*.jpg') print(self.imglist) print(ImNameSet) ImNameSet.sort() # ImPath = os.path.join(ImFolder, ImNameSet[0]) ImPath = os.path.join(self.ImgFolder, ImNameSet[1]) # pix = QtGui.QPixmap(ImPath) # self.ImgShowLabel.setPixmap(pix) # 画板 # self.__board = QtGui.QPixmap(r'C:\Users\49942\Pictures\Saved Pictures\t2.jpg') self.__board = QtGui.QPixmap(self.imglist[0]) self.__board = self.__board.scaled(500,500) # self.__IsEmpty = True # 默认为空画板 # self.EraserMode = False # 默认为禁用橡皮擦模式 # # self.__lastPos = QPoint(0, 0) # 上一次鼠标位置 # self.__currentPos = QPoint(0, 0) # 当前的鼠标位置 # # self.__painter = QPainter() # 新建绘图工具 # # self.__thickness = 5 # 默认画笔粗细为10px # self.__penColor = QColor("black") # 设置默认画笔颜色为黑色 # self.__colorList = QColor.colorNames() # 获取颜色列表 # 界面标题 self.ImNameSet = ImNameSet self.CurImId = 0 _, SelectFolderName = os.path.split(self.ImgFolder) CopyImFolderName = 'From{}CopyIm_{}-{}-{}-{}'.format(SelectFolderName, Month, Day, Hour, Minute) self.CopyImFolder = os.path.join(CurFolder, CopyImFolderName) _translate = QtCore.QCoreApplication.translate CurWinTitle = "检测工具 " + \ " " + \ SelectFolderName + '\\' + ImNameSet[0] self.setWindowTitle(_translate("MainWindow", '审查工具 '+self.imglist[0])) else: print('请重新选择文件夹') #########显示下一张图片 ######### def NextImBntClicked(self): ImFolder = self.ImgFolder # ImNameSet = self.ImNameSet CurImId = self.CurImId ImNum = len(self.imglist) if CurImId < ImNum - 1: # 不可循环看图 ImPath = os.path.join(ImFolder, self.imglist[CurImId + 1]) self.__board = QtGui.QPixmap(self.imglist[CurImId + 1]) self.__board = self.__board.scaled(500, 500) self.update() # self.ImgShowLabel.setPixmap(pix) self.CurImId = CurImId + 1 _, SelectFolderName = os.path.split(ImFolder) _translate = QtCore.QCoreApplication.translate CurWinTitle = "审查图片 " + \ " " + \ SelectFolderName + '\\' self.setWindowTitle(_translate("MainWindow", self.imglist[CurImId + 1])) #########显示前一张图片 ######### def PreImBntClicked(self): ImFolder = self.ImgFolder ImNameSet = self.ImNameSet CurImId = self.CurImId ImNum = len(self.imglist) if CurImId > 0: # 第一张图片没有前一张 ImPath = os.path.join(ImFolder, ImNameSet[CurImId - 1]) self.__board = QtGui.QPixmap(self.imglist[CurImId - 1]) self.__board = self.__board.scaled(500,500) self.update() # self.ImgShowLabel.setPixmap(pix) self.CurImId = CurImId - 1 _, SelectFolderName = os.path.split(ImFolder) _translate = QtCore.QCoreApplication.translate CurWinTitle = "看图工具1.0 " + \ " " + \ SelectFolderName + '\\' self.setWindowTitle(_translate("MainWindow", self.imglist[CurImId - 1])) if self.CurImId < 0: self.CurImId = 0 def Clear(self): # 清空画板 self.__board.fill(Qt.white) self.update() self.__IsEmpty = True def ChangePenColor(self, color="black"): # 改变画笔颜色 self.__penColor = QColor(color) def ChangePenThickness(self, thickness=10): # 改变画笔粗细 self.__thickness = thickness def IsEmpty(self): # 返回画板是否为空 return self.__IsEmpty def GetContentAsQImage(self): # 获取画板内容(返回QImage) image = self.__board.toImage() return image def paintEvent(self, paintEvent): # 绘图事件 # 绘图时必须使用QPainter的实例,此处为__painter # 绘图在begin()函数与end()函数间进行 # begin(param)的参数要指定绘图设备,即把图画在哪里 # drawPixmap用于绘制QPixmap类型的对象 self.__painter.begin(self) # 0,0为绘图的左上角起点的坐标,__board即要绘制的图 self.__painter.drawPixmap(0, 0, self.__board) self.__painter.end() def mousePressEvent(self, mouseEvent): # 鼠标按下时,获取鼠标的当前位置保存为上一次位置 self.__currentPos = mouseEvent.pos() self.__lastPos = self.__currentPos def mouseMoveEvent(self, mouseEvent): # 鼠标移动时,更新当前位置,并在上一个位置和当前位置间画线 self.__currentPos = mouseEvent.pos() if mouseEvent.buttons() == QtCore.Qt.LeftButton: self.__painter.begin(self.__board) if self.EraserMode == False: # 非橡皮擦模式 self.__painter.setPen(QPen(self.__penColor, self.__thickness)) # 设置画笔颜色,粗细 else: # 橡皮擦模式下画笔为纯白色,粗细为10 self.__painter.setPen(QPen(Qt.white, 10)) # 画线 self.__painter.drawLine(self.__lastPos, self.__currentPos) self.__painter.end() self.__lastPos = self.__currentPos self.update() # 更新显示 self.mouseEventpos = mouseEvent.pos() # pos = self.mapToGlobal(mouseEvent.pos()) #相對位置轉絕對 # print(pos) pos = QCursor.pos() hwnd = win32gui.WindowFromPoint((pos.x(), pos.y())) print('x,y', pos.x(), pos.y()) print(*win32gui.GetWindowRect(hwnd)) # self.frameWidget.setRect(*win32gui.GetWindowRect(hwnd)) # 截图 screen = QApplication.primaryScreen() # 获取主显示屏对象(QScreen对象) if screen is not None: image = screen.grabWindow(0, pos.x() - 60, pos.y() - 60, 120, 120) if not image.isNull(): self.EnlargeImg.setPixmap(image.scaled(240, 240)) # self.EnlargeImg.update() def mouseReleaseEvent(self, mouseEvent): self.__IsEmpty = False # 画板不再为空 # def leaveEvent(self, event): # # super(Label, self).leaveEvent(event) # # 得到鼠标在屏幕中的位置 # print('鼠标离开') # print(event) # pos = QCursor.pos() # print(pos) # hwnd = win32gui.WindowFromPoint((pos.x(), pos.y())) # print('x,y', pos.x(), pos.y()) # print(*win32gui.GetWindowRect(hwnd)) # # self.frameWidget.setRect(*win32gui.GetWindowRect(hwnd)) # # 截图 # screen = QApplication.primaryScreen() # 获取主显示屏对象(QScreen对象) # if screen is not None: # image = screen.grabWindow(0, pos.x() - 60, pos.y() - 60, 120, 120) # if not image.isNull(): # self.EnlargeImg.setPixmap(image.scaled(240, 240)) # # self.EnlargeImg.update() def on_PenColorChange(self): color_index = self.__comboBox_penColor.currentIndex() color_str = self.__colorList[color_index] self.__paintBoard.ChangePenColor(color_str) def on_PenThicknessChange(self): penThickness = self.__spinBox_penThickness.value() self.__paintBoard.ChangePenThickness(penThickness) def on_btn_Save_Clicked(self): # savePath = QFileDialog.getSaveFileName(self, 'Save Your Paint', '.\\', '*.png') # print(savePath) curImg = self.imglist[self.CurImId] ImgName = os.path.split(curImg)[-1] savePath = os.path.join(r'C:\Users\49942\Pictures', ImgName) print('保存') print(savePath) if savePath == "": print("Save cancel") return image = self.__board.toImage() image.save(savePath) def on_cbtn_Eraser_clicked(self): if self.__cbtn_Eraser.isChecked(): self.__paintBoard.EraserMode = True # 进入橡皮擦模式 else: self.__paintBoard.EraserMode = False # 退出橡皮擦模式 def Quit(self): self.close()
class PaintBoard(QWidget): def __init__(self, Parent=None): ''' Constructor ''' super().__init__(Parent) self.__InitData() # 先初始化数据,再初始化界面 self.__InitView() def __InitData(self): self.__size = QSize(480, 460) # 新建QPixmap作为画板,尺寸为__size self.__board = QPixmap(self.__size) self.__board.fill(Qt.white) # 用白色填充画板 self.__IsEmpty = True # 默认为空画板 self.EraserMode = False # 默认为禁用橡皮擦模式 self.__lastPos = QPoint(0, 0) # 上一次鼠标位置 self.__currentPos = QPoint(0, 0) # 当前的鼠标位置 self.__painter = QPainter() # 新建绘图工具 self.__thickness = 10 # 默认画笔粗细为10px self.__penColor = QColor("black") # 设置默认画笔颜色为黑色 self.__colorList = QColor.colorNames() # 获取颜色列表 def __InitView(self): # 设置界面的尺寸为__size self.setFixedSize(self.__size) def Clear(self): # 清空画板 self.__board.fill(Qt.white) self.update() self.__IsEmpty = True def ChangePenColor(self, color="black"): # 改变画笔颜色 self.__penColor = QColor(color) def ChangePenThickness(self, thickness=10): # 改变画笔粗细 self.__thickness = thickness def IsEmpty(self): # 返回画板是否为空 return self.__IsEmpty def GetContentAsQImage(self): # 获取画板内容(返回QImage) image = self.__board.toImage() return image def paintEvent(self, paintEvent): # 绘图事件 # 绘图时必须使用QPainter的实例,此处为__painter # 绘图在begin()函数与end()函数间进行 # begin(param)的参数要指定绘图设备,即把图画在哪里 # drawPixmap用于绘制QPixmap类型的对象 self.__painter.begin(self) # 0,0为绘图的左上角起点的坐标,__board即要绘制的图 self.__painter.drawPixmap(0, 0, self.__board) self.__painter.end() def mousePressEvent(self, mouseEvent): # 鼠标按下时,获取鼠标的当前位置保存为上一次位置 self.__currentPos = mouseEvent.pos() self.__lastPos = self.__currentPos def mouseMoveEvent(self, mouseEvent): # 鼠标移动时,更新当前位置,并在上一个位置和当前位置间画线 self.__currentPos = mouseEvent.pos() self.__painter.begin(self.__board) if self.EraserMode == False: # 非橡皮擦模式 self.__painter.setPen(QPen(self.__penColor, self.__thickness)) # 设置画笔颜色,粗细 else: # 橡皮擦模式下画笔为纯白色,粗细为10 self.__painter.setPen(QPen(Qt.white, 10)) # 画线 self.__painter.drawLine(self.__lastPos, self.__currentPos) self.__painter.end() self.__lastPos = self.__currentPos self.update() # 更新显示 def mouseReleaseEvent(self, mouseEvent): self.__IsEmpty = False # 画板不再为空
class PaintBoard(QLabel): signal_right_mouse = pyqtSignal(int) signal_draw = pyqtSignal() def __init__(self, parent=None): super().__init__(parent) self.__parent = parent self.__board = QPixmap(QSize(440, 440)) self.__board.fill(Qt.transparent) self.__board_old = self.__board.copy() self.__board_old_old = self.__board.copy() self.__board_before_dots = self.__board.copy() self.__thickness = 10 # 默认画笔粗细为10px self.__penColor = QColor(0, 0, 0, 128) self.__painter = QPainter() self.__pen = QPen(self.__penColor, self.__thickness) self.__pen_seg = QPen(QColor(0, 0, 0, 128)) self.__brush = QBrush(QColor(0, 0, 0, 128)) self.__pen.setCapStyle(Qt.RoundCap) #self.__painter.setPen(self.__pen) self.__lastPos = QPoint(0, 0) # 上一次鼠标位置 self.__currentPos = QPoint(0, 0) # 当前的鼠标位置 self.__points = [] # dots模式的点集 self.__mouse_pressed = False self.__can_undo = False self.__has_seg = False self.__mode = 1 self.__ERASE = 0 self.__LINE = 1 self.__RECT = 2 self.__CIRCLE = 3 self.__DOTS = 4 self.__transparent = False self.__trans_board = self.__board.copy() self.__trans_board.fill(Qt.transparent) @staticmethod def dist(p1, p2): return math.hypot(p1.x() - p2.x(), p1.y() - p2.y()) # Each time paintEvent is called it clean the space where it is going to draw. # So it does not save memory of the previous drawings, # A simple solution is to first paint a QPixmap to store what you have painted. # And then paint the widget with that QPixmap. def set_trans(self, trans): self.__transparent = trans self.update() def is_trans(self): return self.__transparent def paintEvent(self, paint_event): # 把board绘制到界面上 self.__painter.begin(self) if not self.__transparent: self.__painter.drawPixmap(0, 0, self.__board) else: self.__painter.drawPixmap(0, 0, self.__trans_board) #结果图关闭mask self.__painter.end() def mousePressEvent(self, mouse_event): if mouse_event.button() == Qt.LeftButton: self.__mouse_pressed = True self.__board_old_old = self.__board_old.copy() self.__board_old = self.__board.copy() self.__currentPos = mouse_event.pos() self.__lastPos = self.__currentPos if self.__mode == self.__DOTS: if len(self.__points) == 0: self.__board_before_dots = self.__board.copy() self.__parent.childAt(740, 0).setEnabled(False) self.__parent.childAt(840, 0).setEnabled(False) self.__parent.childAt(370, 0).setEnabled(False) self.__parent.childAt(300, 610).setEnabled(False) if len(self.__points) > 0: print( self.dist( self.__points[0], QPoint(self.__currentPos.x(), self.__currentPos.y()))) if len(self.__points) > 2 and \ self.dist(self.__points[0], QPoint(self.__currentPos.x(), self.__currentPos.y())) < 5: self.__board = self.__board_before_dots.copy() self.__painter.begin(self.__board) if self.__ERASE: self.__painter.setCompositionMode( QPainter.CompositionMode_Clear) else: self.__painter.setCompositionMode( QPainter.CompositionMode_Source) self.__painter.setPen(Qt.NoPen) self.__painter.setBrush(self.__brush) self.__painter.drawPolygon(QPolygon(self.__points)) self.signal_draw.emit() self.__painter.end() self.__points.clear() self.__parent.childAt(740, 0).setEnabled(True) self.__parent.childAt(840, 0).setEnabled(True) self.__parent.childAt(370, 0).setEnabled(True) self.__parent.childAt(300, 610).setEnabled(True) self.update() else: self.__points.append( QPoint(self.__currentPos.x(), self.__currentPos.y())) if not (self.__mode == self.__DOTS and len(self.__points) == 1): self.__can_undo = True self.__parent.childAt(70, 610).setEnabled(True) else: self.__can_undo = False self.__parent.childAt(70, 610).setEnabled(False) def mouseMoveEvent(self, mouse_event): # 把线绘制到board上 self.__currentPos = mouse_event.pos() if self.__mode != self.__LINE: if len(self.__points) > 0: self.__board = self.__board_old.copy() elif not self.__mode == self.__DOTS: if self.__mouse_pressed: self.__board = self.__board_old.copy() self.__painter.begin(self.__board) self.__painter.setPen(self.__pen) if self.__ERASE: self.__painter.setCompositionMode(QPainter.CompositionMode_Clear) else: self.__painter.setCompositionMode(QPainter.CompositionMode_Source) if self.__mode == self.__LINE: if self.__mouse_pressed: self.__painter.drawLine(self.__lastPos, self.__currentPos) self.signal_draw.emit() elif self.__mode == self.__RECT: self.__painter.setPen(Qt.NoPen) self.__painter.setBrush(self.__brush) if self.__mouse_pressed: self.__painter.drawRect( self.__lastPos.x(), self.__lastPos.y(), (self.__currentPos.x() - self.__lastPos.x()), (self.__currentPos.y() - self.__lastPos.y())) self.signal_draw.emit() elif self.__mode == self.__CIRCLE: self.__painter.setPen(Qt.NoPen) self.__painter.setBrush(self.__brush) if self.__mouse_pressed: self.__painter.drawEllipse( self.__lastPos.x(), self.__lastPos.y(), (self.__currentPos.x() - self.__lastPos.x()), (self.__currentPos.y() - self.__lastPos.y())) self.signal_draw.emit() elif self.__mode == self.__DOTS: if len(self.__points) > 0: self.__painter.setCompositionMode( QPainter.CompositionMode_Source) self.__painter.setPen(QPen(self.__pen_seg.color(), 1)) self.__painter.drawLine(self.__points[-1], self.__currentPos) self.signal_draw.emit() self.__painter.end() if self.__mode == self.__LINE: self.__lastPos = self.__currentPos self.update() # 触发paintEvent def mouseDoubleClickEvent(self, mouse_event): if mouse_event.button() == Qt.LeftButton: if not self.__mode == self.__DOTS: if self.__has_seg: x = mouse_event.pos().x() y = mouse_event.pos().y() value = self.segment[y][x] # 注意这里x和y要反过来 self.__painter.begin(self.__board) self.paint_segment(value, x, y) self.__painter.end() self.signal_draw.emit() self.update() # 触发paintEvent def mouseReleaseEvent(self, mouse_event): if mouse_event.button() == Qt.LeftButton: self.__mouse_pressed = False if mouse_event.button() == Qt.RightButton: self.signal_right_mouse.emit(1 - self.__ERASE) return def undo(self): if self.__can_undo: if self.__mode != self.__DOTS: self.__board = self.__board_old.copy() else: if len(self.__points) == 0: self.__board = self.__board_before_dots.copy() else: self.__points.pop() self.__board = self.__board_old_old.copy() self.__board_old = self.__board_old_old.copy() self.signal_draw.emit() self.update() self.__can_undo = False self.__parent.childAt(70, 610).setEnabled(False) def update_segment(self, seg): self.segment = seg self.__parent.childAt(1040, 0).setEnabled(False) self.__has_seg = True def set_board(self, x, y): self.__board = self.__board.scaled(x, y) def update_board(self, board): self.__board = board self.update() def paint_segment(self, value, x, y): has_painted = np.zeros(self.segment.shape, dtype=np.uint8) point_stack = [(x, y)] while len(point_stack) > 0: point = point_stack.pop() x = point[0] y = point[1] self.__painter.setPen(self.__pen_seg) if self.__ERASE: self.__painter.setCompositionMode( QPainter.CompositionMode_Clear) else: self.__painter.setCompositionMode( QPainter.CompositionMode_Source) self.__painter.drawPoint(x, y) has_painted[y][x] = 1 if x + 1 < self.segment.shape[1] and has_painted[y][ x + 1] == 0 and value == self.segment[y][x + 1]: point_stack.append((x + 1, y)) if x - 1 >= 0 and has_painted[y][ x - 1] == 0 and value == self.segment[y][x - 1]: point_stack.append((x - 1, y)) if y + 1 < self.segment.shape[0] and has_painted[ y + 1][x] == 0 and value == self.segment[y + 1][x]: point_stack.append((x, y + 1)) if y - 1 >= 0 and has_painted[ y - 1][x] == 0 and value == self.segment[y - 1][x]: point_stack.append((x, y - 1)) def Thanos(self, label): if len(label) == 0: return False image = self.__board.copy() image.fill(Qt.transparent) pixels = image.toImage() s = pixels.bits().asstring(pixels.width() * pixels.height() * 4) arr = np.fromstring(s, dtype=np.uint8).reshape( (pixels.height(), pixels.width(), 4)) np.set_printoptions(threshold=sys.maxsize) mask = arr[..., 3] for l in label: mask[self.segment == l] = 255 expand_mask(mask, 5) #Image.fromarray(np.uint8(mask)).save('mask_10.jpg') return mask def set_seg(self): self.__has_seg = False def set_pen(self, value): self.__pen.setWidth(value) def pen_black(self): self.__pen.setColor(QColor(0, 0, 0, 128)) def pen_white(self): self.__pen.setColor(QColor(255, 255, 255, 128)) def geo_black(self): self.__pen_seg.setColor(QColor(0, 0, 0, 128)) self.__brush = QBrush(QColor(0, 0, 0, 128)) def geo_white(self): self.__pen_seg.setColor(QColor(255, 255, 255, 128)) self.__brush = QBrush(QColor(255, 255, 255, 128)) def switch_mode(self): self.__ERASE = 1 - self.__ERASE def set_mode(self, mode): self.__ERASE = mode def tool_pen(self): self.__mode = self.__LINE def tool_rect(self): self.__mode = self.__RECT def tool_circle(self): self.__mode = self.__CIRCLE def tool_dots(self): self.__mode = self.__DOTS def clear_board(self): self.__board.fill(Qt.transparent) self.__board_old = self.__board.copy() self.__board_before_dots = self.__board.copy() self.__board_old_old = self.__board.copy() self.__parent.childAt(70, 610).setEnabled(False) self.signal_draw.emit() self.update() def save(self): # save_path = QFileDialog.getSaveFileName(self, 'Save Your Paint', '.\\', '*.jpg') save_path = 'D:/test.png', '*.png' print(save_path) if save_path[0] == "": print("Save cancel") return image = self.__board pixels = image.toImage() s = pixels.bits().asstring(pixels.width() * pixels.height() * 4) arr = np.fromstring(s, dtype=np.uint8).reshape( (pixels.height(), pixels.width(), 4)) np.set_printoptions(threshold=sys.maxsize) mask = arr[..., 3] print(mask) # qimage2numpy(pixels) # Pixels can only be accessed through QPainter functions or by converting the QPixmap to a QImage. image.save(save_path[0]) def get_mask(self): image = self.__board pixels = image.toImage() s = pixels.bits().asstring(pixels.width() * pixels.height() * 4) arr = np.fromstring(s, dtype=np.uint8).reshape( (pixels.height(), pixels.width(), 4)) np.set_printoptions(threshold=sys.maxsize) mask = arr[..., 3] # 取alpha通道,就是不透明度 mask[mask > 0] = 255 return mask def get_board(self): return self.__board.copy() def test(self): # self.pix = QPixmap("road.jpg") self.__painter.begin(self.__board) for i in range(301): for j in range(301): self.__painter.drawPoint(i, j) self.__painter.end() self.update()