1、箭头标注
可以采用labelme标注工具标注,我在windows下使用如下链接
Windows环境使用Lableme - LiWeixiao - 博客园 (cnblogs.com)
- 标注格式:3点折线
- 类型:arrowPoint
- 标注细则
- )箭头的三个点全部可见且清晰
- )Labelme打开后,鼠标右键选中Create LineStrip先标箭头的顶点,然后逆时针标另外两个点(三个点不用闭合),存储类别为arrowPoint。
- )有一个及以上点被遮挡或看不见,其余点按单点标注,Labelme打开后,鼠标右键选中Create Point ,标注单点类别为singleArrowPoint。
2、labelme格式的json文件转voc格式的xml文件
把labeme标注的json格式的文件写个脚本,分别生成:
1、箭头的最小外接矩形框(箭头的三个顶点),下图arrowRect类别矩形框
2、箭头三个顶点的外接矩形框(以箭头顶点为中心),下图arrowPointRect类别矩形框
下图为labeme标注的箭头
下图为上图json文件生成的 矩形框,箭头外接矩形框(arrowRect),三个箭头顶点矩形框(以箭头顶点为中心生成固定长度的正方形框arrowPointRect)
脚本代码如下:配置好json文件夹路径,和xml文件夹路径运行即可生成json文件对应的xml文件
import os
import xml.etree.ElementTree as ET
from xml.etree.ElementTree import ElementTree,Element
from lxml import etree, objectify
import numpy as np
import json
json_path = r'C:\Users\Desktop\park\arrow\jsons/' #json文件的路径
annotations_path = r'C:\Users\Desktop\park\arrow\xml/' #生成的xml文件需要保存的路径
class_names = ("singleArrowPoint", "arrowPoint")
def write_xml(imgname,filepath,labeldicts,width,height): #参数imagename是图片名(无后缀)
annotation = etree.Element('annotation') #创建Annotation根节点
etree.SubElement(annotation, "folder").text = "labels"
etree.SubElement(annotation, 'filename').text = str(imgname)+".xml" #创建filename子节点(无后缀)
etree.SubElement(annotation, "path").text = filepath[:-3]+"jpg"
source = etree.SubElement(annotation, "source")
etree.SubElement(source, "database").text = "Unknown"
size = etree.SubElement(annotation,'size') #创建size子节点
etree.SubElement(size, 'width').text = str(width) #没带脑子直接写了原图片的尺寸......
etree.SubElement(size, 'height').text = str(height)
etree.SubElement(size, 'depth').text = '3' #图片的通道数:img.shape[2]
etree.SubElement(annotation, "segmented").text = '0'
for labeldict in labeldicts:
objects = etree.SubElement(annotation, 'object') #创建object子节点
etree.SubElement(objects, 'name').text = labeldict['name'] #BDD100K_10.names文件中
#的类别名
etree.SubElement(objects, 'pose').text = 'Unspecified'
etree.SubElement(objects, 'truncated').text = '0'
etree.SubElement(objects, 'difficult').text = '0'
bndbox = etree.SubElement(objects,'bndbox')
etree.SubElement(bndbox, 'xmin').text = str(int(labeldict['xmin']))
etree.SubElement(bndbox, 'ymin').text = str(int(labeldict['ymin']))
etree.SubElement(bndbox, 'xmax').text = str(int(labeldict['xmax']))
etree.SubElement(bndbox, 'ymax').text = str(int(labeldict['ymax']))
tree = etree.ElementTree(annotation)
tree.write(filepath, pretty_print=True)
def boundaryJudge(xmin,ymin,xmax,ymax,imgW,imgH):
if xmin < 0:
xmax = xmax + xmin
xmin = 0
if ymin < 0:
ymax = ymax + ymin
ymin = 0
if xmax > imgW - 1:
xmin = xmin + xmax - imgW
xmax = imgW - 1
if ymax > imgH - 1:
ymin = ymin + ymax - imgH
ymax = imgH - 1
return xmin,ymin,xmax,ymax
def generateRect(labeldicts, point, rectW,rectName):
xmin = round(point[0]) - rectW
ymin = round(point[1]) - rectW
xmax = round(point[0]) + rectW
ymax = round(point[1]) + rectW
minx, miny, maxx, maxy = boundaryJudge(xmin, ymin, xmax, ymax, imgW, imgH)
new_dict = {'name': rectName,
'difficult': '0',
'xmin': minx,
'ymin': miny,
'xmax': maxx,
'ymax': maxy
}
labeldicts.append(new_dict)
if __name__ == '__main__':
imgW = 480
imgH = 480
rectW = 8 #箭头顶点生成矩形框的宽度
listJson = os.listdir(json_path)
for i in range(0, len(listJson)):
print(i)
path = os.path.join(json_path, listJson[i])
if os.path.isfile(path):
data = json.load(open(path, 'r'))
labeldicts = []
for lineLabel in data["shapes"]:
class_name = lineLabel["label"].strip()
lineName = ""
if class_name == "arrowPoint" and len(lineLabel["points"]) == 3:
ap0 = lineLabel["points"][0]
ap1 = lineLabel["points"][1]
ap2 = lineLabel["points"][2]
xmin = min(ap0[0], ap1[0], ap2[0])
xmax = max(ap0[0], ap1[0], ap2[0])
ymin = min(ap0[1], ap1[1], ap2[1])
ymax = max(ap0[1], ap1[1], ap2[1])
xmin = xmin - 1
ymin = ymin - 1
xmax = xmax + 1
ymax = ymax + 1
minx, miny, maxx, maxy = boundaryJudge(xmin, ymin, xmax, ymax, imgW, imgH)
if maxx - minx > 5 and maxy - miny > 5:
new_dict = {'name': "arrowRect",
'difficult': '0',
'xmin': minx,
'ymin': miny,
'xmax': maxx,
'ymax': maxy
}
labeldicts.append(new_dict)
# --------------------------------------single point----------start
generateRect(labeldicts, ap0, rectW, "arrowPointRect")
generateRect(labeldicts, ap1, rectW, "arrowPointRect")
generateRect(labeldicts, ap2, rectW, "arrowPointRect")
# --------------------------------------single point----------end
write_xml(listJson[i].strip('.json'), annotations_path + listJson[i].strip('.json')+ '.xml', labeldicts,imgW,imgH)
3、目标检测训练
随便找个目标检测模型训练即可,推荐使用yolov5,链接如下
github.comhttps://github.com/ultralytics/yolov5目标检测模型输出的结果如下:
通过后处理操作,取箭头顶点矩形框的中心,则得到如下结果
再通过一系列后处理操作(1、判断红色顶点是否属于箭头(蓝色矩形框),2找到属于矩形框的三个红点,3、三个端点两两生成三条直线,判断这三条直线的长度及角度),既可得到箭头的方向向量(如下图红色直线,方向顶点用圆点表示)
下一篇分享地面减速带检测方法