图片标记-图像标注版本3-多标注框+标注标签
这个图像标注版本在前面多标注框基础上图片标记,增加了标注标签的选择,同时修正了一下之前绘制最后一个标注框的显示问题,现在看起来更像一个标注软件了。
参照labelImg的样式定义了一个自定义Dialog窗口,在这个窗口中加载了标注标签列表文件,同时这个标签是要必须选择的,或者取消。
对多标注框的代码重新做了优化图片标记,一个是关于正在绘制的标注框的显示问题,如果标签取消,则不予绘制,如果选择了标签才绘制出来
一、通过qt designer设计一个标签选择的自定义Dialog窗口
# -*- coding: utf-8 -*-# Form implementation generated from reading ui file 'ui_labelchoose.ui'## Created by: PyQt5 UI code generator 5.15.4## WARNING: Any manual changes made to this file will be lost when pyuic5 is# run again. Do not edit this file unless you know what you are doing.from PyQt5 import QtCore, QtGui, QtWidgetsclass Ui_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName("Dialog") Dialog.resize(285, 336) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(Dialog.sizePolicy().hasHeightForWidth()) Dialog.setSizePolicy(sizePolicy) Dialog.setMinimumSize(QtCore.QSize(285, 336)) Dialog.setMaximumSize(QtCore.QSize(285, 336)) self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) self.buttonBox.setGeometry(QtCore.QRect(80, 39, 193, 28)) self.buttonBox.setOrientation(QtCore.Qt.Horizontal) self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) self.buttonBox.setObjectName("buttonBox") self.leditChoosedLabel = QtWidgets.QLineEdit(Dialog) self.leditChoosedLabel.setGeometry(QtCore.QRect(11, 11, 261, 21)) self.leditChoosedLabel.setObjectName("leditChoosedLabel") self.leditChoosedLabel.setEnabled(False) self.lviewLabelList = QtWidgets.QListView(Dialog) self.lviewLabelList.setGeometry(QtCore.QRect(10, 80, 261, 241)) self.lviewLabelList.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) self.lviewLabelList.setObjectName("lviewLabelList") self.retranslateUi(Dialog) QtCore.QMetaObject.conn【88 个靠.谱项.目】ectSlotsByName(Dialog) def retranslateUi(self, Dialog): _translate = QtCore.QCoreApplication.translate Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
二、实现自定义Dialog的相关功能
一个是初始化过程中对标签列表文件的加载
一个是QListView的点击事件
一个是Dialog的返回值
最后一个是对OK按钮事件的校验,确保已经选择了标签
from PyQt5 import QtCore, QtGui, QtWidgetsfrom PyQt5.QtWidgets import QMainWindow, QApplication, QDialog,QMessageBoxfrom PyQt5.QtCore import QStringListModelclass DialogChoooseLabelWin(QDialog, Ui_Dialog): def __init__(self,parent=None): # super(DialogChoooseLabelWin, self).__init__() QDialog.__init__(self,parent) self.setupUi(self) self.labelList=[] self.initLableList() self.lviewLabelList.clicked.connect(self.clickedlist) self.buttonBox.accepted.connect(self.validate) self.buttonBox.rejected.connect(self.reject) def initLableList(self): with open('datalabellistbak.txt', 'r',encoding='utf-8') as f: self.labelList=[line.strip() for line in f] self.labelslm=QStringListModel() self.labelslm.setStringList(self.labelList) self.lviewLabelList.setModel(self.labelslm) def clicked【88 个靠.谱.项.目】list(self, qModelIndex): self.leditChoosedLabel.setText(self.labelList[qModelIndex.row()]) def getValue(self): return self.leditChoosedLabel.text() def validate(self): if self.leditChoosedLabel.text()!='': self.accept()if __name__ == "__main__": import sys app = QtWidgets.QApplication(sys.argv) Dialog=DialogChoooseLabelWin() print('dialogChooseLabel.exec_()=', Dialog.exec_()) print('dialogChooseLabel.getValue()=', Dialog.getValue()) sys.exit(app.exec_())
三、对原来的MyLabel进行重写,参见加粗字体部分
引入了一个实时坐标的概念
在鼠标移动事件中,不断根据鼠标位置进行实时绘制
在鼠标释放事件中,增加了一个对话框选择项,确认后将相关标注项加入到bboxlist中(bboxlist相对于2.0版本有所调整)
在绘制事件中,修正了对实时标注框的单独绘制
from PyQt5.QtWidgets import QWidget, QApplication, QLabelfrom PyQt5.QtCore import QRect, Qtfrom PyQt5.QtGui import QPixmap, QPainter, QPenfrom ui_labelchoose import DialogChoooseLabelWinimport sys# 重定义QLabel,实现绘制事件和各类鼠标事件class MyLabel(QLabel): def __init__(self, parent=None): ''' :param parent: 初始化基本参数 ''' super(MyLabel, self).__init__(parent) self.x0 = 0 self.y0 = 0 self.x1 = 0 self.y1 = 0 self.x1RealTime = 0 self.y1RealTime = 0 self.rect = QRect() self.flag = False # 增加一个存储标注框坐标的列表 self.bboxList=[] # 单击鼠标触发事件 # 获取鼠标事件的开始位置 def mousePressEvent(self, event): # 将绘制标志设置为True self.flag = True self.x0 = event.pos().x() self.y0 = event.pos().y() # 鼠标移动事件 # 绘制鼠标行进过程中的矩形框 def mouseMoveEvent(self, event): if self.flag: self.x1RealTime = event.pos().x() self.y1RealTime = event.pos().y() self.update() # 鼠标释放事件 def mouseReleaseEvent(self, event): # 将绘制标志设置为False self.flag = False self.x1 = event.pos().x() self.y1 = event.pos().y() self.x1RealTime = self.x0 self.y1RealTime = self.y0 # 这样就不用画出实时框了 # 将标注框的四个坐标轴存储到bboxList dialogChooseLabel = DialogChoooseLabelWin() if dialogChooseLabel.exec_(): labelname = dialogChooseLabel.getValue() self.saveBBbox(self.x0, self.y0, self.x1, self.y1, labelname) event.ignore() # 绘制事件 def paintEvent(self, event): super().paintEvent(event) painter = QPainter() # 增加绘制开始和结束时间 painter.begin(self) # 遍历之前存储的标注框坐标列表 for point in self.bboxList: rect = QRect(point[0], point[1], abs(point[0]-point[2]), abs(point[1]-point[3])) painter.setPen(QPen(Qt.red, 2, Qt.SolidLine)) painter.drawRect(rect) painter.drawText(point[0], point[1], point[4]) # 绘制当前标注框的举行 # 构造矩形框的起始坐标和宽度、高度 tempx0 = min(self.x0, self.x1RealTime) tempy0 = min(self.y0, self.y1RealTime) tempx1 = max(self.x0, self.x1RealTime) tempy1 = max(self.y0, self.y1RealTime) width=tempx1-tempx0 height=tempy1-tempy0 currect = QRect(tempx0, tempy0, width, height) # 构造QPainter,进行矩形框绘制 painter.setPen(QPen(Qt.blue, 1, Qt.SolidLine)) painter.drawRect(currect) painter.end() # 保存到bbox列表 def saveBBbox(self,x0,y0,x1,y1,labelname): tempx0 = min(x0, x1) tempy0 = min(y0, y1) tempx1 = max(x0, x1) tempy1 = max(y0, y1) bbox = (tempx0, tempy0, tempx1, tempy1,labelname) self.bboxList.append(bbox)
四、窗口类和main函数未做调整
# 窗口类class LabelV1(QWidget): def __init__(self): super(LabelV1, self).__init__() self.initUI() def initUI(self): self.resize(960, 540) self.move(100, 50) self.setWindowTitle('Label标注框3.0版本') # 加载重定义的label self.lbl = MyLabel(self) # 构造QPixmap,加载待标注图片 img = QPixmap('010.png') # 在自定义label中显示QImage self.lbl.setPixmap(img) self.lbl.setCursor(Qt.CrossCursor) self.show()if __name__ == '__main__': app = QApplication(sys.argv) labelwin = LabelV1() sys.exit(app.exec())
———END———
限 时 特 惠: 【资 ;源 之.家.】mxyxt .com 每日持.续更新.可.实操.的副.业.项目,【微-信 】 qgz mt1, 【点击查看详情】
站 长 微 信: qgzmt1