【标注工具】labelme5.0.1自定义功能——添加水平线标注及显示信息

一、背景

随着项目的逐步开展,数据标注的工作量越来越大,为了提高标注效率和标注准确性,需要对labelme的功能进行扩充,更好地适应标注需求,同时后期也能将数据标注工作顺利交付出去。

本次标注需要一个rectangle,一条水平line,一个point,并计算三者之间的相对位置关系,将计算结果显示到界面上,有助于精细化调整,因此需要添加水平线标注及显示信息两个功能。

二、具体工作

1. 添加水平线HLine标注

全局搜索“line”,仿照“line”的生成方式添加“hline”。需要修改的文件内容如下:

(1)utils/shape.py

Line36 后面添加代码

# 新增shape_type
elif shape_type == "hline":
    assert len(xy) == 2, "Shape of shape_type=hline must have 2 points"
    draw.line(xy=xy, fill=1, width=line_width)
(2)utils/canvas.py

Line103 createMode()中添加代码

def createMode(self, value):
        if value not in [
            "polygon",
            "rectangle",
            "circle",
            "line",
            "hline",    # 添加hline类型
            "point",
            "linestrip",
        ]:

 Line236 后面添加代码段

# 添加水平线标注方法
elif self.createMode == "hline":
    pos2 = pos
    pos2.setY(self.current[0].y())    #将第二个点的y坐标替换为第一个点的y坐标
    self.line.points = [self.current[0], pos2]
    self.line.close()

 Line362 mousePressEvent()中添加

elif self.createMode in ["rectangle", "circle", "line", "hline"]:    # 添加hline
    assert len(self.current.points) == 1
    self.current.points = self.line.points

Line837 undoLastLine()中添加

elif self.createMode in ["rectangle", "line", "circle", "hline"]:
    self.current.points = self.current.points[0:1]
(3)app.py

 Line351 后面添加代码段

# 创建水平线方法
createHLineMode = action(
    self.tr("Create HLine"),
    lambda: self.toggleDrawMode(False, createMode="hline"),
    shortcuts["create_hline"],
    "objects",
    self.tr("Start drawing hlines"),
    enabled=False,
)

Line601 后添加代码

createHLineMode=createHLineMode

 Line635、653 后添加代码

createHLineMode

Line850 后添加代码

self.actions.createHLineMode

Line881、958、966、973、980、987、994、1001后添加代码

self.actions.createLineMode.setEnabled(True)

Line982 后添加代码段

elif createMode == "hline":
    self.actions.createMode.setEnabled(True)
    self.actions.createRectangleMode.setEnabled(True)
    self.actions.createCircleMode.setEnabled(True)
    self.actions.createLineMode.setEnabled(True)
    self.actions.createHLineMode.setEnabled(False)
    self.actions.createPointMode.setEnabled(True)
    self.actions.createLineStripMode.setEnabled(True)
(4)shape.py

Line93 后面添加

if value not in [
    "polygon",
    "rectangle",
    "point",
    "line",
    "hline",    # 添加hline
    "circle",
    "linestrip",
]:

2. 添加信息显示

本次标注需要将点与线段间的距离值显示到标注界面上,随着点的移动实时更新距离值,主要修改canvas.py,创建rectangle、hline和point后提取相应点的y坐标,在编辑形状的过程中,移动point的位置后更新y坐标,计算新的距离值。

(1)坐标值记录

创建变量记录坐标值,class canvas()__init__()

self.bottom_y = 0    # rectangle(x1,y1,x2,y2)的y2
self.top_y = 0    # hline(x1,y,x,2y)的y
self.move_p_y = 0    # point(x,y)的y
self.ht = 0.        # 距离值
self.ht_tag = False    # 是否开始计算距离值

创建rectangle后记录其y_2的值

elif self.createMode == "rectangle":
    self.line.points = [self.current[0], pos]
    self.bottom_y = pos.y()    # 记录y2
    self.line.close()

创建hline后记录其y

elif self.createMode == "hline":
    pos2 = pos
    pos2.setY(self.current[0].y())
    self.line.points = [self.current[0], pos2]
    self.top_y = self.current[0].y()    # 记录y
    self.line.close()

创建point后记录其y

elif self.createMode == "point":
    self.line.points = [self.current[0]]
    self.move_p_y = self.current[0].y()    # 记录y
    self.ht = min(1., max(0., (self.bottom_y - self.move_p_y)) / (self.bottom_y -self.top_y))    # 计算距离值
    self.ht_tag = True    # 完成point标注,可以显示
    self.line.close()
(2)坐标更新

在鼠标点击坐标点或编辑形状时,也要实时记录,mousePressEvent()

if ev.button() == QtCore.Qt.LeftButton:
    if self.drawing():
        if self.current:
            # Add point to existing shape.
            if self.createMode == "polygon":
                self.current.addPoint(self.line[1])
                self.line[0] = self.current[-1]
                if self.current.isClosed():
                    self.finalise()
            elif self.createMode in ["rectangle", "circle", "line", "hline"]:
                assert len(self.current.points) == 1
                self.current.points = self.line.points
                if self.createMode == "rectangle":
                    self.bottom_y = self.current.points[1].y()    # 记录rec y2
                elif self.createMode == "hline":
                    self.top_y = self.current.points[0].y()    # 记录hline y
                self.finalise()
            elif self.createMode == "linestrip":
                self.current.addPoint(self.line[1])
                self.line[0] = self.current[-1]
                if int(ev.modifiers()) == QtCore.Qt.ControlModifier:
                    self.finalise()
        elif not self.outOfPixmap(pos):
            # Create new shape.
            self.current = Shape(shape_type=self.createMode)
            self.current.addPoint(pos)
            if self.createMode == "point":
                self.move_p_y = self.current.points[0].y()    # 记录point y
                self.ht = min(1., max(0., (self.bottom_y - self.move_p_y)) / (self.bottom_y - self.top_y))    # 更新距离值
                self.ht_tag = True
                self.finalise()
            else:
                if self.createMode == "circle":
                    self.current.shape_type = "circle"
                self.line.points = [pos, pos]
                self.setHiding()
                self.drawingPolygon.emit(True)
                self.update()
    elif self.editing():
        if self.selectedEdge():
            self.addPointToEdge()
        elif (
            self.selectedVertex()
            and int(ev.modifiers()) == QtCore.Qt.ShiftModifier
        ):
            # Delete point if: left-click + SHIFT on a point
            self.removeSelectedPoint()

        group_mode = int(ev.modifiers()) == QtCore.Qt.ControlModifier
        self.selectShapePoint(pos, multiple_selection_mode=group_mode)
        self.prevPoint = pos
        # 编辑形状时,根据调整的point的位置更新距离值
        if self.createMode == 'point':
            self.move_p_y = int(pos.y())
            self.ht = min(1., max(0., (self.bottom_y - self.move_p_y)) / (self.bottom_y - self.top_y))
            self.ht_tag = True

        self.repaint()

更新坐标,mouseReleaseEvent()

(2024-08-13修改,修复删除水平线时报错问题)

if self.movingShape and self.hShape:
    index = self.shapes.index(self.hShape)
    if (
        self.shapesBackups[-1][index].points
        != self.shapes[index].points
    ):
        if self.hShape.shape_type == 'rectangle':
            self.bottom_y = self.shapes[index].points[1].y()
        if self.hShape.shape_type == 'hline':
            # 修改,删除点时不更新坐标
            if len(self.shapes[index].points) > 1:
                self.shapes[index].points[1].setY(self.shapesBackups[-1][index].points[0].y())
            self.top_y = self.shapes[index].points[0].y()
        if self.hShape.shape_type == 'point':
            self.move_p_y = self.shapes[index].points[0].y()
            self.ht = min(1., max(0., (self.bottom_y - self.move_p_y)) / (self.bottom_y - self.top_y))
            self.ht_tag = True
        self.storeShapes()
        self.shapeMoved.emit()

    self.movingShape = False
(3)界面绘制

主要参考[1]

for shape in self.shapes:
    if (shape.selected or not self._hideBackround) and self.isVisible(
        shape
    ):
        shape.fill = shape.selected or shape == self.hShape
        shape.paint(p)
        p.setPen(QColor(0 ,255, 0))
        p.setFont(QFont('微软雅黑', 20))
        if self.ht_tag:
            labelText = f'当前料位高度:{self.ht}'
            p.drawText(QPointF(10, 40), labelText)

3. 其他改动

参考[2]设置默认自动保存,不存储imageData,节省存储空间。

最终效果见图(展示用图,并非实际标注图)

 

总结

经过修改,可以节省一部分标注时间,同时能进行更加精细化的标注调整,也有助于标注工作的交付。(不想再兼职数据标注员了

第一次写技术博客,纯属学习记录,大佬勿喷

  • 27
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值