Roboflow 是一款易于使用的在线图像标注软件。当我需要标注数据集以进行对象检测时,我总是使用它。

对图像进行对象检测标注是指在图像上绘制和标注对象周围的边界框。

但是,当涉及到关键点的标注时,Roboflow 会显示以下消息:

目前,我们只支持对象检测(边界框)和单类分类项目。我们根据用户需求进行优先排序。您可以通过添加投票记录您的支持并请求此功能。

最近,我需要使用胶管对图像数据集进行关键点标注,以训练自定义关键点 RCNN。

以下是数据集中的几张随机图像:

每个图像的标注应包括:

  • 边界框坐标(每个胶管应该有一个边界框,用[x1, y1, x2, y2]格式即左上角和右下角点描述);
  • 关键点的坐标和可见性(每个胶管应该有 2 个关键点即头部和尾部[x, y, visibility] 格式描述)。

下面是标注后可视化的结果:

但我找不到在线工具来标注关键点。所以我想出了一个想法,如何通过使用可用的 Roboflow 功能和自定义 python 脚本来做到这一点。

下面是该过程的分步描述。

1.标注关键点和边界框

  • 1)在 https://roboflow.com 注册一个免费帐户,然后登录并单击Create New Project

  • 2)为您的项目命名,然后单击Create Public Project

  • 3.1)上传数据集

  • 3.2)上传后,系统会询问您希望以哪种比例(训练/有效/测试)分割这些图像:

  • 3.3)选择 100% / 0% / 0%(如果需要,您可以稍后手动分割图像)并单击Continue

  • 4.1)现在您将开始标注过程。点击第一张图片:

  • 4.2)单击第一张图片后,您将看到以下窗口:

  • 4.3)在左边的胶管周围画一个矩形并为其设置类名 Tube,按Enter

    您将看到新类Tube出现在左侧的注释栏中:

    在右胶管周围画一个矩形。现在你有两个边界框:

  • 4.4)在左胶管盖的中心画一个小矩形。这个矩形的中心将是胶管的第一个关键点。为它设置类名Head,按Enter

    你会看到一个新的类Head出现在左边的注释栏中:

    对右边的胶管盖做同样的事情。现在你有两个与头部关键点相关的矩形:

  • 4.5)在左胶管尾部的中心画一个小矩形。这个矩形的中心将是胶管的第二个关键点。为其设置类名 Tail,按Enter

    您会看到左侧的注释列中出现了一个新类 Tail

    对右边的胶管做同样的事情。现在您有两个与尾部关键点相关的矩形:

  • 4.6)重要的!要将与关键点相关的矩形转换为关键点,您需要使用我将在本文后面提供的自定义 python 脚本。仅当对象(在我们的例子中为胶管)的边界框仅包含与该特定对象相关的那些关键点时,此脚本才能正常工作。

例如,在下图中,左胶管的边界框不仅包含其自身的头尾关键点,还包含右胶管的尾部关键点。你应该避免这样的重叠:

在下图中,边界框部分重叠,但可以通过这样一种方式来绘制关键点,即每个包围框只包含与其胶管相关的头部和尾部关键点:

  • 5.1)现在,在标记完所有图像后,您需要下载数据集。单击左侧菜单中的Dataset链接:

  • 5.2)默认情况下,会添加 Auto-OrientResize 等预处理步骤。删除那些。此外,不要在下一步添加任何增强。
    点击Generate按钮:

  • 5.3)生成数据集后,您可以为其命名并导出它:

  • 5.4)在导出选项中选择YOLO v5 PyTorch格式和download zip to computer,然后单击Continue

  • 5.5)这次您不必在 Roboflow 中自己用胶管标注整个数据,我已经为您完成了!只需从此处下载并解压缩文件。

2.使用 python 脚本转换标注文件

在下载的文档中,您将看到文件 data.yaml 以及文件夹 train/imagestrain/labels

文件 data.yaml 包含以下类名列表:['Tube'、'Head'、'Tail']

train/images 文件夹中的每个图像在 train/labels 文件夹中都有一个对应的同名 txt 文件。

train/labels 文件夹中的 txt 文件具有以下结构(这里是一个示例):

2 0.7460938 0.3745370 0.0015625 0.0027778
0 0.6315104 0.4097222 0.2598958 0.1712963
1 0.5307292 0.4509259 0.0020833 0.0037037
1 0.4484375 0.4944444 0.0020833 0.0037037
0 0.3372396 0.5666667 0.2859375 0.2268519
2 0.2044271 0.6171296 0.0026042 0.0046296

txt 文件中的每一行对应于某个矩形,由五个数字组成。第一个数字是列表 ['Tube', 'Head', 'Tail'] 中矩形类的索引。其他四个数字是 x_center y_center width height 格式的矩形的归一化坐标。

例如,如果您需要将 x 坐标从归一化格式转换为绝对格式,则应将归一化 x 坐标乘以图像的宽度(以像素为单位)。

要获取关键点及其坐标,您需要转换这些行。如果第一个数字为0,则矩形坐标应转换为[x_top_left,y_top_left,x_bottom_right,y_bottom_right]格式的胶管边界框的绝对坐标。如果第一个数字是 1 或 2,则矩形应转换为 [x, y, visibility] 格式的关键点(头部或尾部)的绝对坐标。

  • 2.1) 在 Jupyter Notebook 中创建一个新笔记本。首先,您需要导入必要的模块:
import json
import os
import cv2
import matplotlib.pyplot as plt
  • 2.2) 让我们看看 /train/images 文件夹中的第一张图片:
file_image_example = '/path/to/dataset/train/images/IMG_4801_JPG_jpg.rf.004c63fe3ea1692644120c6040d32108.jpg'img = cv2.imread(file_image_example)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)plt.figure(figsize=(15,15))
plt.imshow(img)

  • 2.3) 现在让我们看看 /train/labels 文件夹中第一个 txt 文件的内容:
file_labels_example = '/path/to/dataset/train/labels/IMG_4801_JPG_jpg.rf.004c63fe3ea1692644120c6040d32108.txt'with open(file_labels_example) as f:lines_txt = f.readlines()lines = []for line in lines_txt:lines.append([int(line.split()[0])] + [round(float(el), 7) for el in line.split()[1:]])for idx, line in enumerate(lines):print("Rectangle {}:".format(idx+1), line)

您将看到以下输出:

Rectangle 1: [2, 0.7460938, 0.374537, 0.0015625, 0.0027778]
Rectangle 2: [0, 0.6315104, 0.4097222, 0.2598958, 0.1712963]
Rectangle 3: [1, 0.5307292, 0.4509259, 0.0020833, 0.0037037]
Rectangle 4: [1, 0.4484375, 0.4944444, 0.0020833, 0.0037037]
Rectangle 5: [0, 0.3372396, 0.5666667, 0.2859375, 0.2268519]
Rectangle 6: [2, 0.2044271, 0.6171296, 0.0026042, 0.0046296]

这里第 2 和第 5 个矩形与边界框相关,第 3 和第 4 个矩形与头部关键点相关,第 1 和第 6 个矩形与尾部关键点相关。现在您需要在与关键点相关的矩形和与边界框相关的矩形之间找到匹配项。

  • 2.4) 这是一个匹配关键点和边界框的函数,并将注释从 Roboflow 格式转换为 KeypointRCNN 模型所需的格式:
keypoint_names = ['Head', 'Tail']# Dictionary to convert rectangles classes into keypoint classes because keypoint classes should start with 0
rectangles2keypoints = {1:0, 2:1}def converter(file_labels, file_image, keypoint_names):img = cv2.imread(file_image)img_w, img_h = img.shape[1], img.shape[0]with open(file_labels) as f:lines_txt = f.readlines()lines = []for line in lines_txt:lines.append([int(line.split()[0])] + [round(float(el), 5) for el in line.split()[1:]])bboxes = []keypoints = []# In this loop we convert normalized coordinates to absolute coordinatesfor line in lines:# Number 0 is a class of rectangles related to bounding boxes.if line[0] == 0:x_c, y_c, w, h = round(line[1] * img_w), round(line[2] * img_h), round(line[3] * img_w), round(line[4] * img_h)bboxes.append([round(x_c - w/2), round(y_c - h/2), round(x_c + w/2), round(y_c + h/2)])# Other numbers are the classes of rectangles related to keypoints.# After convertion, numbers of keypoint classes should start with 0, so we apply rectangles2keypoints dictionary to achieve that.# In our case:# 1 is rectangle for head keypoint, which is 0, so we convert 1 to 0;# 2 is rectangle for tail keypoint, which is 1, so we convert 2 to 1.if line[0] != 0:kp_id, x_c, y_c = rectangles2keypoints[line[0]], round(line[1] * img_w), round(line[2] * img_h)keypoints.append([kp_id, x_c, y_c])# In this loop we are iterating over each keypoint and looking to which bounding box it matches.# Thus, we are matching keypoints and corresponding bounding boxes.keypoints_sorted = [[[] for _ in keypoint_names] for _ in bboxes]for kp in keypoints:kp_id, kp_x, kp_y = kp[0], kp[1], kp[2]for bbox_idx, bbox in enumerate(bboxes):x1, y1, x2, y2 = bbox[0], bbox[1], bbox[2], bbox[3]if x1 < kp_x < x2 and y1 < kp_y < y2:keypoints_sorted[bbox_idx][kp_id] = [kp_x, kp_y, 1] # All keypoints are visiblereturn bboxes, keypoints_sorted
  • 2.5) 让我们看看这个函数是如何工作的:
bboxes, keypoints_sorted = converter(file_labels_example, file_image_example, keypoint_names)print("Bboxes:", bboxes)
print("Keypoints:", keypoints_sorted)

您将看到以下输出:

Bboxes: [[962, 350, 1462, 534], [374, 490, 922, 734]]
Keypoints: [[[1019, 487, 1], [1432, 405, 1]], [[861, 534, 1], [393, 667, 1]]]

在这里可以看到坐标为[[1019, 487, 1], [1432, 405, 1]]的关键点与坐标为[962, 350, 1462, 534]的边界框相关,坐标为[[861, 534, 1], [393, 667, 1]] 的关键点与坐标为 [374, 490, 922, 734] 的边界框相关。 这里的每个关键点的可见性都等于 1。

  • 2.6) 让我们可视化图像上的边界框和关键点:
for bbox_idx, bbox in enumerate(bboxes):top_left_corner, bottom_right_corner = tuple([bbox[0], bbox[1]]), tuple([bbox[2], bbox[3]])img = cv2.rectangle(img, top_left_corner, bottom_right_corner, (0,255,0), 3)for kp_idx, kp in enumerate(keypoints_sorted[bbox_idx]):center = tuple([kp[0], kp[1]])img = cv2.circle(img, center, 5, (255,0,0), 5)img = cv2.putText(img, " " + keypoint_names[kp_idx], center, cv2.FONT_HERSHEY_SIMPLEX, 1.5, (255,0,0), 4)plt.figure(figsize=(15,15))
plt.imshow(img)

  • 2.7) 让我们定义一个将标注保存到 json 文件中的函数:
def dump2json(bboxes, keypoints_sorted, file_json):annotations = {}annotations['bboxes'], annotations['keypoints'] = bboxes, keypoints_sortedwith open(file_json, "w") as f:json.dump(annotations, f)

函数 dump2json() 将通过以下方式为上面示例中的图像保存注释:

{"bboxes": [[962, 350, 1462, 534], [374, 490, 922, 734]], "keypoints": [[[1019, 487, 1], [1432, 404, 1]], [[861, 534, 1], [392, 666, 1]]]}
  • 2.8) 创建 /train/annotations 文件夹。
  • 2.9) 运行将标签转换为注释并将它们保存到 /train/annotations 文件夹的最后一个代码块:
IMAGES = '/path/to/dataset/train/images'
LABELS = '/path/to/dataset/train/labels'
ANNOTATIONS = '/path/to/dataset/train/annotations'files_names = [file.split('.jpg')[0] for file in os.listdir(IMAGES)]for file in files_names:file_labels = os.path.join(LABELS, file + ".txt")file_image = os.path.join(IMAGES, file + ".jpg")bboxes, keypoints_sorted = converter(file_labels, file_image, keypoint_names)dump2json(bboxes, keypoints_sorted, os.path.join(ANNOTATIONS, file + '.json'))

转换标注后,您需要手动拆分数据集为训练/测试集。

现在,带有标注关键点的胶管图像数据集已准备就绪。您也可以从这里下载。

这是一个 GitHub 存储库和一个包含上述所有步骤的笔记本。

更新: 您可能感兴趣阅读这边文章:如何使用 PyTorch 训练自定义关键点检测模型

参考目录

https://medium.com/@alexppppp/how-to-annotate-keypoints-using-roboflow-9bc2aa8915cd

如何使用 Roboflow 标注关键点相关推荐

  1. COCO KeyPoints关键点数据集准备

    COCO KeyPoints关键点数据集准备 概述 网上搜了一圈,coco关键点数据集准备的内容比较少,这里写一篇完成的标注流程到数据集准备的文章,以备后忘 标注工具 coco官方标注工具: coco ...

  2. 基于人脸关键点修复人脸,腾讯等提出优于SOTA的LaFIn生成网络

    作者 | Yang Yang.Xiaojie Guo.Jiayi Ma.Lin Ma.Haibin Ling 译者 | 刘畅 编辑 | Jane 出品 | AI科技大本营(ID:rgznai100) ...

  3. 李飞飞团队最新论文:基于anchor关键点的类别级物体6D位姿跟踪

    点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 简介 作者提出了一种基于RGB-D的深度学习方法6PACK,能够实时的跟踪已知类别物体.通过学习用少量 ...

  4. 传统的6d位姿估计fangfa1_李飞飞团队最新论文:基于anchor关键点的类别级物体6D位姿跟踪...

    点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 简介 作者提出了一种基于RGB-D的深度学习方法6PACK,能够实时的跟踪已知类别物体.通过学习用少量 ...

  5. 十种常见的图像标注方法 | 数据标注

    计算机视觉的飞速发展离不开大量图像标注数据的支撑,随着各类图像检测.识别算法的商业化落地,市场对图像标注精准度愈发严格,同时针对不同的应用场景,也衍生出了不同的图像标注方法. 今天景联文科技给大家介绍 ...

  6. coco人体姿态估计标注软件

    最近在做人体姿态估计的项目,想自己标注一批数据,但直接使用labelme等软件标注关键点简直不要太痛苦,每个点都要重新点击,还要挨个选择标签.就想尝试一下有没有简单好用的小软件 但看了Github和C ...

  7. MS COCO数据集人体关键点评估(Keypoint Evaluation)(来自官网)

    COCO系列文章: MS COCO数据集目标检测评估(Detection Evaluation)(来自官网) MS COCO数据集人体关键点评估(Keypoint Evaluation)(来自官网) ...

  8. MsCOCO数据集标注详解

    COCO数据集的标注格式 COCO数据集的介绍:全称是Common Objects in COntext,是微软团队提供的一个可以用来进行图像识别的数据集.MS COCO数据集中的图像分为训练.验证和 ...

  9. 融合与创新:数据堂骨龄标注工具为医生赋能

    骨龄是评价青少年儿童生物年龄的主要方法,骨龄与实际年龄并不是必须一致的,骨龄检查可以了解骨骼的发育情况,判断骨龄发育迟缓还是过速,了解身材过矮的原因以及预后.在临床医学.法医学和运动医学等领域中有广泛 ...

最新文章

  1. word2016提示mathtype文件未找到:MathPage.wll
  2. linux 查看和修改文件编码的方法
  3. 史上最“可怕”的数学科普,能全都看懂的只有天才!
  4. Struts2项目中的JSP如何访问Session对象
  5. 散列技术之链地址法(基于无序链表)
  6. java 连接数据库查询_JAVA连接数据库,查询功能怎么写
  7. 矩阵的最大路径和问题
  8. java new对象的创建过程
  9. note : FAILED宏 和 SUCCEEDED宏 的使用细节
  10. linux系统下多终端管理工具,terminator
  11. ,到底是买新房好还是二手房好?看完你就明白了!
  12. 【转】Mp4 Faq
  13. 巴菲特:我可以发2100万个巴菲特币|附视频
  14. linux安装tomcat
  15. 知乎不能改用户名吗_不知道不能随便改名字吗
  16. C语言指针双星,双星引力模拟不知道什么问题……
  17. Ubuntu的docker详细安装+使用
  18. 计算机程序设计员技能试题,计算机程序设计员(基础知识程序设计员高级程序设计员程序设计师国家职业技能鉴定指导)...
  19. 阮小五动问道 江民杀毒软件
  20. 看《反恐24小时》的得到的教训与魔鬼词典

热门文章

  1. php人物图像动漫化
  2. 关于VeriSign(威瑞信)_VeriSign(威瑞信)全球服务网络遍及全球,面向各地客户提供PKI及SSL证书、代码签名证书服务...
  3. 找回手机功能(仅限华为)
  4. 使用Scrapy爬取虎扑爆照区的照片
  5. 全网最全linux Csa 文件创建,删除的方法,教你五分钟掌握干货
  6. redis命令之哈希表类型hset命令用法详情(返回值需要特别注意)
  7. 阿里妈妈API接口 按关键字或网址搜索商品
  8. Scapy 发送带数据的TCP报文 wireshark抓不到scapy发出的包
  9. 计算机网络发展的第三阶段是,在计算机网络发展的第三个阶段,标志性的技术是( )...
  10. Linux系列——VMware虚拟机配置端口转发(端口映射),实现远程访问