diff --git a/docs/annotation/README.md b/docs/annotation/README.md index 13a98e823eef195cef2acc457e7fa6df41bb9834..5be98ce7841af87c7a8f65e708c02aa9b08dc907 100644 --- a/docs/annotation/README.md +++ b/docs/annotation/README.md @@ -1,97 +1,12 @@ # PaddleSeg 数据标注 -用户需预先采集好用于训练、评估和测试的图片,并使用数据标注工具[LabelMe](https://github.com/wkentaro/labelme)完成数据标注,最后用我们提供的数据转换脚本将LabelMe产出的数据格式转换为模型训练时所需的数据格式。 +用户需预先采集好用于训练、评估和测试的图片,并使用数据标注工具完成数据标注。 -## 1 LabelMe的安装 +PaddleSeg支持2种标注工具:LabelMe、精灵数据标注工具。 -用户在采集完用于训练、评估和预测的图片之后,需使用数据标注工具[LabelMe](https://github.com/wkentaro/labelme)完成数据标注。LabelMe支持在Windows/macOS/Linux三个系统上使用,且三个系统下的标注格式是一样。具体的安装流程请参见[官方安装指南](https://github.com/wkentaro/labelme)。 +标注教程如下: +- [LabelMe标注教程](labelme2seg.md) +- [精灵数据标注工具教程](jingling2seg.md) -## 2 LabelMe的使用 +最后用我们提供的数据转换脚本将上述标注工具产出的数据格式转换为模型训练时所需的数据格式。 -打开终端输入`labelme`会出现LableMe的交互界面,可以先预览`LabelMe`给出的已标注好的图片,再开始标注自定义数据集。 - -
- -

图1 LableMe交互界面的示意图

-
- -* 预览已标注图片 - -获取`LabelMe`的源码: -``` -git clone https://github.com/wkentaro/labelme -``` -终端输入`labelme`会出现LableMe的交互界面,点击`OpenDir`打开`/examples/semantic_segmentation/data_annotated`,其中``为克隆下来的`labelme`的路径,打开后示意的是语义分割的真值标注。 - -
- -

图2 已标注图片的示意图

-
- -* 开始标注 - -请按照下述步骤标注数据集: - -​ (1) 点击`OpenDir`打开待标注图片所在目录,点击`Create Polygons`,沿着目标的边缘画多边形,完成后输入目标的类别。在标注过程中,如果某个点画错了,可以按撤销快捷键可撤销该点。Mac下的撤销快捷键为`command+Z`。 - -
- -

图3 标注单个目标的示意图

-
- -​ (2) 右击选择`Edit Polygons`可以整体移动多边形的位置,也可以移动某个点的位置;右击选择`Edit Label`可以修改每个目标的类别。请根据自己的需要执行这一步骤,若不需要修改,可跳过。 - -
- - -

图4 修改标注的示意图

-
- -​ (3) 图片中所有目标的标注都完成后,点击`Save`保存json文件,**请将json文件和图片放在同一个文件夹里**,点击`Next Image`标注下一张图片。 - -LableMe产出的真值文件可参考我们给出的文件夹`data_annotated`。 - -
- -

图5 LableMe产出的真值文件的示意图

-
- - ## 3 数据格式转换 - -* 我们用于完成语义分割的数据集目录结构如下: - - ``` - my_dataset # 根目录 - |-- JPEGImages # 数据集图片 - |-- SegmentationClassPNG # 数据集真值 - | |-- xxx.png # 像素级别的真值信息 - | |... - |-- class_names.txt # 数据集的类别名称 - - ``` - -
- -

图6 训练所需的数据集目录的结构示意图

-
- -* 运行转换脚本需要依赖labelme和pillow,如未安装,请先安装。Labelme的具体安装流程请参见[官方安装指南](https://github.com/wkentaro/labelme)。Pillow的安装: - -```shell -pip install pillow -``` - -* 运行以下代码,将标注后的数据转换成满足以上格式的数据集: - -``` - python labelme2seg.py -``` - -其中,``为图片以及LabelMe产出的json文件所在文件夹的目录,``为转换后的数据集所在文件夹的目录。**需注意的是:``不用预先创建,脚本运行时会自动创建,否则会报错。** - -转换得到的数据集可参考我们给出的文件夹`my_dataset`。其中,文件`class_names.txt`是数据集中所有标注类别的名称,包含背景类;文件夹`JPEGImages`保存的是数据集的图片;文件夹`SegmentationClassPNG`保存的是各图片的像素级别的真值信息,背景类`_background_`对应为0,其它目标类别从1开始递增,至多为255。 - -
- -

图7 训练所需的数据集各目录的内容示意图

-
diff --git a/docs/annotation/data_annotated/aa63d7e6db0d03137883772c246c6761fc201059.jpg b/docs/annotation/data_annotated/aa63d7e6db0d03137883772c246c6761fc201059.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3d10c0d1ea47987153f7c51e6b992d1dfe35d3ae Binary files /dev/null and b/docs/annotation/data_annotated/aa63d7e6db0d03137883772c246c6761fc201059.jpg differ diff --git a/docs/annotation/data_annotated/aa63d7e6db0d03137883772c246c6761fc201059.json b/docs/annotation/data_annotated/aa63d7e6db0d03137883772c246c6761fc201059.json new file mode 100644 index 0000000000000000000000000000000000000000..34bb4674f0d0f16f257e2cc0abb7292f1dc4566d --- /dev/null +++ b/docs/annotation/data_annotated/aa63d7e6db0d03137883772c246c6761fc201059.json @@ -0,0 +1 @@ +{"path":"/Users/chulutao/dataset/humanseg/aa63d7e6db0d03137883772c246c6761fc201059.jpg","outputs":{"object":[{"name":"person","polygon":{"x1":321.99,"y1":63,"x2":293,"y2":98.00999999999999,"x3":245.01,"y3":141.01,"x4":221,"y4":194,"x5":231.99,"y5":237,"x6":231.99,"y6":348.01,"x7":191,"y7":429,"x8":197,"y8":465.01,"x9":193,"y9":586,"x10":151,"y10":618.01,"x11":124,"y11":622,"x12":100,"y12":703,"x13":121.99,"y13":744,"x14":141.99,"y14":724,"x15":163,"y15":658.01,"x16":238.01,"y16":646,"x17":259,"y17":627,"x18":313,"y18":618.01,"x19":416,"y19":639,"x20":464,"y20":606,"x21":454,"y21":555.01,"x22":404,"y22":508.01,"x23":430,"y23":489,"x24":407,"y24":464,"x25":397,"y25":365.01,"x26":407,"y26":290,"x27":361.99,"y27":252,"x28":376,"y28":215.01,"x29":391.99,"y29":189,"x30":388.01,"y30":135.01,"x31":340,"y31":120,"x32":313,"y32":161.01,"x33":307,"y33":188.01,"x34":311,"y34":207,"x35":277,"y35":186,"x36":293,"y36":137,"x37":308.01,"y37":117,"x38":361,"y38":93}}]},"time_labeled":1568101256852,"labeled":true,"size":{"width":706,"height":1000,"depth":3}} \ No newline at end of file diff --git a/docs/annotation/jingling2seg.md b/docs/annotation/jingling2seg.md new file mode 100644 index 0000000000000000000000000000000000000000..127bfb693f46c4391634e91df702a2d961cae85d --- /dev/null +++ b/docs/annotation/jingling2seg.md @@ -0,0 +1,94 @@ +# 精灵标注工具教程 + +## 1 精灵标注工具的安装 + +用户在采集完用于训练、评估和预测的图片之后,可使用[精灵数据标注工具](http://www.jinglingbiaozhu.com/)完成数据标注。精灵标注支持在Windows/macOS/Linux三个系统上使用,Mac的话可以到MacStore中搜索colabeler下载即可。 + +## 2 精灵标注工具的使用 + +开始标注自定义数据集之前,可以先预览精灵标注官网的[文字教程](http://www.jinglingbiaozhu.com/?type=tutorial&cat_id=4)和[视频教程](http://www.jinglingbiaozhu.com/?type=tutorial&cat_id=5)。 + + +* 开始标注 + +打开精灵标注工具。 + +
+ +

图1 精灵标注交互界面的示意图

+
+ +请按照下述步骤标注数据集: + +(1) 点击`新建`,然后选择`位置标注`,选择`图片文件夹`,修改填写所需的`分类值`(注意:以英文逗号隔开),点击`创建`按钮,软件会自动加载文件夹下的图片(png,jpg,gif)并创建一个项目。 + +位置标注支持三种类型:矩形,多边形和曲线。选择简单好用的`多边形框`,沿着目标的边缘画多边形,完成后在右侧输入目标的类别。 + +**注意:切记单张图片标注完成后进行保存,点击下方中央的勾按钮或者使用快捷键ctrl+s**。 + +然后可以点击左边的前一个后一个或者直接使用键盘的向左按钮和向右按钮来切换图片。 + +
+ +

图2 标注单个目标的示意图

+
+ +(2) 单击目标框,鼠标拖动可以整体移动多边形的位置;点击左侧的`删除选框`可以删除画错的目标框;点击右侧的`标注信息`可修改目标类别。请根据自己的需要执行这一步骤,若不需要修改,可跳过。 + +
+ +

图3 修改标注的示意图

+
+ +(3) 当所有图片的标注都完成后,点击左侧的`导出`,输出方式选择`JSON`,指定`保存位置`,点击`确定导出`保存所有图片的标注文件。 + +**注意:导出的标注文件位于`保存位置`下的`outputs`目录。** + +精灵标注产出的真值文件可参考我们给出的文件夹`data_annotated`。 + +
+ +

图4 精灵标注产出的真值文件的示意图

+
+ + ## 3 数据格式转换 + +* 我们用于完成语义分割的数据集目录结构如下: + + ``` + my_dataset # 根目录 + |-- JPEGImages # 数据集图片 + |-- SegmentationClassPNG # 数据集真值 + | |-- xxx.png # 像素级别的真值信息 + | |... + |-- class_names.txt # 数据集的类别名称 + + ``` + +
+ +

图5 训练所需的数据集目录的结构示意图

+
+ +* 运行转换脚本需要依赖labelme和pillow,如未安装,请先安装。Labelme的具体安装流程请参见[官方安装指南](https://github.com/wkentaro/labelme)。Pillow的安装: + +```shell +pip install pillow +``` + +* 运行以下代码,将标注后的数据转换成满足以上格式的数据集: + +``` + python jingling2seg.py +``` + +其中,``为精灵标注产出的json文件所在文件夹的目录,一般为精灵工具使用(3)中`保存位置`下的`outputs`目录。``为转换后的数据集所在文件夹的目录。 + +**注意:``不用预先创建,脚本运行时会自动创建,否则会报错。** + +转换得到的数据集可参考我们给出的文件夹`my_dataset`。其中,文件`class_names.txt`是数据集中所有标注类别的名称,包含背景类;文件夹`JPEGImages`保存的是数据集的图片;文件夹`SegmentationClassPNG`保存的是各图片的像素级别的真值信息,背景类`_background_`对应为0,其它目标类别从1开始递增,至多为255。 + +
+ +

图6 训练所需的数据集各目录的内容示意图

+
diff --git a/docs/annotation/jingling2seg.py b/docs/annotation/jingling2seg.py new file mode 100644 index 0000000000000000000000000000000000000000..18626157738671afc8415471d108e9d6a04f8495 --- /dev/null +++ b/docs/annotation/jingling2seg.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python + +from __future__ import print_function + +import argparse +import glob +import json +import os +import os.path as osp +import sys + +import numpy as np +import PIL.Image + +import labelme + + +def main(): + parser = argparse.ArgumentParser( + formatter_class=argparse.ArgumentDefaultsHelpFormatter + ) + parser.add_argument('label_dir', help='input annotated directory') + parser.add_argument('output_dir', help='output dataset directory') + args = parser.parse_args() + + if osp.exists(args.output_dir): + print('Output directory already exists:', args.output_dir) + sys.exit(1) + + os.makedirs(args.output_dir) + os.makedirs(osp.join(args.output_dir, 'JPEGImages')) + os.makedirs(osp.join(args.output_dir, 'SegmentationClassPNG')) + print('Creating dataset:', args.output_dir) + + # get the all class names for the given dataset + class_names = ['_background_'] + for label_file in glob.glob(osp.join(args.label_dir, '*.json')): + with open(label_file) as f: + data = json.load(f) + if data['outputs']: + for output in data['outputs']['object']: + name = output['name'] + cls_name = name + if not cls_name in class_names: + class_names.append(cls_name) + + class_name_to_id = {} + for i, class_name in enumerate(class_names): + class_id = i # starts with 0 + class_name_to_id[class_name] = class_id + if class_id == 0: + assert class_name == '_background_' + class_names = tuple(class_names) + print('class_names:', class_names) + + out_class_names_file = osp.join(args.output_dir, 'class_names.txt') + with open(out_class_names_file, 'w') as f: + f.writelines('\n'.join(class_names)) + print('Saved class_names:', out_class_names_file) + + for label_file in glob.glob(osp.join(args.label_dir, '*.json')): + print('Generating dataset from:', label_file) + with open(label_file) as f: + base = osp.splitext(osp.basename(label_file))[0] + out_img_file = osp.join( + args.output_dir, 'JPEGImages', base + '.jpg') + out_png_file = osp.join( + args.output_dir, 'SegmentationClassPNG', base + '.png') + + data = json.load(f) + + data_shapes = [] + if data['outputs']: + for output in data['outputs']['object']: + if 'polygon' in output.keys(): + polygon = output['polygon'] + name = output['name'] + + # convert jingling format to labelme format + points = [] + for i in range(1, int(len(polygon) / 2) + 1): + points.append([polygon['x' + str(i)], polygon['y' + str(i)]]) + shape = {'label': name, 'points': points, 'shape_type': 'polygon'} + data_shapes.append(shape) + + img_file = osp.join(osp.dirname(label_file), data['path']) + img = np.asarray(PIL.Image.open(img_file)) + PIL.Image.fromarray(img).save(out_img_file) + + lbl = labelme.utils.shapes_to_label( + img_shape=img.shape, + shapes=data_shapes, + label_name_to_value=class_name_to_id, + ) + + if osp.splitext(out_png_file)[1] != '.png': + out_png_file += '.png' + # Assume label ranses [0, 255] for uint8, + if lbl.min() >= 0 and lbl.max() <= 255: + lbl_pil = PIL.Image.fromarray(lbl.astype(np.uint8), mode='L') + lbl_pil.save(out_png_file) + else: + raise ValueError( + '[%s] Cannot save the pixel-wise class label as PNG. ' + 'Please consider using the .npy format.' % out_png_file + ) + + +if __name__ == '__main__': + main() diff --git a/docs/annotation/labelme2seg.md b/docs/annotation/labelme2seg.md new file mode 100644 index 0000000000000000000000000000000000000000..b969ea092c1b5e9dddf4a8dc27255cb7818c9571 --- /dev/null +++ b/docs/annotation/labelme2seg.md @@ -0,0 +1,95 @@ +# LabelMe数据标注教程 + +## 1 LabelMe的安装 + +用户在采集完用于训练、评估和预测的图片之后,需使用数据标注工具[LabelMe](https://github.com/wkentaro/labelme)完成数据标注。LabelMe支持在Windows/macOS/Linux三个系统上使用,且三个系统下的标注格式是一样。具体的安装流程请参见[官方安装指南](https://github.com/wkentaro/labelme)。 + +## 2 LabelMe的使用 + +打开终端输入`labelme`会出现LableMe的交互界面,可以先预览`LabelMe`给出的已标注好的图片,再开始标注自定义数据集。 + +
+ +

图1 LableMe交互界面的示意图

+
+ +* 预览已标注图片 + +获取`LabelMe`的源码: +``` +git clone https://github.com/wkentaro/labelme +``` +终端输入`labelme`会出现LableMe的交互界面,点击`OpenDir`打开`/examples/semantic_segmentation/data_annotated`,其中``为克隆下来的`labelme`的路径,打开后示意的是语义分割的真值标注。 + +
+ +

图2 已标注图片的示意图

+
+ +* 开始标注 + +请按照下述步骤标注数据集: + +​ (1) 点击`OpenDir`打开待标注图片所在目录,点击`Create Polygons`,沿着目标的边缘画多边形,完成后输入目标的类别。在标注过程中,如果某个点画错了,可以按撤销快捷键可撤销该点。Mac下的撤销快捷键为`command+Z`。 + +
+ +

图3 标注单个目标的示意图

+
+ +​ (2) 右击选择`Edit Polygons`可以整体移动多边形的位置,也可以移动某个点的位置;右击选择`Edit Label`可以修改每个目标的类别。请根据自己的需要执行这一步骤,若不需要修改,可跳过。 + +
+ + +

图4 修改标注的示意图

+
+ +​ (3) 图片中所有目标的标注都完成后,点击`Save`保存json文件,**请将json文件和图片放在同一个文件夹里**,点击`Next Image`标注下一张图片。 + +LableMe产出的真值文件可参考我们给出的文件夹`data_annotated`。 + +
+ +

图5 LableMe产出的真值文件的示意图

+
+ + ## 3 数据格式转换 + +* 我们用于完成语义分割的数据集目录结构如下: + + ``` + my_dataset # 根目录 + |-- JPEGImages # 数据集图片 + |-- SegmentationClassPNG # 数据集真值 + | |-- xxx.png # 像素级别的真值信息 + | |... + |-- class_names.txt # 数据集的类别名称 + + ``` + +
+ +

图6 训练所需的数据集目录的结构示意图

+
+ +* 运行转换脚本需要依赖labelme和pillow,如未安装,请先安装。Labelme的具体安装流程请参见[官方安装指南](https://github.com/wkentaro/labelme)。Pillow的安装: + +```shell +pip install pillow +``` + +* 运行以下代码,将标注后的数据转换成满足以上格式的数据集: + +``` + python labelme2seg.py +``` + +其中,``为图片以及LabelMe产出的json文件所在文件夹的目录,``为转换后的数据集所在文件夹的目录。**需注意的是:``不用预先创建,脚本运行时会自动创建,否则会报错。** + +转换得到的数据集可参考我们给出的文件夹`my_dataset`。其中,文件`class_names.txt`是数据集中所有标注类别的名称,包含背景类;文件夹`JPEGImages`保存的是数据集的图片;文件夹`SegmentationClassPNG`保存的是各图片的像素级别的真值信息,背景类`_background_`对应为0,其它目标类别从1开始递增,至多为255。 + +
+ +

图7 训练所需的数据集各目录的内容示意图

+
diff --git a/docs/imgs/annotation/jingling-1.png b/docs/imgs/annotation/jingling-1.png new file mode 100644 index 0000000000000000000000000000000000000000..6c29de5858ce95be95b9c1ce3a6f01bde8cbe1eb Binary files /dev/null and b/docs/imgs/annotation/jingling-1.png differ diff --git a/docs/imgs/annotation/jingling-2.png b/docs/imgs/annotation/jingling-2.png new file mode 100644 index 0000000000000000000000000000000000000000..1e93e9491ac2667535b2dcc6016a1a9ac3b83f20 Binary files /dev/null and b/docs/imgs/annotation/jingling-2.png differ diff --git a/docs/imgs/annotation/jingling-3.png b/docs/imgs/annotation/jingling-3.png new file mode 100644 index 0000000000000000000000000000000000000000..bd0cba879b045e7c31b0ef024bbf75cc1ba3c9e3 Binary files /dev/null and b/docs/imgs/annotation/jingling-3.png differ diff --git a/docs/imgs/annotation/jingling-4.png b/docs/imgs/annotation/jingling-4.png new file mode 100644 index 0000000000000000000000000000000000000000..8a2e70b985cf4bf4cbb5ed5de88221e8a86aaf25 Binary files /dev/null and b/docs/imgs/annotation/jingling-4.png differ diff --git a/docs/imgs/annotation/jingling-5.png b/docs/imgs/annotation/jingling-5.png new file mode 100644 index 0000000000000000000000000000000000000000..54bfb1e03f89078873cae11704d6d6cc6eb7cd2c Binary files /dev/null and b/docs/imgs/annotation/jingling-5.png differ diff --git a/docs/imgs/data_aug_flow.png b/docs/imgs/data_aug_flow.png index 9ed4cc5688df36960ef5ee405bd1eadc1b58d357..b9e0a32b7ed61da5a1bd8c94a8761f181898803c 100644 Binary files a/docs/imgs/data_aug_flow.png and b/docs/imgs/data_aug_flow.png differ