Browse Source

dataannotation

LaraStuStu 5 years ago
parent
commit
e4784c9c2d
100 changed files with 5001 additions and 0 deletions
  1. 47 0
      DataAnnotation/labelme/examples/instance_segmentation/README.md
  2. BIN
      DataAnnotation/labelme/examples/instance_segmentation/data_dataset_voc/SegmentationClassVisualization/2011_000006.jpg
  3. BIN
      DataAnnotation/labelme/examples/instance_segmentation/data_dataset_voc/SegmentationClassVisualization/2011_000025.jpg
  4. BIN
      DataAnnotation/labelme/examples/instance_segmentation/data_dataset_voc/SegmentationObject/2011_000003.npy
  5. BIN
      DataAnnotation/labelme/examples/instance_segmentation/data_dataset_voc/SegmentationObject/2011_000006.npy
  6. BIN
      DataAnnotation/labelme/examples/instance_segmentation/data_dataset_voc/SegmentationObject/2011_000025.npy
  7. BIN
      DataAnnotation/labelme/examples/instance_segmentation/data_dataset_voc/SegmentationObjectPNG/2011_000003.png
  8. BIN
      DataAnnotation/labelme/examples/instance_segmentation/data_dataset_voc/SegmentationObjectPNG/2011_000006.png
  9. BIN
      DataAnnotation/labelme/examples/instance_segmentation/data_dataset_voc/SegmentationObjectPNG/2011_000025.png
  10. BIN
      DataAnnotation/labelme/examples/instance_segmentation/data_dataset_voc/SegmentationObjectVisualization/2011_000003.jpg
  11. BIN
      DataAnnotation/labelme/examples/instance_segmentation/data_dataset_voc/SegmentationObjectVisualization/2011_000006.jpg
  12. BIN
      DataAnnotation/labelme/examples/instance_segmentation/data_dataset_voc/SegmentationObjectVisualization/2011_000025.jpg
  13. 153 0
      DataAnnotation/labelme/examples/instance_segmentation/labelme2coco.py
  14. 117 0
      DataAnnotation/labelme/examples/instance_segmentation/labelme2voc.py
  15. 22 0
      DataAnnotation/labelme/examples/instance_segmentation/labels.txt
  16. BIN
      DataAnnotation/labelme/examples/primitives/primitives.jpg
  17. 140 0
      DataAnnotation/labelme/examples/primitives/primitives.json
  18. BIN
      DataAnnotation/labelme/examples/semantic_segmentation/.readme/annotation.jpg
  19. BIN
      DataAnnotation/labelme/examples/semantic_segmentation/.readme/draw_label_png.jpg
  20. 35 0
      DataAnnotation/labelme/examples/semantic_segmentation/README.md
  21. BIN
      DataAnnotation/labelme/examples/semantic_segmentation/data_annotated/2011_000003.jpg
  22. 481 0
      DataAnnotation/labelme/examples/semantic_segmentation/data_annotated/2011_000003.json
  23. BIN
      DataAnnotation/labelme/examples/semantic_segmentation/data_annotated/2011_000006.jpg
  24. 528 0
      DataAnnotation/labelme/examples/semantic_segmentation/data_annotated/2011_000006.json
  25. BIN
      DataAnnotation/labelme/examples/semantic_segmentation/data_annotated/2011_000025.jpg
  26. 215 0
      DataAnnotation/labelme/examples/semantic_segmentation/data_annotated/2011_000025.json
  27. BIN
      DataAnnotation/labelme/examples/semantic_segmentation/data_dataset_voc/JPEGImages/2011_000003.jpg
  28. BIN
      DataAnnotation/labelme/examples/semantic_segmentation/data_dataset_voc/JPEGImages/2011_000006.jpg
  29. BIN
      DataAnnotation/labelme/examples/semantic_segmentation/data_dataset_voc/JPEGImages/2011_000025.jpg
  30. BIN
      DataAnnotation/labelme/examples/semantic_segmentation/data_dataset_voc/SegmentationClass/2011_000003.npy
  31. BIN
      DataAnnotation/labelme/examples/semantic_segmentation/data_dataset_voc/SegmentationClass/2011_000006.npy
  32. BIN
      DataAnnotation/labelme/examples/semantic_segmentation/data_dataset_voc/SegmentationClass/2011_000025.npy
  33. BIN
      DataAnnotation/labelme/examples/semantic_segmentation/data_dataset_voc/SegmentationClassPNG/2011_000003.png
  34. BIN
      DataAnnotation/labelme/examples/semantic_segmentation/data_dataset_voc/SegmentationClassPNG/2011_000006.png
  35. BIN
      DataAnnotation/labelme/examples/semantic_segmentation/data_dataset_voc/SegmentationClassPNG/2011_000025.png
  36. BIN
      DataAnnotation/labelme/examples/semantic_segmentation/data_dataset_voc/SegmentationClassVisualization/2011_000003.jpg
  37. BIN
      DataAnnotation/labelme/examples/semantic_segmentation/data_dataset_voc/SegmentationClassVisualization/2011_000006.jpg
  38. BIN
      DataAnnotation/labelme/examples/semantic_segmentation/data_dataset_voc/SegmentationClassVisualization/2011_000025.jpg
  39. 21 0
      DataAnnotation/labelme/examples/semantic_segmentation/data_dataset_voc/class_names.txt
  40. 95 0
      DataAnnotation/labelme/examples/semantic_segmentation/labelme2voc.py
  41. 22 0
      DataAnnotation/labelme/examples/semantic_segmentation/labels.txt
  42. BIN
      DataAnnotation/labelme/examples/tutorial/.readme/annotation.jpg
  43. BIN
      DataAnnotation/labelme/examples/tutorial/.readme/draw_json.jpg
  44. BIN
      DataAnnotation/labelme/examples/tutorial/.readme/draw_label_png.jpg
  45. 66 0
      DataAnnotation/labelme/examples/tutorial/README.md
  46. BIN
      DataAnnotation/labelme/examples/tutorial/apc2016_obj3.jpg
  47. 248 0
      DataAnnotation/labelme/examples/tutorial/apc2016_obj3.json
  48. BIN
      DataAnnotation/labelme/examples/tutorial/apc2016_obj3_json/img.png
  49. 6 0
      DataAnnotation/labelme/examples/tutorial/apc2016_obj3_json/info.yaml
  50. BIN
      DataAnnotation/labelme/examples/tutorial/apc2016_obj3_json/label.png
  51. 5 0
      DataAnnotation/labelme/examples/tutorial/apc2016_obj3_json/label_names.txt
  52. BIN
      DataAnnotation/labelme/examples/tutorial/apc2016_obj3_json/label_viz.png
  53. 37 0
      DataAnnotation/labelme/examples/tutorial/load_label_png.py
  54. BIN
      DataAnnotation/labelme/examples/video_annotation/.readme/00000100.jpg
  55. BIN
      DataAnnotation/labelme/examples/video_annotation/.readme/00000101.jpg
  56. BIN
      DataAnnotation/labelme/examples/video_annotation/.readme/data_annotated.gif
  57. 31 0
      DataAnnotation/labelme/examples/video_annotation/README.md
  58. BIN
      DataAnnotation/labelme/examples/video_annotation/data_annotated/00000100.jpg
  59. 160 0
      DataAnnotation/labelme/examples/video_annotation/data_annotated/00000100.json
  60. BIN
      DataAnnotation/labelme/examples/video_annotation/data_annotated/00000101.jpg
  61. 160 0
      DataAnnotation/labelme/examples/video_annotation/data_annotated/00000101.json
  62. BIN
      DataAnnotation/labelme/examples/video_annotation/data_annotated/00000102.jpg
  63. 160 0
      DataAnnotation/labelme/examples/video_annotation/data_annotated/00000102.json
  64. BIN
      DataAnnotation/labelme/examples/video_annotation/data_annotated/00000103.jpg
  65. 160 0
      DataAnnotation/labelme/examples/video_annotation/data_annotated/00000103.json
  66. BIN
      DataAnnotation/labelme/examples/video_annotation/data_annotated/00000104.jpg
  67. 160 0
      DataAnnotation/labelme/examples/video_annotation/data_annotated/00000104.json
  68. BIN
      DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/JPEGImages/00000100.jpg
  69. BIN
      DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/JPEGImages/00000101.jpg
  70. BIN
      DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/JPEGImages/00000102.jpg
  71. BIN
      DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/JPEGImages/00000103.jpg
  72. BIN
      DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/JPEGImages/00000104.jpg
  73. BIN
      DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/SegmentationClass/00000100.npy
  74. BIN
      DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/SegmentationClass/00000101.npy
  75. BIN
      DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/SegmentationClass/00000102.npy
  76. BIN
      DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/SegmentationClass/00000103.npy
  77. BIN
      DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/SegmentationClass/00000104.npy
  78. BIN
      DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/SegmentationClassPNG/00000100.png
  79. BIN
      DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/SegmentationClassPNG/00000101.png
  80. BIN
      DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/SegmentationClassPNG/00000102.png
  81. BIN
      DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/SegmentationClassPNG/00000103.png
  82. BIN
      DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/SegmentationClassPNG/00000104.png
  83. BIN
      DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/SegmentationClassVisualization/00000100.jpg
  84. BIN
      DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/SegmentationClassVisualization/00000101.jpg
  85. BIN
      DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/SegmentationClassVisualization/00000102.jpg
  86. BIN
      DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/SegmentationClassVisualization/00000103.jpg
  87. BIN
      DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/SegmentationClassVisualization/00000104.jpg
  88. 3 0
      DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/class_names.txt
  89. 1 0
      DataAnnotation/labelme/examples/video_annotation/labelme2voc.py
  90. 4 0
      DataAnnotation/labelme/examples/video_annotation/labels.txt
  91. 26 0
      DataAnnotation/labelme/github2pypi/.travis.yml
  92. 47 0
      DataAnnotation/labelme/github2pypi/README.md
  93. 3 0
      DataAnnotation/labelme/github2pypi/__init__.py
  94. 41 0
      DataAnnotation/labelme/github2pypi/replace_url.py
  95. 45 0
      DataAnnotation/labelme/labelme.spec
  96. 23 0
      DataAnnotation/labelme/labelme/__init__.py
  97. 5 0
      DataAnnotation/labelme/labelme/_version.py
  98. 1670 0
      DataAnnotation/labelme/labelme/app.py
  99. 6 0
      DataAnnotation/labelme/labelme/cli/__init__.py
  100. 58 0
      DataAnnotation/labelme/labelme/cli/draw_json.py

+ 47 - 0
DataAnnotation/labelme/examples/instance_segmentation/README.md

@@ -0,0 +1,47 @@
+# Instance Segmentation Example
+
+## Annotation
+
+```bash
+labelme data_annotated --labels labels.txt --nodata
+labelme data_annotated --labels labels.txt --nodata --labelflags '{.*: [occluded, truncated], person-\d+: [male]}'
+```
+
+![](.readme/annotation.jpg)
+
+## Convert to VOC-format Dataset
+
+```bash
+# It generates:
+#   - data_dataset_voc/JPEGImages
+#   - data_dataset_voc/SegmentationClass
+#   - data_dataset_voc/SegmentationClassVisualization
+#   - data_dataset_voc/SegmentationObject
+#   - data_dataset_voc/SegmentationObjectVisualization
+./labelme2voc.py data_annotated data_dataset_voc --labels labels.txt
+```
+
+<img src="data_dataset_voc/JPEGImages/2011_000003.jpg" width="33%" /> <img src="data_dataset_voc/SegmentationClassVisualization/2011_000003.jpg" width="33%" /> <img src="data_dataset_voc/SegmentationObjectVisualization/2011_000003.jpg" width="33%" />  
+Fig 1. JPEG image (left), JPEG class label visualization (center), JPEG instance label visualization (right)
+
+
+Note that the label file contains only very low label values (ex. `0, 4, 14`), and
+`255` indicates the `__ignore__` label value (`-1` in the npy file).  
+You can see the label PNG file by following.
+
+```bash
+labelme_draw_label_png data_dataset_voc/SegmentationClassPNG/2011_000003.png   # left
+labelme_draw_label_png data_dataset_voc/SegmentationObjectPNG/2011_000003.png  # right
+```
+
+<img src=".readme/draw_label_png_class.jpg" width="33%" /> <img src=".readme/draw_label_png_object.jpg" width="33%" />
+
+
+## Convert to COCO-format Dataset
+
+```bash
+# It generates:
+#   - data_dataset_coco/JPEGImages
+#   - data_dataset_coco/annotations.json
+./labelme2coco.py data_annotated data_dataset_coco --labels labels.txt
+```

BIN
DataAnnotation/labelme/examples/instance_segmentation/data_dataset_voc/SegmentationClassVisualization/2011_000006.jpg


BIN
DataAnnotation/labelme/examples/instance_segmentation/data_dataset_voc/SegmentationClassVisualization/2011_000025.jpg


BIN
DataAnnotation/labelme/examples/instance_segmentation/data_dataset_voc/SegmentationObject/2011_000003.npy


BIN
DataAnnotation/labelme/examples/instance_segmentation/data_dataset_voc/SegmentationObject/2011_000006.npy


BIN
DataAnnotation/labelme/examples/instance_segmentation/data_dataset_voc/SegmentationObject/2011_000025.npy


BIN
DataAnnotation/labelme/examples/instance_segmentation/data_dataset_voc/SegmentationObjectPNG/2011_000003.png


BIN
DataAnnotation/labelme/examples/instance_segmentation/data_dataset_voc/SegmentationObjectPNG/2011_000006.png


BIN
DataAnnotation/labelme/examples/instance_segmentation/data_dataset_voc/SegmentationObjectPNG/2011_000025.png


BIN
DataAnnotation/labelme/examples/instance_segmentation/data_dataset_voc/SegmentationObjectVisualization/2011_000003.jpg


BIN
DataAnnotation/labelme/examples/instance_segmentation/data_dataset_voc/SegmentationObjectVisualization/2011_000006.jpg


BIN
DataAnnotation/labelme/examples/instance_segmentation/data_dataset_voc/SegmentationObjectVisualization/2011_000025.jpg


+ 153 - 0
DataAnnotation/labelme/examples/instance_segmentation/labelme2coco.py

@@ -0,0 +1,153 @@
+#!/usr/bin/env python
+
+import argparse
+import collections
+import datetime
+import glob
+import json
+import os
+import os.path as osp
+import sys
+
+import numpy as np
+import PIL.Image
+
+import labelme
+
+try:
+    import pycocotools.mask
+except ImportError:
+    print('Please install pycocotools:\n\n    pip install pycocotools\n')
+    sys.exit(1)
+
+
+def main():
+    parser = argparse.ArgumentParser(
+        formatter_class=argparse.ArgumentDefaultsHelpFormatter
+    )
+    parser.add_argument('input_dir', help='input annotated directory')
+    parser.add_argument('output_dir', help='output dataset directory')
+    parser.add_argument('--labels', help='labels file', required=True)
+    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'))
+    print('Creating dataset:', args.output_dir)
+
+    now = datetime.datetime.now()
+
+    data = dict(
+        info=dict(
+            description=None,
+            url=None,
+            version=None,
+            year=now.year,
+            contributor=None,
+            date_created=now.strftime('%Y-%m-%d %H:%M:%S.%f'),
+        ),
+        licenses=[dict(
+            url=None,
+            id=0,
+            name=None,
+        )],
+        images=[
+            # license, url, file_name, height, width, date_captured, id
+        ],
+        type='instances',
+        annotations=[
+            # segmentation, area, iscrowd, image_id, bbox, category_id, id
+        ],
+        categories=[
+            # supercategory, id, name
+        ],
+    )
+
+    class_name_to_id = {}
+    for i, line in enumerate(open(args.labels).readlines()):
+        class_id = i - 1  # starts with -1
+        class_name = line.strip()
+        if class_id == -1:
+            assert class_name == '__ignore__'
+            continue
+        class_name_to_id[class_name] = class_id
+        data['categories'].append(dict(
+            supercategory=None,
+            id=class_id,
+            name=class_name,
+        ))
+
+    out_ann_file = osp.join(args.output_dir, 'annotations.json')
+    label_files = glob.glob(osp.join(args.input_dir, '*.json'))
+    for image_id, label_file in enumerate(label_files):
+        print('Generating dataset from:', label_file)
+        with open(label_file) as f:
+            label_data = json.load(f)
+
+        base = osp.splitext(osp.basename(label_file))[0]
+        out_img_file = osp.join(
+            args.output_dir, 'JPEGImages', base + '.jpg'
+        )
+
+        img_file = osp.join(
+            osp.dirname(label_file), label_data['imagePath']
+        )
+        img = np.asarray(PIL.Image.open(img_file))
+        PIL.Image.fromarray(img).save(out_img_file)
+        data['images'].append(dict(
+            license=0,
+            url=None,
+            file_name=osp.relpath(out_img_file, osp.dirname(out_ann_file)),
+            height=img.shape[0],
+            width=img.shape[1],
+            date_captured=None,
+            id=image_id,
+        ))
+
+        masks = {}                                     # for area
+        segmentations = collections.defaultdict(list)  # for segmentation
+        for shape in label_data['shapes']:
+            points = shape['points']
+            label = shape['label']
+            shape_type = shape.get('shape_type', None)
+            mask = labelme.utils.shape_to_mask(
+                img.shape[:2], points, shape_type
+            )
+
+            if label in masks:
+                masks[label] = masks[label] | mask
+            else:
+                masks[label] = mask
+
+            points = np.asarray(points).flatten().tolist()
+            segmentations[label].append(points)
+
+        for label, mask in masks.items():
+            cls_name = label.split('-')[0]
+            if cls_name not in class_name_to_id:
+                continue
+            cls_id = class_name_to_id[cls_name]
+
+            mask = np.asfortranarray(mask.astype(np.uint8))
+            mask = pycocotools.mask.encode(mask)
+            area = float(pycocotools.mask.area(mask))
+            bbox = pycocotools.mask.toBbox(mask).flatten().tolist()
+
+            data['annotations'].append(dict(
+                id=len(data['annotations']),
+                image_id=image_id,
+                category_id=cls_id,
+                segmentation=segmentations[label],
+                area=area,
+                bbox=bbox,
+                iscrowd=0,
+            ))
+
+    with open(out_ann_file, 'w') as f:
+        json.dump(data, f)
+
+
+if __name__ == '__main__':
+    main()

+ 117 - 0
DataAnnotation/labelme/examples/instance_segmentation/labelme2voc.py

@@ -0,0 +1,117 @@
+#!/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('input_dir', help='input annotated directory')
+    parser.add_argument('output_dir', help='output dataset directory')
+    parser.add_argument('--labels', help='labels file', required=True)
+    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, 'SegmentationClass'))
+    os.makedirs(osp.join(args.output_dir, 'SegmentationClassPNG'))
+    os.makedirs(osp.join(args.output_dir, 'SegmentationClassVisualization'))
+    os.makedirs(osp.join(args.output_dir, 'SegmentationObject'))
+    os.makedirs(osp.join(args.output_dir, 'SegmentationObjectPNG'))
+    os.makedirs(osp.join(args.output_dir, 'SegmentationObjectVisualization'))
+    print('Creating dataset:', args.output_dir)
+
+    class_names = []
+    class_name_to_id = {}
+    for i, line in enumerate(open(args.labels).readlines()):
+        class_id = i - 1  # starts with -1
+        class_name = line.strip()
+        class_name_to_id[class_name] = class_id
+        if class_id == -1:
+            assert class_name == '__ignore__'
+            continue
+        elif class_id == 0:
+            assert class_name == '_background_'
+        class_names.append(class_name)
+    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)
+
+    colormap = labelme.utils.label_colormap(255)
+
+    for label_file in glob.glob(osp.join(args.input_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_cls_file = osp.join(
+                args.output_dir, 'SegmentationClass', base + '.npy')
+            out_clsp_file = osp.join(
+                args.output_dir, 'SegmentationClassPNG', base + '.png')
+            out_clsv_file = osp.join(
+                args.output_dir,
+                'SegmentationClassVisualization',
+                base + '.jpg',
+            )
+            out_ins_file = osp.join(
+                args.output_dir, 'SegmentationObject', base + '.npy')
+            out_insp_file = osp.join(
+                args.output_dir, 'SegmentationObjectPNG', base + '.png')
+            out_insv_file = osp.join(
+                args.output_dir,
+                'SegmentationObjectVisualization',
+                base + '.jpg',
+            )
+
+            data = json.load(f)
+
+            img_file = osp.join(osp.dirname(label_file), data['imagePath'])
+            img = np.asarray(PIL.Image.open(img_file))
+            PIL.Image.fromarray(img).save(out_img_file)
+
+            cls, ins = labelme.utils.shapes_to_label(
+                img_shape=img.shape,
+                shapes=data['shapes'],
+                label_name_to_value=class_name_to_id,
+                type='instance',
+            )
+            ins[cls == -1] = 0  # ignore it.
+
+            # class label
+            labelme.utils.lblsave(out_clsp_file, cls)
+            np.save(out_cls_file, cls)
+            clsv = labelme.utils.draw_label(
+                cls, img, class_names, colormap=colormap)
+            PIL.Image.fromarray(clsv).save(out_clsv_file)
+
+            # instance label
+            labelme.utils.lblsave(out_insp_file, ins)
+            np.save(out_ins_file, ins)
+            instance_ids = np.unique(ins)
+            instance_names = [str(i) for i in range(max(instance_ids) + 1)]
+            insv = labelme.utils.draw_label(ins, img, instance_names)
+            PIL.Image.fromarray(insv).save(out_insv_file)
+
+
+if __name__ == '__main__':
+    main()

+ 22 - 0
DataAnnotation/labelme/examples/instance_segmentation/labels.txt

@@ -0,0 +1,22 @@
+__ignore__
+_background_
+aeroplane
+bicycle
+bird
+boat
+bottle
+bus
+car
+cat
+chair
+cow
+diningtable
+dog
+horse
+motorbike
+person
+potted plant
+sheep
+sofa
+train
+tv/monitor

BIN
DataAnnotation/labelme/examples/primitives/primitives.jpg


+ 140 - 0
DataAnnotation/labelme/examples/primitives/primitives.json

@@ -0,0 +1,140 @@
+{
+  "version": "3.5.0",
+  "flags": {},
+  "shapes": [
+    {
+      "label": "rectangle",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          32,
+          35
+        ],
+        [
+          132,
+          135
+        ]
+      ],
+      "shape_type": "rectangle"
+    },
+    {
+      "label": "circle",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          195,
+          84
+        ],
+        [
+          225,
+          125
+        ]
+      ],
+      "shape_type": "circle"
+    },
+    {
+      "label": "rectangle",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          391,
+          33
+        ],
+        [
+          542,
+          135
+        ]
+      ],
+      "shape_type": "rectangle"
+    },
+    {
+      "label": "polygon",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          69,
+          318
+        ],
+        [
+          45,
+          403
+        ],
+        [
+          173,
+          406
+        ],
+        [
+          198,
+          321
+        ]
+      ],
+      "shape_type": "polygon"
+    },
+    {
+      "label": "line",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          188,
+          178
+        ],
+        [
+          160,
+          224
+        ]
+      ],
+      "shape_type": "line"
+    },
+    {
+      "label": "point",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          345,
+          174
+        ]
+      ],
+      "shape_type": "point"
+    },
+    {
+      "label": "line_strip",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          441,
+          181
+        ],
+        [
+          403,
+          274
+        ],
+        [
+          545,
+          275
+        ]
+      ],
+      "shape_type": "linestrip"
+    }
+  ],
+  "lineColor": [
+    0,
+    255,
+    0,
+    128
+  ],
+  "fillColor": [
+    255,
+    0,
+    0,
+    128
+  ],
+  "imagePath": "primitives.jpg",
+  "imageData": null
+}

BIN
DataAnnotation/labelme/examples/semantic_segmentation/.readme/annotation.jpg


BIN
DataAnnotation/labelme/examples/semantic_segmentation/.readme/draw_label_png.jpg


+ 35 - 0
DataAnnotation/labelme/examples/semantic_segmentation/README.md

@@ -0,0 +1,35 @@
+# Semantic Segmentation Example
+
+## Annotation
+
+```bash
+labelme data_annotated --labels labels.txt --nodata
+```
+
+![](.readme/annotation.jpg)
+
+
+## Convert to VOC-format Dataset
+
+```bash
+# It generates:
+#   - data_dataset_voc/JPEGImages
+#   - data_dataset_voc/SegmentationClass
+#   - data_dataset_voc/SegmentationClassVisualization
+./labelme2voc.py data_annotated data_dataset_voc --labels labels.txt
+```
+
+<img src="data_dataset_voc/JPEGImages/2011_000003.jpg" width="33%" /> <img src="data_dataset_voc/SegmentationClassPNG/2011_000003.png" width="33%" /> <img src="data_dataset_voc/SegmentationClassVisualization/2011_000003.jpg" width="33%" />
+
+Fig 1. JPEG image (left), PNG label (center), JPEG label visualization (right)  
+
+
+Note that the label file contains only very low label values (ex. `0, 4, 14`), and
+`255` indicates the `__ignore__` label value (`-1` in the npy file).  
+You can see the label PNG file by following.
+
+```bash
+labelme_draw_label_png data_dataset_voc/SegmentationClassPNG/2011_000003.png
+```
+
+<img src=".readme/draw_label_png.jpg" width="33%" />

BIN
DataAnnotation/labelme/examples/semantic_segmentation/data_annotated/2011_000003.jpg


+ 481 - 0
DataAnnotation/labelme/examples/semantic_segmentation/data_annotated/2011_000003.json

@@ -0,0 +1,481 @@
+{
+  "shapes": [
+    {
+      "label": "person",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          250.8142292490119,
+          107.33596837944665
+        ],
+        [
+          229.8142292490119,
+          119.33596837944665
+        ],
+        [
+          221.8142292490119,
+          135.33596837944665
+        ],
+        [
+          223.8142292490119,
+          148.33596837944665
+        ],
+        [
+          217.8142292490119,
+          161.33596837944665
+        ],
+        [
+          202.8142292490119,
+          168.33596837944665
+        ],
+        [
+          192.8142292490119,
+          200.33596837944665
+        ],
+        [
+          194.8142292490119,
+          222.33596837944665
+        ],
+        [
+          199.8142292490119,
+          227.33596837944665
+        ],
+        [
+          191.8142292490119,
+          234.33596837944665
+        ],
+        [
+          197.8142292490119,
+          264.3359683794467
+        ],
+        [
+          213.8142292490119,
+          295.3359683794467
+        ],
+        [
+          214.8142292490119,
+          320.3359683794467
+        ],
+        [
+          221.8142292490119,
+          327.3359683794467
+        ],
+        [
+          235.8142292490119,
+          326.3359683794467
+        ],
+        [
+          240.8142292490119,
+          323.3359683794467
+        ],
+        [
+          235.8142292490119,
+          298.3359683794467
+        ],
+        [
+          238.8142292490119,
+          287.3359683794467
+        ],
+        [
+          234.8142292490119,
+          268.3359683794467
+        ],
+        [
+          257.81422924901193,
+          258.3359683794467
+        ],
+        [
+          264.81422924901193,
+          264.3359683794467
+        ],
+        [
+          256.81422924901193,
+          273.3359683794467
+        ],
+        [
+          259.81422924901193,
+          282.3359683794467
+        ],
+        [
+          284.81422924901193,
+          288.3359683794467
+        ],
+        [
+          297.81422924901193,
+          278.3359683794467
+        ],
+        [
+          288.81422924901193,
+          270.3359683794467
+        ],
+        [
+          281.81422924901193,
+          270.3359683794467
+        ],
+        [
+          283.81422924901193,
+          264.3359683794467
+        ],
+        [
+          292.81422924901193,
+          261.3359683794467
+        ],
+        [
+          308.81422924901193,
+          236.33596837944665
+        ],
+        [
+          313.81422924901193,
+          217.33596837944665
+        ],
+        [
+          309.81422924901193,
+          208.33596837944665
+        ],
+        [
+          312.81422924901193,
+          202.33596837944665
+        ],
+        [
+          308.81422924901193,
+          185.33596837944665
+        ],
+        [
+          291.81422924901193,
+          173.33596837944665
+        ],
+        [
+          269.81422924901193,
+          159.33596837944665
+        ],
+        [
+          261.81422924901193,
+          154.33596837944665
+        ],
+        [
+          264.81422924901193,
+          142.33596837944665
+        ],
+        [
+          273.81422924901193,
+          137.33596837944665
+        ],
+        [
+          278.81422924901193,
+          130.33596837944665
+        ],
+        [
+          270.81422924901193,
+          121.33596837944665
+        ]
+      ]
+    },
+    {
+      "label": "person",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          482.81422924901193,
+          85.33596837944665
+        ],
+        [
+          468.81422924901193,
+          90.33596837944665
+        ],
+        [
+          460.81422924901193,
+          110.33596837944665
+        ],
+        [
+          460.81422924901193,
+          127.33596837944665
+        ],
+        [
+          444.81422924901193,
+          137.33596837944665
+        ],
+        [
+          419.81422924901193,
+          153.33596837944665
+        ],
+        [
+          410.81422924901193,
+          163.33596837944665
+        ],
+        [
+          403.81422924901193,
+          168.33596837944665
+        ],
+        [
+          394.81422924901193,
+          170.33596837944665
+        ],
+        [
+          386.81422924901193,
+          168.33596837944665
+        ],
+        [
+          386.81422924901193,
+          184.33596837944665
+        ],
+        [
+          392.81422924901193,
+          182.33596837944665
+        ],
+        [
+          410.81422924901193,
+          187.33596837944665
+        ],
+        [
+          414.81422924901193,
+          192.33596837944665
+        ],
+        [
+          437.81422924901193,
+          189.33596837944665
+        ],
+        [
+          434.81422924901193,
+          204.33596837944665
+        ],
+        [
+          390.81422924901193,
+          195.33596837944665
+        ],
+        [
+          386.81422924901193,
+          195.33596837944665
+        ],
+        [
+          387.81422924901193,
+          208.33596837944665
+        ],
+        [
+          381.81422924901193,
+          212.33596837944665
+        ],
+        [
+          372.81422924901193,
+          212.33596837944665
+        ],
+        [
+          372.81422924901193,
+          216.33596837944665
+        ],
+        [
+          400.81422924901193,
+          270.3359683794467
+        ],
+        [
+          389.81422924901193,
+          272.3359683794467
+        ],
+        [
+          389.81422924901193,
+          274.3359683794467
+        ],
+        [
+          403.81422924901193,
+          282.3359683794467
+        ],
+        [
+          444.81422924901193,
+          283.3359683794467
+        ],
+        [
+          443.81422924901193,
+          259.3359683794467
+        ],
+        [
+          426.81422924901193,
+          244.33596837944665
+        ],
+        [
+          462.81422924901193,
+          256.3359683794467
+        ],
+        [
+          474.81422924901193,
+          270.3359683794467
+        ],
+        [
+          477.81422924901193,
+          280.3359683794467
+        ],
+        [
+          473.81422924901193,
+          289.3359683794467
+        ],
+        [
+          471.81422924901193,
+          296.3359683794467
+        ],
+        [
+          472.81422924901193,
+          317.3359683794467
+        ],
+        [
+          480.81422924901193,
+          332.3359683794467
+        ],
+        [
+          494.81422924901193,
+          335.3359683794467
+        ],
+        [
+          498.81422924901193,
+          329.3359683794467
+        ],
+        [
+          494.81422924901193,
+          308.3359683794467
+        ],
+        [
+          499.81422924901193,
+          297.3359683794467
+        ],
+        [
+          499.81422924901193,
+          90.33596837944665
+        ]
+      ]
+    },
+    {
+      "label": "bottle",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          374.81422924901193,
+          159.33596837944665
+        ],
+        [
+          369.81422924901193,
+          170.33596837944665
+        ],
+        [
+          369.81422924901193,
+          210.33596837944665
+        ],
+        [
+          375.81422924901193,
+          212.33596837944665
+        ],
+        [
+          387.81422924901193,
+          209.33596837944665
+        ],
+        [
+          385.81422924901193,
+          185.33596837944665
+        ],
+        [
+          385.81422924901193,
+          168.33596837944665
+        ],
+        [
+          385.81422924901193,
+          165.33596837944665
+        ],
+        [
+          382.81422924901193,
+          159.33596837944665
+        ]
+      ]
+    },
+    {
+      "label": "person",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          370.81422924901193,
+          170.33596837944665
+        ],
+        [
+          366.81422924901193,
+          173.33596837944665
+        ],
+        [
+          365.81422924901193,
+          182.33596837944665
+        ],
+        [
+          368.81422924901193,
+          185.33596837944665
+        ]
+      ]
+    },
+    {
+      "label": "__ignore__",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          338.81422924901193,
+          266.3359683794467
+        ],
+        [
+          313.81422924901193,
+          269.3359683794467
+        ],
+        [
+          297.81422924901193,
+          277.3359683794467
+        ],
+        [
+          282.81422924901193,
+          288.3359683794467
+        ],
+        [
+          273.81422924901193,
+          302.3359683794467
+        ],
+        [
+          272.81422924901193,
+          320.3359683794467
+        ],
+        [
+          279.81422924901193,
+          337.3359683794467
+        ],
+        [
+          428.81422924901193,
+          337.3359683794467
+        ],
+        [
+          432.81422924901193,
+          316.3359683794467
+        ],
+        [
+          423.81422924901193,
+          296.3359683794467
+        ],
+        [
+          403.81422924901193,
+          283.3359683794467
+        ],
+        [
+          370.81422924901193,
+          270.3359683794467
+        ]
+      ]
+    }
+  ],
+  "lineColor": [
+    0,
+    255,
+    0,
+    128
+  ],
+  "fillColor": [
+    255,
+    0,
+    0,
+    128
+  ],
+  "imagePath": "2011_000003.jpg",
+  "imageData": null
+}

BIN
DataAnnotation/labelme/examples/semantic_segmentation/data_annotated/2011_000006.jpg


+ 528 - 0
DataAnnotation/labelme/examples/semantic_segmentation/data_annotated/2011_000006.json

@@ -0,0 +1,528 @@
+{
+  "shapes": [
+    {
+      "label": "person",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          204.936170212766,
+          108.56382978723406
+        ],
+        [
+          183.936170212766,
+          141.56382978723406
+        ],
+        [
+          166.936170212766,
+          150.56382978723406
+        ],
+        [
+          108.93617021276599,
+          203.56382978723406
+        ],
+        [
+          92.93617021276599,
+          228.56382978723406
+        ],
+        [
+          95.93617021276599,
+          244.56382978723406
+        ],
+        [
+          105.93617021276599,
+          244.56382978723406
+        ],
+        [
+          116.93617021276599,
+          223.56382978723406
+        ],
+        [
+          163.936170212766,
+          187.56382978723406
+        ],
+        [
+          147.936170212766,
+          212.56382978723406
+        ],
+        [
+          117.93617021276599,
+          222.56382978723406
+        ],
+        [
+          108.93617021276599,
+          243.56382978723406
+        ],
+        [
+          100.93617021276599,
+          325.56382978723406
+        ],
+        [
+          135.936170212766,
+          329.56382978723406
+        ],
+        [
+          148.936170212766,
+          319.56382978723406
+        ],
+        [
+          150.936170212766,
+          295.56382978723406
+        ],
+        [
+          169.936170212766,
+          272.56382978723406
+        ],
+        [
+          171.936170212766,
+          249.56382978723406
+        ],
+        [
+          178.936170212766,
+          246.56382978723406
+        ],
+        [
+          186.936170212766,
+          225.56382978723406
+        ],
+        [
+          214.936170212766,
+          219.56382978723406
+        ],
+        [
+          242.936170212766,
+          157.56382978723406
+        ],
+        [
+          228.936170212766,
+          146.56382978723406
+        ],
+        [
+          228.936170212766,
+          125.56382978723406
+        ],
+        [
+          216.936170212766,
+          112.56382978723406
+        ]
+      ]
+    },
+    {
+      "label": "person",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          271.936170212766,
+          109.56382978723406
+        ],
+        [
+          249.936170212766,
+          110.56382978723406
+        ],
+        [
+          244.936170212766,
+          150.56382978723406
+        ],
+        [
+          215.936170212766,
+          219.56382978723406
+        ],
+        [
+          208.936170212766,
+          245.56382978723406
+        ],
+        [
+          214.936170212766,
+          220.56382978723406
+        ],
+        [
+          188.936170212766,
+          227.56382978723406
+        ],
+        [
+          170.936170212766,
+          246.56382978723406
+        ],
+        [
+          170.936170212766,
+          275.56382978723406
+        ],
+        [
+          221.936170212766,
+          278.56382978723406
+        ],
+        [
+          233.936170212766,
+          259.56382978723406
+        ],
+        [
+          246.936170212766,
+          253.56382978723406
+        ],
+        [
+          245.936170212766,
+          256.56382978723406
+        ],
+        [
+          242.936170212766,
+          251.56382978723406
+        ],
+        [
+          262.936170212766,
+          256.56382978723406
+        ],
+        [
+          304.936170212766,
+          226.56382978723406
+        ],
+        [
+          297.936170212766,
+          199.56382978723406
+        ],
+        [
+          308.936170212766,
+          164.56382978723406
+        ],
+        [
+          296.936170212766,
+          148.56382978723406
+        ]
+      ]
+    },
+    {
+      "label": "person",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          308.936170212766,
+          115.56382978723406
+        ],
+        [
+          298.936170212766,
+          145.56382978723406
+        ],
+        [
+          309.936170212766,
+          166.56382978723406
+        ],
+        [
+          297.936170212766,
+          200.56382978723406
+        ],
+        [
+          305.936170212766,
+          228.56382978723406
+        ],
+        [
+          262.936170212766,
+          258.56382978723406
+        ],
+        [
+          252.936170212766,
+          284.56382978723406
+        ],
+        [
+          272.936170212766,
+          291.56382978723406
+        ],
+        [
+          281.936170212766,
+          250.56382978723406
+        ],
+        [
+          326.936170212766,
+          235.56382978723406
+        ],
+        [
+          351.936170212766,
+          239.56382978723406
+        ],
+        [
+          365.936170212766,
+          223.56382978723406
+        ],
+        [
+          371.936170212766,
+          187.56382978723406
+        ],
+        [
+          353.936170212766,
+          168.56382978723406
+        ],
+        [
+          344.936170212766,
+          143.56382978723406
+        ],
+        [
+          336.936170212766,
+          115.56382978723406
+        ]
+      ]
+    },
+    {
+      "label": "chair",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          308.936170212766,
+          242.56382978723406
+        ],
+        [
+          281.936170212766,
+          251.56382978723406
+        ],
+        [
+          270.936170212766,
+          287.56382978723406
+        ],
+        [
+          174.936170212766,
+          275.56382978723406
+        ],
+        [
+          148.936170212766,
+          296.56382978723406
+        ],
+        [
+          150.936170212766,
+          319.56382978723406
+        ],
+        [
+          159.936170212766,
+          328.56382978723406
+        ],
+        [
+          164.77327127659578,
+          375.0
+        ],
+        [
+          485.936170212766,
+          373.56382978723406
+        ],
+        [
+          497.936170212766,
+          336.56382978723406
+        ],
+        [
+          497.936170212766,
+          202.56382978723406
+        ],
+        [
+          453.936170212766,
+          193.56382978723406
+        ],
+        [
+          434.936170212766,
+          212.56382978723406
+        ],
+        [
+          367.936170212766,
+          224.56382978723406
+        ],
+        [
+          350.936170212766,
+          241.56382978723406
+        ]
+      ]
+    },
+    {
+      "label": "person",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          425.936170212766,
+          82.56382978723406
+        ],
+        [
+          404.936170212766,
+          109.56382978723406
+        ],
+        [
+          400.936170212766,
+          114.56382978723406
+        ],
+        [
+          437.936170212766,
+          114.56382978723406
+        ],
+        [
+          448.936170212766,
+          102.56382978723406
+        ],
+        [
+          446.936170212766,
+          91.56382978723406
+        ]
+      ]
+    },
+    {
+      "label": "__ignore__",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          457.936170212766,
+          85.56382978723406
+        ],
+        [
+          439.936170212766,
+          117.56382978723406
+        ],
+        [
+          477.936170212766,
+          117.56382978723406
+        ],
+        [
+          474.936170212766,
+          87.56382978723406
+        ]
+      ]
+    },
+    {
+      "label": "sofa",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          183.936170212766,
+          140.56382978723406
+        ],
+        [
+          125.93617021276599,
+          140.56382978723406
+        ],
+        [
+          110.93617021276599,
+          187.56382978723406
+        ],
+        [
+          22.936170212765987,
+          199.56382978723406
+        ],
+        [
+          18.936170212765987,
+          218.56382978723406
+        ],
+        [
+          22.936170212765987,
+          234.56382978723406
+        ],
+        [
+          93.93617021276599,
+          239.56382978723406
+        ],
+        [
+          91.93617021276599,
+          229.56382978723406
+        ],
+        [
+          110.93617021276599,
+          203.56382978723406
+        ]
+      ]
+    },
+    {
+      "label": "sofa",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          103.93617021276599,
+          290.56382978723406
+        ],
+        [
+          58.93617021276599,
+          303.56382978723406
+        ],
+        [
+          97.93617021276599,
+          311.56382978723406
+        ]
+      ]
+    },
+    {
+      "label": "sofa",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          348.936170212766,
+          146.56382978723406
+        ],
+        [
+          472.936170212766,
+          149.56382978723406
+        ],
+        [
+          477.936170212766,
+          162.56382978723406
+        ],
+        [
+          471.936170212766,
+          196.56382978723406
+        ],
+        [
+          453.936170212766,
+          192.56382978723406
+        ],
+        [
+          434.936170212766,
+          213.56382978723406
+        ],
+        [
+          368.936170212766,
+          226.56382978723406
+        ],
+        [
+          375.936170212766,
+          187.56382978723406
+        ],
+        [
+          353.936170212766,
+          164.56382978723406
+        ]
+      ]
+    },
+    {
+      "label": "sofa",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          246.936170212766,
+          252.56382978723406
+        ],
+        [
+          219.936170212766,
+          277.56382978723406
+        ],
+        [
+          254.936170212766,
+          287.56382978723406
+        ],
+        [
+          261.936170212766,
+          256.56382978723406
+        ]
+      ]
+    }
+  ],
+  "lineColor": [
+    0,
+    255,
+    0,
+    128
+  ],
+  "fillColor": [
+    255,
+    0,
+    0,
+    128
+  ],
+  "imagePath": "2011_000006.jpg",
+  "imageData": null
+}

BIN
DataAnnotation/labelme/examples/semantic_segmentation/data_annotated/2011_000025.jpg


+ 215 - 0
DataAnnotation/labelme/examples/semantic_segmentation/data_annotated/2011_000025.json

@@ -0,0 +1,215 @@
+{
+  "shapes": [
+    {
+      "label": "bus",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          260.936170212766,
+          22.563829787234056
+        ],
+        [
+          193.936170212766,
+          19.563829787234056
+        ],
+        [
+          124.93617021276599,
+          39.563829787234056
+        ],
+        [
+          89.93617021276599,
+          101.56382978723406
+        ],
+        [
+          81.93617021276599,
+          150.56382978723406
+        ],
+        [
+          108.93617021276599,
+          145.56382978723406
+        ],
+        [
+          88.93617021276599,
+          244.56382978723406
+        ],
+        [
+          89.93617021276599,
+          322.56382978723406
+        ],
+        [
+          116.93617021276599,
+          367.56382978723406
+        ],
+        [
+          158.936170212766,
+          368.56382978723406
+        ],
+        [
+          165.936170212766,
+          337.56382978723406
+        ],
+        [
+          347.936170212766,
+          335.56382978723406
+        ],
+        [
+          349.936170212766,
+          369.56382978723406
+        ],
+        [
+          391.936170212766,
+          373.56382978723406
+        ],
+        [
+          403.936170212766,
+          335.56382978723406
+        ],
+        [
+          425.936170212766,
+          332.56382978723406
+        ],
+        [
+          421.936170212766,
+          281.56382978723406
+        ],
+        [
+          428.936170212766,
+          252.56382978723406
+        ],
+        [
+          428.936170212766,
+          236.56382978723406
+        ],
+        [
+          409.936170212766,
+          220.56382978723406
+        ],
+        [
+          409.936170212766,
+          150.56382978723406
+        ],
+        [
+          430.936170212766,
+          143.56382978723406
+        ],
+        [
+          433.936170212766,
+          112.56382978723406
+        ],
+        [
+          431.936170212766,
+          96.56382978723406
+        ],
+        [
+          408.936170212766,
+          90.56382978723406
+        ],
+        [
+          395.936170212766,
+          50.563829787234056
+        ],
+        [
+          338.936170212766,
+          25.563829787234056
+        ]
+      ]
+    },
+    {
+      "label": "bus",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          88.93617021276599,
+          115.56382978723406
+        ],
+        [
+          0.9361702127659877,
+          96.56382978723406
+        ],
+        [
+          0.0,
+          251.968085106388
+        ],
+        [
+          0.9361702127659877,
+          265.56382978723406
+        ],
+        [
+          27.936170212765987,
+          265.56382978723406
+        ],
+        [
+          29.936170212765987,
+          283.56382978723406
+        ],
+        [
+          63.93617021276599,
+          281.56382978723406
+        ],
+        [
+          89.93617021276599,
+          252.56382978723406
+        ],
+        [
+          100.93617021276599,
+          183.56382978723406
+        ],
+        [
+          108.93617021276599,
+          145.56382978723406
+        ],
+        [
+          81.93617021276599,
+          151.56382978723406
+        ]
+      ]
+    },
+    {
+      "label": "car",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          413.936170212766,
+          168.56382978723406
+        ],
+        [
+          497.936170212766,
+          168.56382978723406
+        ],
+        [
+          497.936170212766,
+          256.56382978723406
+        ],
+        [
+          431.936170212766,
+          258.56382978723406
+        ],
+        [
+          430.936170212766,
+          236.56382978723406
+        ],
+        [
+          408.936170212766,
+          218.56382978723406
+        ]
+      ]
+    }
+  ],
+  "lineColor": [
+    0,
+    255,
+    0,
+    128
+  ],
+  "fillColor": [
+    255,
+    0,
+    0,
+    128
+  ],
+  "imagePath": "2011_000025.jpg",
+  "imageData": null
+}

BIN
DataAnnotation/labelme/examples/semantic_segmentation/data_dataset_voc/JPEGImages/2011_000003.jpg


BIN
DataAnnotation/labelme/examples/semantic_segmentation/data_dataset_voc/JPEGImages/2011_000006.jpg


BIN
DataAnnotation/labelme/examples/semantic_segmentation/data_dataset_voc/JPEGImages/2011_000025.jpg


BIN
DataAnnotation/labelme/examples/semantic_segmentation/data_dataset_voc/SegmentationClass/2011_000003.npy


BIN
DataAnnotation/labelme/examples/semantic_segmentation/data_dataset_voc/SegmentationClass/2011_000006.npy


BIN
DataAnnotation/labelme/examples/semantic_segmentation/data_dataset_voc/SegmentationClass/2011_000025.npy


BIN
DataAnnotation/labelme/examples/semantic_segmentation/data_dataset_voc/SegmentationClassPNG/2011_000003.png


BIN
DataAnnotation/labelme/examples/semantic_segmentation/data_dataset_voc/SegmentationClassPNG/2011_000006.png


BIN
DataAnnotation/labelme/examples/semantic_segmentation/data_dataset_voc/SegmentationClassPNG/2011_000025.png


BIN
DataAnnotation/labelme/examples/semantic_segmentation/data_dataset_voc/SegmentationClassVisualization/2011_000003.jpg


BIN
DataAnnotation/labelme/examples/semantic_segmentation/data_dataset_voc/SegmentationClassVisualization/2011_000006.jpg


BIN
DataAnnotation/labelme/examples/semantic_segmentation/data_dataset_voc/SegmentationClassVisualization/2011_000025.jpg


+ 21 - 0
DataAnnotation/labelme/examples/semantic_segmentation/data_dataset_voc/class_names.txt

@@ -0,0 +1,21 @@
+_background_
+aeroplane
+bicycle
+bird
+boat
+bottle
+bus
+car
+cat
+chair
+cow
+diningtable
+dog
+horse
+motorbike
+person
+potted plant
+sheep
+sofa
+train
+tv/monitor

+ 95 - 0
DataAnnotation/labelme/examples/semantic_segmentation/labelme2voc.py

@@ -0,0 +1,95 @@
+#!/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('input_dir', help='input annotated directory')
+    parser.add_argument('output_dir', help='output dataset directory')
+    parser.add_argument('--labels', help='labels file', required=True)
+    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, 'SegmentationClass'))
+    os.makedirs(osp.join(args.output_dir, 'SegmentationClassPNG'))
+    os.makedirs(osp.join(args.output_dir, 'SegmentationClassVisualization'))
+    print('Creating dataset:', args.output_dir)
+
+    class_names = []
+    class_name_to_id = {}
+    for i, line in enumerate(open(args.labels).readlines()):
+        class_id = i - 1  # starts with -1
+        class_name = line.strip()
+        class_name_to_id[class_name] = class_id
+        if class_id == -1:
+            assert class_name == '__ignore__'
+            continue
+        elif class_id == 0:
+            assert class_name == '_background_'
+        class_names.append(class_name)
+    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)
+
+    colormap = labelme.utils.label_colormap(255)
+
+    for label_file in glob.glob(osp.join(args.input_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_lbl_file = osp.join(
+                args.output_dir, 'SegmentationClass', base + '.npy')
+            out_png_file = osp.join(
+                args.output_dir, 'SegmentationClassPNG', base + '.png')
+            out_viz_file = osp.join(
+                args.output_dir,
+                'SegmentationClassVisualization',
+                base + '.jpg',
+            )
+
+            data = json.load(f)
+
+            img_file = osp.join(osp.dirname(label_file), data['imagePath'])
+            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,
+            )
+            labelme.utils.lblsave(out_png_file, lbl)
+
+            np.save(out_lbl_file, lbl)
+
+            viz = labelme.utils.draw_label(
+                lbl, img, class_names, colormap=colormap)
+            PIL.Image.fromarray(viz).save(out_viz_file)
+
+
+if __name__ == '__main__':
+    main()

+ 22 - 0
DataAnnotation/labelme/examples/semantic_segmentation/labels.txt

@@ -0,0 +1,22 @@
+__ignore__
+_background_
+aeroplane
+bicycle
+bird
+boat
+bottle
+bus
+car
+cat
+chair
+cow
+diningtable
+dog
+horse
+motorbike
+person
+potted plant
+sheep
+sofa
+train
+tv/monitor

BIN
DataAnnotation/labelme/examples/tutorial/.readme/annotation.jpg


BIN
DataAnnotation/labelme/examples/tutorial/.readme/draw_json.jpg


BIN
DataAnnotation/labelme/examples/tutorial/.readme/draw_label_png.jpg


+ 66 - 0
DataAnnotation/labelme/examples/tutorial/README.md

@@ -0,0 +1,66 @@
+# Tutorial (Single Image Example)
+
+## Annotation
+
+```bash
+labelme apc2016_obj3.jpg -O apc2016_obj3.json
+```
+
+![](.readme/annotation.jpg)
+
+
+## Visualization
+
+To view the json file quickly, you can use utility script:
+
+```bash
+labelme_draw_json apc2016_obj3.json
+```
+
+<img src=".readme/draw_json.jpg" width="70%" />
+
+
+## Convert to Dataset
+
+To convert the json to set of image and label, you can run following:
+
+
+```bash
+labelme_json_to_dataset apc2016_obj3.json -o apc2016_obj3_json
+```
+
+It generates standard files from the JSON file.
+
+- [img.png](apc2016_obj3_json/img.png): Image file.
+- [label.png](apc2016_obj3_json/label.png): uint8 label file.
+- [label_viz.png](apc2016_obj3_json/label_viz.png): Visualization of `label.png`.
+- [label_names.txt](apc2016_obj3_json/label_names.txt): Label names for values in `label.png`.
+
+## How to load label PNG file?
+
+Note that loading `label.png` is a bit difficult
+(`scipy.misc.imread`, `skimage.io.imread` may not work correctly),
+and please use `PIL.Image.open` to avoid unexpected behavior:
+
+```python
+# see load_label_png.py also.
+>>> import numpy as np
+>>> import PIL.Image
+
+>>> label_png = 'apc2016_obj3_json/label.png'
+>>> lbl = np.asarray(PIL.Image.open(label_png))
+>>> print(lbl.dtype)
+dtype('uint8')
+>>> np.unique(lbl)
+array([0, 1, 2, 3], dtype=uint8)
+>>> lbl.shape
+(907, 1210)
+```
+
+Also, you can see the label PNG file by:
+
+```python
+labelme_draw_label_png apc2016_obj3_json/label.png
+```
+
+<img src=".readme/draw_label_png.jpg" width="35%" />

BIN
DataAnnotation/labelme/examples/tutorial/apc2016_obj3.jpg


File diff suppressed because it is too large
+ 248 - 0
DataAnnotation/labelme/examples/tutorial/apc2016_obj3.json


BIN
DataAnnotation/labelme/examples/tutorial/apc2016_obj3_json/img.png


+ 6 - 0
DataAnnotation/labelme/examples/tutorial/apc2016_obj3_json/info.yaml

@@ -0,0 +1,6 @@
+label_names:
+- _background_
+- shelf
+- highland_6539_self_stick_notes
+- mead_index_cards
+- kong_air_dog_squeakair_tennis_ball

BIN
DataAnnotation/labelme/examples/tutorial/apc2016_obj3_json/label.png


+ 5 - 0
DataAnnotation/labelme/examples/tutorial/apc2016_obj3_json/label_names.txt

@@ -0,0 +1,5 @@
+_background_
+shelf
+highland_6539_self_stick_notes
+mead_index_cards
+kong_air_dog_squeakair_tennis_ball

BIN
DataAnnotation/labelme/examples/tutorial/apc2016_obj3_json/label_viz.png


+ 37 - 0
DataAnnotation/labelme/examples/tutorial/load_label_png.py

@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+
+from __future__ import print_function
+
+import os.path as osp
+
+import numpy as np
+import PIL.Image
+
+
+here = osp.dirname(osp.abspath(__file__))
+
+
+def main():
+    label_png = osp.join(here, 'apc2016_obj3_json/label.png')
+    print('Loading:', label_png)
+    print()
+
+    lbl = np.asarray(PIL.Image.open(label_png))
+    labels = np.unique(lbl)
+
+    label_names_txt = osp.join(here, 'apc2016_obj3_json/label_names.txt')
+    label_names = [name.strip() for name in open(label_names_txt)]
+    print('# of labels:', len(labels))
+    print('# of label_names:', len(label_names))
+    if len(labels) != len(label_names):
+        print('Number of unique labels and label_names must be same.')
+        quit(1)
+    print()
+
+    print('label: label_name')
+    for label, label_name in zip(labels, label_names):
+        print('%d: %s' % (label, label_name))
+
+
+if __name__ == '__main__':
+    main()

BIN
DataAnnotation/labelme/examples/video_annotation/.readme/00000100.jpg


BIN
DataAnnotation/labelme/examples/video_annotation/.readme/00000101.jpg


BIN
DataAnnotation/labelme/examples/video_annotation/.readme/data_annotated.gif


+ 31 - 0
DataAnnotation/labelme/examples/video_annotation/README.md

@@ -0,0 +1,31 @@
+# Video Annotation Example
+
+
+## Annotation
+
+```bash
+labelme data_annotated --labels labels.txt --nodata --keep-prev
+```
+
+<img src=".readme/00000100.jpg" width="49%" /> <img src=".readme/00000101.jpg" width="49%" />
+
+*Fig 1. Video annotation example. A frame (left), The next frame (right).*
+
+
+<img src=".readme/data_annotated.gif" width="98%" />
+
+*Fig 2. Visualization of video semantic segmentation.*
+
+
+## How to Convert a Video File to Images for Annotation?
+
+```bash
+# Download and install software for converting a video file (MP4) to images
+wget https://raw.githubusercontent.com/wkentaro/dotfiles/f3c5ad1f47834818d4f123c36ed59a5943709518/local/bin/video_to_images
+pip install imageio imageio-ffmpeg tqdm
+
+python video_to_images your_video.mp4  # this creates your_video/ directory
+ls your_video/
+
+labelme your_video/
+```

BIN
DataAnnotation/labelme/examples/video_annotation/data_annotated/00000100.jpg


+ 160 - 0
DataAnnotation/labelme/examples/video_annotation/data_annotated/00000100.json

@@ -0,0 +1,160 @@
+{
+  "flags": {},
+  "shapes": [
+    {
+      "label": "track",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          634,
+          204
+        ],
+        [
+          604,
+          275
+        ],
+        [
+          603,
+          340
+        ],
+        [
+          622,
+          363
+        ],
+        [
+          639,
+          363
+        ],
+        [
+          649,
+          354
+        ],
+        [
+          682,
+          383
+        ],
+        [
+          733,
+          390
+        ],
+        [
+          748,
+          364
+        ],
+        [
+          827,
+          359
+        ],
+        [
+          829,
+          250
+        ],
+        [
+          800,
+          194
+        ],
+        [
+          775,
+          185
+        ],
+        [
+          740,
+          199
+        ]
+      ]
+    },
+    {
+      "label": "track",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          860,
+          190
+        ],
+        [
+          997,
+          186
+        ],
+        [
+          998,
+          305
+        ],
+        [
+          924,
+          320
+        ],
+        [
+          905,
+          352
+        ],
+        [
+          877,
+          353
+        ],
+        [
+          869,
+          245
+        ],
+        [
+          879,
+          222
+        ]
+      ]
+    },
+    {
+      "label": "car",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          924,
+          321
+        ],
+        [
+          905,
+          352
+        ],
+        [
+          909,
+          388
+        ],
+        [
+          936,
+          404
+        ],
+        [
+          959,
+          411
+        ],
+        [
+          966,
+          431
+        ],
+        [
+          1000.0,
+          432.0
+        ],
+        [
+          1000.0,
+          306.0
+        ]
+      ]
+    }
+  ],
+  "lineColor": [
+    0,
+    255,
+    0,
+    128
+  ],
+  "fillColor": [
+    255,
+    0,
+    0,
+    128
+  ],
+  "imagePath": "00000100.jpg",
+  "imageData": null
+}

BIN
DataAnnotation/labelme/examples/video_annotation/data_annotated/00000101.jpg


+ 160 - 0
DataAnnotation/labelme/examples/video_annotation/data_annotated/00000101.json

@@ -0,0 +1,160 @@
+{
+  "flags": {},
+  "shapes": [
+    {
+      "label": "track",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          614.0,
+          204.0
+        ],
+        [
+          584.0,
+          275.0
+        ],
+        [
+          583.0,
+          340.0
+        ],
+        [
+          602.0,
+          363.0
+        ],
+        [
+          619.0,
+          363.0
+        ],
+        [
+          629.0,
+          354.0
+        ],
+        [
+          662.0,
+          383.0
+        ],
+        [
+          713.0,
+          390.0
+        ],
+        [
+          728.0,
+          364.0
+        ],
+        [
+          827.0,
+          358.0
+        ],
+        [
+          825.0,
+          249.0
+        ],
+        [
+          801.0,
+          200.0
+        ],
+        [
+          757.0,
+          194.0
+        ],
+        [
+          720.0,
+          199.0
+        ]
+      ]
+    },
+    {
+      "label": "track",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          860.0,
+          190.0
+        ],
+        [
+          997.0,
+          186.0
+        ],
+        [
+          998.0,
+          305.0
+        ],
+        [
+          924.0,
+          320.0
+        ],
+        [
+          905.0,
+          352.0
+        ],
+        [
+          877.0,
+          353.0
+        ],
+        [
+          869.0,
+          245.0
+        ],
+        [
+          879.0,
+          222.0
+        ]
+      ]
+    },
+    {
+      "label": "car",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          924.0,
+          321.0
+        ],
+        [
+          905.0,
+          352.0
+        ],
+        [
+          909.0,
+          388.0
+        ],
+        [
+          936.0,
+          404.0
+        ],
+        [
+          959.0,
+          411.0
+        ],
+        [
+          966.0,
+          431.0
+        ],
+        [
+          1000.0,
+          432.0
+        ],
+        [
+          1000.0,
+          306.0
+        ]
+      ]
+    }
+  ],
+  "lineColor": [
+    0,
+    255,
+    0,
+    128
+  ],
+  "fillColor": [
+    255,
+    0,
+    0,
+    128
+  ],
+  "imagePath": "00000101.jpg",
+  "imageData": null
+}

BIN
DataAnnotation/labelme/examples/video_annotation/data_annotated/00000102.jpg


+ 160 - 0
DataAnnotation/labelme/examples/video_annotation/data_annotated/00000102.json

@@ -0,0 +1,160 @@
+{
+  "flags": {},
+  "shapes": [
+    {
+      "label": "track",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          593.0,
+          204.0
+        ],
+        [
+          563.0,
+          275.0
+        ],
+        [
+          562.0,
+          340.0
+        ],
+        [
+          581.0,
+          363.0
+        ],
+        [
+          598.0,
+          363.0
+        ],
+        [
+          608.0,
+          354.0
+        ],
+        [
+          641.0,
+          383.0
+        ],
+        [
+          692.0,
+          390.0
+        ],
+        [
+          707.0,
+          364.0
+        ],
+        [
+          827.0,
+          358.0
+        ],
+        [
+          823.0,
+          243.0
+        ],
+        [
+          802.0,
+          199.0
+        ],
+        [
+          736.0,
+          194.0
+        ],
+        [
+          699.0,
+          199.0
+        ]
+      ]
+    },
+    {
+      "label": "track",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          860.0,
+          190.0
+        ],
+        [
+          997.0,
+          186.0
+        ],
+        [
+          998.0,
+          305.0
+        ],
+        [
+          924.0,
+          320.0
+        ],
+        [
+          905.0,
+          352.0
+        ],
+        [
+          877.0,
+          353.0
+        ],
+        [
+          869.0,
+          245.0
+        ],
+        [
+          879.0,
+          222.0
+        ]
+      ]
+    },
+    {
+      "label": "car",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          924.0,
+          321.0
+        ],
+        [
+          905.0,
+          352.0
+        ],
+        [
+          909.0,
+          388.0
+        ],
+        [
+          936.0,
+          404.0
+        ],
+        [
+          959.0,
+          411.0
+        ],
+        [
+          966.0,
+          431.0
+        ],
+        [
+          1000.0,
+          432.0
+        ],
+        [
+          1000.0,
+          306.0
+        ]
+      ]
+    }
+  ],
+  "lineColor": [
+    0,
+    255,
+    0,
+    128
+  ],
+  "fillColor": [
+    255,
+    0,
+    0,
+    128
+  ],
+  "imagePath": "00000102.jpg",
+  "imageData": null
+}

BIN
DataAnnotation/labelme/examples/video_annotation/data_annotated/00000103.jpg


+ 160 - 0
DataAnnotation/labelme/examples/video_annotation/data_annotated/00000103.json

@@ -0,0 +1,160 @@
+{
+  "flags": {},
+  "shapes": [
+    {
+      "label": "track",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          573.0,
+          207.0
+        ],
+        [
+          543.0,
+          278.0
+        ],
+        [
+          542.0,
+          343.0
+        ],
+        [
+          561.0,
+          366.0
+        ],
+        [
+          578.0,
+          366.0
+        ],
+        [
+          588.0,
+          357.0
+        ],
+        [
+          621.0,
+          386.0
+        ],
+        [
+          672.0,
+          393.0
+        ],
+        [
+          687.0,
+          367.0
+        ],
+        [
+          829.0,
+          354.0
+        ],
+        [
+          821.0,
+          236.0
+        ],
+        [
+          801.0,
+          199.0
+        ],
+        [
+          716.0,
+          197.0
+        ],
+        [
+          679.0,
+          202.0
+        ]
+      ]
+    },
+    {
+      "label": "track",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          860.0,
+          190.0
+        ],
+        [
+          997.0,
+          186.0
+        ],
+        [
+          998.0,
+          305.0
+        ],
+        [
+          924.0,
+          320.0
+        ],
+        [
+          905.0,
+          352.0
+        ],
+        [
+          877.0,
+          353.0
+        ],
+        [
+          869.0,
+          245.0
+        ],
+        [
+          879.0,
+          222.0
+        ]
+      ]
+    },
+    {
+      "label": "car",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          924.0,
+          321.0
+        ],
+        [
+          905.0,
+          352.0
+        ],
+        [
+          909.0,
+          388.0
+        ],
+        [
+          936.0,
+          404.0
+        ],
+        [
+          959.0,
+          411.0
+        ],
+        [
+          966.0,
+          431.0
+        ],
+        [
+          1000.0,
+          432.0
+        ],
+        [
+          1000.0,
+          306.0
+        ]
+      ]
+    }
+  ],
+  "lineColor": [
+    0,
+    255,
+    0,
+    128
+  ],
+  "fillColor": [
+    255,
+    0,
+    0,
+    128
+  ],
+  "imagePath": "00000103.jpg",
+  "imageData": null
+}

BIN
DataAnnotation/labelme/examples/video_annotation/data_annotated/00000104.jpg


+ 160 - 0
DataAnnotation/labelme/examples/video_annotation/data_annotated/00000104.json

@@ -0,0 +1,160 @@
+{
+  "flags": {},
+  "shapes": [
+    {
+      "label": "track",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          556.0,
+          201.0
+        ],
+        [
+          528.0,
+          277.0
+        ],
+        [
+          524.0,
+          342.0
+        ],
+        [
+          528.0,
+          361.0
+        ],
+        [
+          563.0,
+          365.0
+        ],
+        [
+          573.0,
+          356.0
+        ],
+        [
+          606.0,
+          385.0
+        ],
+        [
+          657.0,
+          392.0
+        ],
+        [
+          672.0,
+          366.0
+        ],
+        [
+          825.0,
+          354.0
+        ],
+        [
+          826.0,
+          238.0
+        ],
+        [
+          801.0,
+          202.0
+        ],
+        [
+          701.0,
+          196.0
+        ],
+        [
+          664.0,
+          201.0
+        ]
+      ]
+    },
+    {
+      "label": "track",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          860.0,
+          190.0
+        ],
+        [
+          997.0,
+          186.0
+        ],
+        [
+          998.0,
+          305.0
+        ],
+        [
+          924.0,
+          320.0
+        ],
+        [
+          905.0,
+          352.0
+        ],
+        [
+          874.0,
+          354.0
+        ],
+        [
+          869.0,
+          245.0
+        ],
+        [
+          879.0,
+          222.0
+        ]
+      ]
+    },
+    {
+      "label": "car",
+      "line_color": null,
+      "fill_color": null,
+      "points": [
+        [
+          924.0,
+          321.0
+        ],
+        [
+          905.0,
+          352.0
+        ],
+        [
+          909.0,
+          388.0
+        ],
+        [
+          936.0,
+          404.0
+        ],
+        [
+          959.0,
+          411.0
+        ],
+        [
+          966.0,
+          431.0
+        ],
+        [
+          1000.0,
+          432.0
+        ],
+        [
+          1000.0,
+          306.0
+        ]
+      ]
+    }
+  ],
+  "lineColor": [
+    0,
+    255,
+    0,
+    128
+  ],
+  "fillColor": [
+    255,
+    0,
+    0,
+    128
+  ],
+  "imagePath": "00000104.jpg",
+  "imageData": null
+}

BIN
DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/JPEGImages/00000100.jpg


BIN
DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/JPEGImages/00000101.jpg


BIN
DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/JPEGImages/00000102.jpg


BIN
DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/JPEGImages/00000103.jpg


BIN
DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/JPEGImages/00000104.jpg


BIN
DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/SegmentationClass/00000100.npy


BIN
DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/SegmentationClass/00000101.npy


BIN
DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/SegmentationClass/00000102.npy


BIN
DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/SegmentationClass/00000103.npy


BIN
DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/SegmentationClass/00000104.npy


BIN
DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/SegmentationClassPNG/00000100.png


BIN
DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/SegmentationClassPNG/00000101.png


BIN
DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/SegmentationClassPNG/00000102.png


BIN
DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/SegmentationClassPNG/00000103.png


BIN
DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/SegmentationClassPNG/00000104.png


BIN
DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/SegmentationClassVisualization/00000100.jpg


BIN
DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/SegmentationClassVisualization/00000101.jpg


BIN
DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/SegmentationClassVisualization/00000102.jpg


BIN
DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/SegmentationClassVisualization/00000103.jpg


BIN
DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/SegmentationClassVisualization/00000104.jpg


+ 3 - 0
DataAnnotation/labelme/examples/video_annotation/data_dataset_voc/class_names.txt

@@ -0,0 +1,3 @@
+_background_
+car
+track

+ 1 - 0
DataAnnotation/labelme/examples/video_annotation/labelme2voc.py

@@ -0,0 +1 @@
+../semantic_segmentation/labelme2voc.py

+ 4 - 0
DataAnnotation/labelme/examples/video_annotation/labels.txt

@@ -0,0 +1,4 @@
+__ignore__
+_background_
+car
+track

+ 26 - 0
DataAnnotation/labelme/github2pypi/.travis.yml

@@ -0,0 +1,26 @@
+sudo: false
+
+cache:
+  - pip
+
+dist: trusty
+
+language: python
+
+python:
+  - '3.6'
+  - '2.7'
+
+branches:
+  only:
+    - master
+
+notifications:
+  email: false
+
+install:
+  - true  # drop pip install -r requirements.txt
+
+script:
+  - pip install flake8
+  - flake8 .

+ 47 - 0
DataAnnotation/labelme/github2pypi/README.md

@@ -0,0 +1,47 @@
+<h1 align="center">
+  github2pypi
+</h1>
+
+<h4 align="center">
+  Utils to release Python repository on GitHub to PyPi
+</h4>
+
+<div align="center">
+  <a href="https://travis-ci.com/wkentaro/github2pypi"><img src="https://travis-ci.com/wkentaro/github2pypi.svg?branch=master"></a>
+</div>
+
+
+## Usage
+
+
+### 1. Add `github2pypi` as submodule.
+
+See [imgviz](https://github.com/wkentaro/imgviz) as an example.
+
+```bash
+git clone https://github.com/wkentaro/imgviz
+cd imgviz
+
+git submodule add https://github.com/wkentaro/github2pypi.git
+```
+
+
+### 2. Edit `setup.py`.
+
+```python
+import github2pypi
+
+...
+with open('README.md') as f:
+    # e.g., ![](examples/image.jpg) ->
+    #       ![](https://github.com/wkentaro/imgviz/blob/master/examples/image.jpg)
+    long_description = github2pypi.replace_url(
+        slug='wkentaro/imgviz', content=f.read()
+    )
+
+setup(
+    ...
+    long_description=long_description,
+    long_description_content_type='text/markdown',
+)
+```

+ 3 - 0
DataAnnotation/labelme/github2pypi/__init__.py

@@ -0,0 +1,3 @@
+# flake8: noqa
+
+from .replace_url import replace_url

+ 41 - 0
DataAnnotation/labelme/github2pypi/replace_url.py

@@ -0,0 +1,41 @@
+import re
+
+
+def replace_url(slug, content, branch='master'):
+
+    def repl(match):
+        if not match:
+            return
+
+        url = match.group(1)
+        if url.startswith('http'):
+            return match.group(0)
+
+        url_new = (
+            'https://github.com/{slug}/blob/{branch}/{url}'
+            .format(slug=slug, branch=branch, url=url)
+        )
+        if re.match(r'.*[\.jpg|\.png]$', url_new):
+            url_new += '?raw=true'
+
+        start0, end0 = match.regs[0]
+        start, end = match.regs[1]
+        start -= start0
+        end -= start0
+
+        res = match.group(0)
+        res = res[:start] + url_new + res[end:]
+        return res
+
+    lines = []
+    for line in content.splitlines():
+        patterns = [
+            r'!\[.*?\]\((.*?)\)',
+            r'<img.*?src="(.*?)".*?>',
+            r'\[.*?\]\((.*?)\)',
+            r'<a.*?href="(.*?)".*?>',
+        ]
+        for pattern in patterns:
+            line = re.sub(pattern, repl, line)
+        lines.append(line)
+    return '\n'.join(lines)

+ 45 - 0
DataAnnotation/labelme/labelme.spec

@@ -0,0 +1,45 @@
+# -*- mode: python -*-
+# vim: ft=python
+
+
+block_cipher = None
+
+
+a = Analysis(
+    ['labelme/main.py'],
+    pathex=['labelme'],
+    binaries=[],
+    datas=[
+        ('labelme/config/default_config.yaml', 'labelme/config'),
+        ('labelme/icons/*', 'labelme/icons'),
+    ],
+    hiddenimports=[],
+    hookspath=[],
+    runtime_hooks=[],
+    excludes=['matplotlib'],
+    win_no_prefer_redirects=False,
+    win_private_assemblies=False,
+    cipher=block_cipher,
+)
+pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
+exe = EXE(
+    pyz,
+    a.scripts,
+    a.binaries,
+    a.zipfiles,
+    a.datas,
+    name='labelme',
+    debug=False,
+    strip=False,
+    upx=True,
+    runtime_tmpdir=None,
+    console=False,
+    icon='labelme/icons/icon.ico',
+)
+app = BUNDLE(
+    exe,
+    name='labelme.app',
+    icon='labelme/icons/icon.icns',
+    bundle_identifier=None,
+    info_plist={'NSHighResolutionCapable': 'True'},
+)

+ 23 - 0
DataAnnotation/labelme/labelme/__init__.py

@@ -0,0 +1,23 @@
+# flake8: noqa
+
+import logging
+import sys
+
+from qtpy import QT_VERSION
+
+
+__appname__ = 'labelme'
+
+QT4 = QT_VERSION[0] == '4'
+QT5 = QT_VERSION[0] == '5'
+del QT_VERSION
+
+PY2 = sys.version[0] == '2'
+PY3 = sys.version[0] == '3'
+del sys
+
+
+from labelme._version import __version__
+
+from labelme import testing
+from labelme import utils

+ 5 - 0
DataAnnotation/labelme/labelme/_version.py

@@ -0,0 +1,5 @@
+# Semantic Versioning 2.0.0: https://semver.org/
+# 1. MAJOR version when you make incompatible API changes;
+# 2. MINOR version when you add functionality in a backwards-compatible manner;
+# 3. PATCH version when you make backwards-compatible bug fixes.
+__version__ = '3.16.3'

+ 1670 - 0
DataAnnotation/labelme/labelme/app.py

@@ -0,0 +1,1670 @@
+import functools
+import os
+import os.path as osp
+import re
+import webbrowser
+
+from qtpy import QtCore
+from qtpy.QtCore import Qt
+from qtpy import QtGui
+from qtpy import QtWidgets
+
+from labelme import __appname__
+from labelme import PY2
+from labelme import QT5
+
+from . import utils
+from labelme.config import get_config
+from labelme.label_file import LabelFile
+from labelme.label_file import LabelFileError
+from labelme.logger import logger
+from labelme.shape import DEFAULT_FILL_COLOR
+from labelme.shape import DEFAULT_LINE_COLOR
+from labelme.shape import Shape
+from labelme.widgets import Canvas
+from labelme.widgets import ColorDialog
+from labelme.widgets import EscapableQListWidget
+from labelme.widgets import LabelDialog
+from labelme.widgets import LabelQListWidget
+from labelme.widgets import ToolBar
+from labelme.widgets import ZoomWidget
+
+
+# FIXME
+# - [medium] Set max zoom value to something big enough for FitWidth/Window
+
+# TODO(unknown):
+# - [high] Add polygon movement with arrow keys
+# - [high] Deselect shape when clicking and already selected(?)
+# - [low,maybe] Open images with drag & drop.
+# - [low,maybe] Preview images on file dialogs.
+# - Zoom is too "steppy".
+
+
+class MainWindow(QtWidgets.QMainWindow):
+
+    FIT_WINDOW, FIT_WIDTH, MANUAL_ZOOM = 0, 1, 2
+
+    def __init__(
+        self,
+        config=None,
+        filename=None,
+        output=None,
+        output_file=None,
+        output_dir=None,
+    ):
+        if output is not None:
+            logger.warning(
+                'argument output is deprecated, use output_file instead'
+            )
+            if output_file is None:
+                output_file = output
+
+        # see labelme/config/default_config.yaml for valid configuration
+        if config is None:
+            config = get_config()
+        self._config = config
+
+        super(MainWindow, self).__init__()
+        self.setWindowTitle(__appname__)
+
+        # Whether we need to save or not.
+        self.dirty = False
+
+        self._noSelectionSlot = False
+
+        # Main widgets and related state.
+        self.labelDialog = LabelDialog(
+            parent=self,
+            labels=self._config['labels'],
+            sort_labels=self._config['sort_labels'],
+            show_text_field=self._config['show_label_text_field'],
+            completion=self._config['label_completion'],
+            fit_to_content=self._config['fit_to_content'],
+            flags=self._config['label_flags']
+        )
+
+        self.labelList = LabelQListWidget()
+        self.lastOpenDir = None
+
+        self.flag_dock = self.flag_widget = None
+        self.flag_dock = QtWidgets.QDockWidget('Flags', self)
+        self.flag_dock.setObjectName('Flags')
+        self.flag_widget = QtWidgets.QListWidget()
+        if config['flags']:
+            self.loadFlags({k: False for k in config['flags']})
+        self.flag_dock.setWidget(self.flag_widget)
+        self.flag_widget.itemChanged.connect(self.setDirty)
+
+        self.labelList.itemActivated.connect(self.labelSelectionChanged)
+        self.labelList.itemSelectionChanged.connect(self.labelSelectionChanged)
+        self.labelList.itemDoubleClicked.connect(self.editLabel)
+        # Connect to itemChanged to detect checkbox changes.
+        self.labelList.itemChanged.connect(self.labelItemChanged)
+        self.labelList.setDragDropMode(
+            QtWidgets.QAbstractItemView.InternalMove)
+        self.labelList.setParent(self)
+        self.shape_dock = QtWidgets.QDockWidget('Polygon Labels', self)
+        self.shape_dock.setObjectName('Labels')
+        self.shape_dock.setWidget(self.labelList)
+
+        self.uniqLabelList = EscapableQListWidget()
+        self.uniqLabelList.setToolTip(
+            "Select label to start annotating for it. "
+            "Press 'Esc' to deselect.")
+        if self._config['labels']:
+            self.uniqLabelList.addItems(self._config['labels'])
+            self.uniqLabelList.sortItems()
+        self.label_dock = QtWidgets.QDockWidget(u'Label List', self)
+        self.label_dock.setObjectName(u'Label List')
+        self.label_dock.setWidget(self.uniqLabelList)
+
+        self.fileSearch = QtWidgets.QLineEdit()
+        self.fileSearch.setPlaceholderText('Search Filename')
+        self.fileSearch.textChanged.connect(self.fileSearchChanged)
+        self.fileListWidget = QtWidgets.QListWidget()
+        self.fileListWidget.itemSelectionChanged.connect(
+            self.fileSelectionChanged
+        )
+        fileListLayout = QtWidgets.QVBoxLayout()
+        fileListLayout.setContentsMargins(0, 0, 0, 0)
+        fileListLayout.setSpacing(0)
+        fileListLayout.addWidget(self.fileSearch)
+        fileListLayout.addWidget(self.fileListWidget)
+        self.file_dock = QtWidgets.QDockWidget(u'File List', self)
+        self.file_dock.setObjectName(u'Files')
+        fileListWidget = QtWidgets.QWidget()
+        fileListWidget.setLayout(fileListLayout)
+        self.file_dock.setWidget(fileListWidget)
+
+        self.zoomWidget = ZoomWidget()
+        self.colorDialog = ColorDialog(parent=self)
+
+        self.canvas = self.labelList.canvas = Canvas(
+            epsilon=self._config['epsilon'],
+        )
+        self.canvas.zoomRequest.connect(self.zoomRequest)
+
+        scrollArea = QtWidgets.QScrollArea()
+        scrollArea.setWidget(self.canvas)
+        scrollArea.setWidgetResizable(True)
+        self.scrollBars = {
+            Qt.Vertical: scrollArea.verticalScrollBar(),
+            Qt.Horizontal: scrollArea.horizontalScrollBar(),
+        }
+        self.canvas.scrollRequest.connect(self.scrollRequest)
+
+        self.canvas.newShape.connect(self.newShape)
+        self.canvas.shapeMoved.connect(self.setDirty)
+        self.canvas.selectionChanged.connect(self.shapeSelectionChanged)
+        self.canvas.drawingPolygon.connect(self.toggleDrawingSensitive)
+
+        self.setCentralWidget(scrollArea)
+
+        features = QtWidgets.QDockWidget.DockWidgetFeatures()
+        for dock in ['flag_dock', 'label_dock', 'shape_dock', 'file_dock']:
+            if self._config[dock]['closable']:
+                features = features | QtWidgets.QDockWidget.DockWidgetClosable
+            if self._config[dock]['floatable']:
+                features = features | QtWidgets.QDockWidget.DockWidgetFloatable
+            if self._config[dock]['movable']:
+                features = features | QtWidgets.QDockWidget.DockWidgetMovable
+            getattr(self, dock).setFeatures(features)
+            if self._config[dock]['show'] is False:
+                getattr(self, dock).setVisible(False)
+
+        self.addDockWidget(Qt.RightDockWidgetArea, self.flag_dock)
+        self.addDockWidget(Qt.RightDockWidgetArea, self.label_dock)
+        self.addDockWidget(Qt.RightDockWidgetArea, self.shape_dock)
+        self.addDockWidget(Qt.RightDockWidgetArea, self.file_dock)
+
+        # Actions
+        action = functools.partial(utils.newAction, self)
+        shortcuts = self._config['shortcuts']
+        quit = action('&Quit', self.close, shortcuts['quit'], 'quit',
+                      'Quit application')
+        open_ = action('&Open', self.openFile, shortcuts['open'], 'open',
+                       'Open image or label file')
+        opendir = action('&Open Dir', self.openDirDialog,
+                         shortcuts['open_dir'], 'open', u'Open Dir')
+        openNextImg = action(
+            '&Next Image',
+            self.openNextImg,
+            shortcuts['open_next'],
+            'next',
+            u'Open next (hold Ctl+Shift to copy labels)',
+            enabled=False,
+        )
+        openPrevImg = action(
+            '&Prev Image',
+            self.openPrevImg,
+            shortcuts['open_prev'],
+            'prev',
+            u'Open prev (hold Ctl+Shift to copy labels)',
+            enabled=False,
+        )
+        save = action('&Save', self.saveFile, shortcuts['save'], 'save',
+                      'Save labels to file', enabled=False)
+        saveAs = action('&Save As', self.saveFileAs, shortcuts['save_as'],
+                        'save-as', 'Save labels to a different file',
+                        enabled=False)
+
+        deleteFile = action(
+            '&Delete File',
+            self.deleteFile,
+            shortcuts['delete_file'],
+            'delete',
+            'Delete current label file',
+            enabled=False)
+
+        changeOutputDir = action(
+            '&Change Output Dir',
+            slot=self.changeOutputDirDialog,
+            shortcut=shortcuts['save_to'],
+            icon='open',
+            tip=u'Change where annotations are loaded/saved'
+        )
+
+        saveAuto = action(
+            text='Save &Automatically',
+            slot=lambda x: self.actions.saveAuto.setChecked(x),
+            icon='save',
+            tip='Save automatically',
+            checkable=True,
+            enabled=True,
+        )
+        saveAuto.setChecked(self._config['auto_save'])
+
+        close = action('&Close', self.closeFile, shortcuts['close'], 'close',
+                       'Close current file')
+        color1 = action('Polygon &Line Color', self.chooseColor1,
+                        shortcuts['edit_line_color'], 'color_line',
+                        'Choose polygon line color')
+        color2 = action('Polygon &Fill Color', self.chooseColor2,
+                        shortcuts['edit_fill_color'], 'color',
+                        'Choose polygon fill color')
+
+        toggle_keep_prev_mode = action(
+            'Keep Previous Annotation',
+            self.toggleKeepPrevMode,
+            shortcuts['toggle_keep_prev_mode'], None,
+            'Toggle "keep pevious annotation" mode',
+            checkable=True)
+        toggle_keep_prev_mode.setChecked(self._config['keep_prev'])
+
+        createMode = action(
+            'Create Polygons',
+            lambda: self.toggleDrawMode(False, createMode='polygon'),
+            shortcuts['create_polygon'],
+            'objects',
+            'Start drawing polygons',
+            enabled=False,
+        )
+        createRectangleMode = action(
+            'Create Rectangle',
+            lambda: self.toggleDrawMode(False, createMode='rectangle'),
+            shortcuts['create_rectangle'],
+            'objects',
+            'Start drawing rectangles',
+            enabled=False,
+        )
+        createCircleMode = action(
+            'Create Circle',
+            lambda: self.toggleDrawMode(False, createMode='circle'),
+            shortcuts['create_circle'],
+            'objects',
+            'Start drawing circles',
+            enabled=False,
+        )
+        createLineMode = action(
+            'Create Line',
+            lambda: self.toggleDrawMode(False, createMode='line'),
+            shortcuts['create_line'],
+            'objects',
+            'Start drawing lines',
+            enabled=False,
+        )
+        createPointMode = action(
+            'Create Point',
+            lambda: self.toggleDrawMode(False, createMode='point'),
+            shortcuts['create_point'],
+            'objects',
+            'Start drawing points',
+            enabled=False,
+        )
+        createLineStripMode = action(
+            'Create LineStrip',
+            lambda: self.toggleDrawMode(False, createMode='linestrip'),
+            shortcuts['create_linestrip'],
+            'objects',
+            'Start drawing linestrip. Ctrl+LeftClick ends creation.',
+            enabled=False,
+        )
+        editMode = action('Edit Polygons', self.setEditMode,
+                          shortcuts['edit_polygon'], 'edit',
+                          'Move and edit the selected polygons', enabled=False)
+
+        delete = action('Delete Polygons', self.deleteSelectedShape,
+                        shortcuts['delete_polygon'], 'cancel',
+                        'Delete the selected polygons', enabled=False)
+        copy = action('Duplicate Polygons', self.copySelectedShape,
+                      shortcuts['duplicate_polygon'], 'copy',
+                      'Create a duplicate of the selected polygons',
+                      enabled=False)
+        undoLastPoint = action('Undo last point', self.canvas.undoLastPoint,
+                               shortcuts['undo_last_point'], 'undo',
+                               'Undo last drawn point', enabled=False)
+        addPointToEdge = action(
+            'Add Point to Edge',
+            self.canvas.addPointToEdge,
+            shortcuts['add_point_to_edge'],
+            'edit',
+            'Add point to the nearest edge',
+            enabled=False,
+        )
+
+        undo = action('Undo', self.undoShapeEdit, shortcuts['undo'], 'undo',
+                      'Undo last add and edit of shape', enabled=False)
+
+        hideAll = action('&Hide\nPolygons',
+                         functools.partial(self.togglePolygons, False),
+                         icon='eye', tip='Hide all polygons', enabled=False)
+        showAll = action('&Show\nPolygons',
+                         functools.partial(self.togglePolygons, True),
+                         icon='eye', tip='Show all polygons', enabled=False)
+
+        help = action('&Tutorial', self.tutorial, icon='help',
+                      tip='Show tutorial page')
+
+        zoom = QtWidgets.QWidgetAction(self)
+        zoom.setDefaultWidget(self.zoomWidget)
+        self.zoomWidget.setWhatsThis(
+            'Zoom in or out of the image. Also accessible with '
+            '{} and {} from the canvas.'
+            .format(
+                utils.fmtShortcut(
+                    '{},{}'.format(
+                        shortcuts['zoom_in'], shortcuts['zoom_out']
+                    )
+                ),
+                utils.fmtShortcut("Ctrl+Wheel"),
+            )
+        )
+        self.zoomWidget.setEnabled(False)
+
+        zoomIn = action('Zoom &In', functools.partial(self.addZoom, 1.1),
+                        shortcuts['zoom_in'], 'zoom-in',
+                        'Increase zoom level', enabled=False)
+        zoomOut = action('&Zoom Out', functools.partial(self.addZoom, 0.9),
+                         shortcuts['zoom_out'], 'zoom-out',
+                         'Decrease zoom level', enabled=False)
+        zoomOrg = action('&Original size',
+                         functools.partial(self.setZoom, 100),
+                         shortcuts['zoom_to_original'], 'zoom',
+                         'Zoom to original size', enabled=False)
+        fitWindow = action('&Fit Window', self.setFitWindow,
+                           shortcuts['fit_window'], 'fit-window',
+                           'Zoom follows window size', checkable=True,
+                           enabled=False)
+        fitWidth = action('Fit &Width', self.setFitWidth,
+                          shortcuts['fit_width'], 'fit-width',
+                          'Zoom follows window width',
+                          checkable=True, enabled=False)
+        # Group zoom controls into a list for easier toggling.
+        zoomActions = (self.zoomWidget, zoomIn, zoomOut, zoomOrg,
+                       fitWindow, fitWidth)
+        self.zoomMode = self.FIT_WINDOW
+        fitWindow.setChecked(Qt.Checked)
+        self.scalers = {
+            self.FIT_WINDOW: self.scaleFitWindow,
+            self.FIT_WIDTH: self.scaleFitWidth,
+            # Set to one to scale to 100% when loading files.
+            self.MANUAL_ZOOM: lambda: 1,
+        }
+
+        edit = action('&Edit Label', self.editLabel, shortcuts['edit_label'],
+                      'edit', 'Modify the label of the selected polygon',
+                      enabled=False)
+
+        shapeLineColor = action(
+            'Shape &Line Color', self.chshapeLineColor, icon='color-line',
+            tip='Change the line color for this specific shape', enabled=False)
+        shapeFillColor = action(
+            'Shape &Fill Color', self.chshapeFillColor, icon='color',
+            tip='Change the fill color for this specific shape', enabled=False)
+        fill_drawing = action(
+            'Fill Drawing Polygon',
+            lambda x: self.canvas.setFillDrawing(x),
+            None,
+            'color',
+            'Fill polygon while drawing',
+            checkable=True,
+            enabled=True,
+        )
+        fill_drawing.setChecked(True)
+
+        # Lavel list context menu.
+        labelMenu = QtWidgets.QMenu()
+        utils.addActions(labelMenu, (edit, delete))
+        self.labelList.setContextMenuPolicy(Qt.CustomContextMenu)
+        self.labelList.customContextMenuRequested.connect(
+            self.popLabelListMenu)
+
+        # Store actions for further handling.
+        self.actions = utils.struct(
+            saveAuto=saveAuto,
+            changeOutputDir=changeOutputDir,
+            save=save, saveAs=saveAs, open=open_, close=close,
+            deleteFile=deleteFile,
+            lineColor=color1, fillColor=color2,
+            toggleKeepPrevMode=toggle_keep_prev_mode,
+            delete=delete, edit=edit, copy=copy,
+            undoLastPoint=undoLastPoint, undo=undo,
+            addPointToEdge=addPointToEdge,
+            createMode=createMode, editMode=editMode,
+            createRectangleMode=createRectangleMode,
+            createCircleMode=createCircleMode,
+            createLineMode=createLineMode,
+            createPointMode=createPointMode,
+            createLineStripMode=createLineStripMode,
+            shapeLineColor=shapeLineColor, shapeFillColor=shapeFillColor,
+            zoom=zoom, zoomIn=zoomIn, zoomOut=zoomOut, zoomOrg=zoomOrg,
+            fitWindow=fitWindow, fitWidth=fitWidth,
+            zoomActions=zoomActions,
+            openNextImg=openNextImg, openPrevImg=openPrevImg,
+            fileMenuActions=(open_, opendir, save, saveAs, close, quit),
+            tool=(),
+            # XXX: need to add some actions here to activate the shortcut
+            editMenu=(
+                edit,
+                copy,
+                delete,
+                None,
+                undo,
+                undoLastPoint,
+                None,
+                addPointToEdge,
+                None,
+                color1,
+                color2,
+                None,
+                toggle_keep_prev_mode,
+            ),
+            # menu shown at right click
+            menu=(
+                createMode,
+                createRectangleMode,
+                createCircleMode,
+                createLineMode,
+                createPointMode,
+                createLineStripMode,
+                editMode,
+                edit,
+                copy,
+                delete,
+                shapeLineColor,
+                shapeFillColor,
+                undo,
+                undoLastPoint,
+                addPointToEdge,
+            ),
+            onLoadActive=(
+                close,
+                createMode,
+                createRectangleMode,
+                createCircleMode,
+                createLineMode,
+                createPointMode,
+                createLineStripMode,
+                editMode,
+            ),
+            onShapesPresent=(saveAs, hideAll, showAll),
+        )
+
+        self.canvas.edgeSelected.connect(
+            self.actions.addPointToEdge.setEnabled
+        )
+
+        self.menus = utils.struct(
+            file=self.menu('&File'),
+            edit=self.menu('&Edit'),
+            view=self.menu('&View'),
+            help=self.menu('&Help'),
+            recentFiles=QtWidgets.QMenu('Open &Recent'),
+            labelList=labelMenu,
+        )
+
+        utils.addActions(
+            self.menus.file,
+            (
+                open_,
+                openNextImg,
+                openPrevImg,
+                opendir,
+                self.menus.recentFiles,
+                save,
+                saveAs,
+                saveAuto,
+                changeOutputDir,
+                close,
+                deleteFile,
+                None,
+                quit,
+            ),
+        )
+        utils.addActions(self.menus.help, (help,))
+        utils.addActions(
+            self.menus.view,
+            (
+                self.flag_dock.toggleViewAction(),
+                self.label_dock.toggleViewAction(),
+                self.shape_dock.toggleViewAction(),
+                self.file_dock.toggleViewAction(),
+                None,
+                fill_drawing,
+                None,
+                hideAll,
+                showAll,
+                None,
+                zoomIn,
+                zoomOut,
+                zoomOrg,
+                None,
+                fitWindow,
+                fitWidth,
+                None,
+            ),
+        )
+
+        self.menus.file.aboutToShow.connect(self.updateFileMenu)
+
+        # Custom context menu for the canvas widget:
+        utils.addActions(self.canvas.menus[0], self.actions.menu)
+        utils.addActions(
+            self.canvas.menus[1],
+            (
+                action('&Copy here', self.copyShape),
+                action('&Move here', self.moveShape),
+            ),
+        )
+
+        self.tools = self.toolbar('Tools')
+        # Menu buttons on Left
+        self.actions.tool = (
+            open_,
+            opendir,
+            openNextImg,
+            openPrevImg,
+            save,
+            deleteFile,
+            None,
+            createMode,
+            editMode,
+            copy,
+            delete,
+            undo,
+            None,
+            zoomIn,
+            zoom,
+            zoomOut,
+            fitWindow,
+            fitWidth,
+        )
+
+        self.statusBar().showMessage('%s started.' % __appname__)
+        self.statusBar().show()
+
+        if output_file is not None and self._config['auto_save']:
+            logger.warn(
+                'If `auto_save` argument is True, `output_file` argument '
+                'is ignored and output filename is automatically '
+                'set as IMAGE_BASENAME.json.'
+            )
+        self.output_file = output_file
+        self.output_dir = output_dir
+
+        # Application state.
+        self.image = QtGui.QImage()
+        self.imagePath = None
+        self.recentFiles = []
+        self.maxRecent = 7
+        self.lineColor = None
+        self.fillColor = None
+        self.otherData = None
+        self.zoom_level = 100
+        self.fit_window = False
+
+        if filename is not None and osp.isdir(filename):
+            self.importDirImages(filename, load=False)
+        else:
+            self.filename = filename
+
+        if config['file_search']:
+            self.fileSearch.setText(config['file_search'])
+            self.fileSearchChanged()
+
+        # XXX: Could be completely declarative.
+        # Restore application settings.
+        self.settings = QtCore.QSettings('labelme', 'labelme')
+        # FIXME: QSettings.value can return None on PyQt4
+        self.recentFiles = self.settings.value('recentFiles', []) or []
+        size = self.settings.value('window/size', QtCore.QSize(600, 500))
+        position = self.settings.value('window/position', QtCore.QPoint(0, 0))
+        self.resize(size)
+        self.move(position)
+        # or simply:
+        # self.restoreGeometry(settings['window/geometry']
+        self.restoreState(
+            self.settings.value('window/state', QtCore.QByteArray()))
+        self.lineColor = QtGui.QColor(
+            self.settings.value('line/color', Shape.line_color))
+        self.fillColor = QtGui.QColor(
+            self.settings.value('fill/color', Shape.fill_color))
+        Shape.line_color = self.lineColor
+        Shape.fill_color = self.fillColor
+
+        # Populate the File menu dynamically.
+        self.updateFileMenu()
+        # Since loading the file may take some time,
+        # make sure it runs in the background.
+        if self.filename is not None:
+            self.queueEvent(functools.partial(self.loadFile, self.filename))
+
+        # Callbacks:
+        self.zoomWidget.valueChanged.connect(self.paintCanvas)
+
+        self.populateModeActions()
+
+        # self.firstStart = True
+        # if self.firstStart:
+        #    QWhatsThis.enterWhatsThisMode()
+
+    def menu(self, title, actions=None):
+        menu = self.menuBar().addMenu(title)
+        if actions:
+            utils.addActions(menu, actions)
+        return menu
+
+    def toolbar(self, title, actions=None):
+        toolbar = ToolBar(title)
+        toolbar.setObjectName('%sToolBar' % title)
+        # toolbar.setOrientation(Qt.Vertical)
+        toolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
+        if actions:
+            utils.addActions(toolbar, actions)
+        self.addToolBar(Qt.LeftToolBarArea, toolbar)
+        return toolbar
+
+    # Support Functions
+
+    def noShapes(self):
+        return not self.labelList.itemsToShapes
+
+    def populateModeActions(self):
+        tool, menu = self.actions.tool, self.actions.menu
+        self.tools.clear()
+        utils.addActions(self.tools, tool)
+        self.canvas.menus[0].clear()
+        utils.addActions(self.canvas.menus[0], menu)
+        self.menus.edit.clear()
+        actions = (
+            self.actions.createMode,
+            self.actions.createRectangleMode,
+            self.actions.createCircleMode,
+            self.actions.createLineMode,
+            self.actions.createPointMode,
+            self.actions.createLineStripMode,
+            self.actions.editMode,
+        )
+        utils.addActions(self.menus.edit, actions + self.actions.editMenu)
+
+    def setDirty(self):
+        if self._config['auto_save'] or self.actions.saveAuto.isChecked():
+            label_file = osp.splitext(self.imagePath)[0] + '.json'
+            if self.output_dir:
+                label_file_without_path = osp.basename(label_file)
+                label_file = osp.join(self.output_dir, label_file_without_path)
+            self.saveLabels(label_file)
+            return
+        self.dirty = True
+        self.actions.save.setEnabled(True)
+        self.actions.undo.setEnabled(self.canvas.isShapeRestorable)
+        title = __appname__
+        if self.filename is not None:
+            title = '{} - {}*'.format(title, self.filename)
+        self.setWindowTitle(title)
+
+    def setClean(self):
+        self.dirty = False
+        self.actions.save.setEnabled(False)
+        self.actions.createMode.setEnabled(True)
+        self.actions.createRectangleMode.setEnabled(True)
+        self.actions.createCircleMode.setEnabled(True)
+        self.actions.createLineMode.setEnabled(True)
+        self.actions.createPointMode.setEnabled(True)
+        self.actions.createLineStripMode.setEnabled(True)
+        title = __appname__
+        if self.filename is not None:
+            title = '{} - {}'.format(title, self.filename)
+        self.setWindowTitle(title)
+
+        if self.hasLabelFile():
+            self.actions.deleteFile.setEnabled(True)
+        else:
+            self.actions.deleteFile.setEnabled(False)
+
+    def toggleActions(self, value=True):
+        """Enable/Disable widgets which depend on an opened image."""
+        for z in self.actions.zoomActions:
+            z.setEnabled(value)
+        for action in self.actions.onLoadActive:
+            action.setEnabled(value)
+
+    def queueEvent(self, function):
+        QtCore.QTimer.singleShot(0, function)
+
+    def status(self, message, delay=5000):
+        self.statusBar().showMessage(message, delay)
+
+    def resetState(self):
+        self.labelList.clear()
+        self.filename = None
+        self.imagePath = None
+        self.imageData = None
+        self.labelFile = None
+        self.otherData = None
+        self.canvas.resetState()
+
+    def currentItem(self):
+        items = self.labelList.selectedItems()
+        if items:
+            return items[0]
+        return None
+
+    def addRecentFile(self, filename):
+        if filename in self.recentFiles:
+            self.recentFiles.remove(filename)
+        elif len(self.recentFiles) >= self.maxRecent:
+            self.recentFiles.pop()
+        self.recentFiles.insert(0, filename)
+
+    # Callbacks
+
+    def undoShapeEdit(self):
+        self.canvas.restoreShape()
+        self.labelList.clear()
+        self.loadShapes(self.canvas.shapes)
+        self.actions.undo.setEnabled(self.canvas.isShapeRestorable)
+
+    def tutorial(self):
+        url = 'https://github.com/wkentaro/labelme/tree/master/examples/tutorial'  # NOQA
+        webbrowser.open(url)
+
+    def toggleDrawingSensitive(self, drawing=True):
+        """Toggle drawing sensitive.
+
+        In the middle of drawing, toggling between modes should be disabled.
+        """
+        self.actions.editMode.setEnabled(not drawing)
+        self.actions.undoLastPoint.setEnabled(drawing)
+        self.actions.undo.setEnabled(not drawing)
+        self.actions.delete.setEnabled(not drawing)
+
+    def toggleDrawMode(self, edit=True, createMode='polygon'):
+        self.canvas.setEditing(edit)
+        self.canvas.createMode = createMode
+        if edit:
+            self.actions.createMode.setEnabled(True)
+            self.actions.createRectangleMode.setEnabled(True)
+            self.actions.createCircleMode.setEnabled(True)
+            self.actions.createLineMode.setEnabled(True)
+            self.actions.createPointMode.setEnabled(True)
+            self.actions.createLineStripMode.setEnabled(True)
+        else:
+            if createMode == 'polygon':
+                self.actions.createMode.setEnabled(False)
+                self.actions.createRectangleMode.setEnabled(True)
+                self.actions.createCircleMode.setEnabled(True)
+                self.actions.createLineMode.setEnabled(True)
+                self.actions.createPointMode.setEnabled(True)
+                self.actions.createLineStripMode.setEnabled(True)
+            elif createMode == 'rectangle':
+                self.actions.createMode.setEnabled(True)
+                self.actions.createRectangleMode.setEnabled(False)
+                self.actions.createCircleMode.setEnabled(True)
+                self.actions.createLineMode.setEnabled(True)
+                self.actions.createPointMode.setEnabled(True)
+                self.actions.createLineStripMode.setEnabled(True)
+            elif createMode == 'line':
+                self.actions.createMode.setEnabled(True)
+                self.actions.createRectangleMode.setEnabled(True)
+                self.actions.createCircleMode.setEnabled(True)
+                self.actions.createLineMode.setEnabled(False)
+                self.actions.createPointMode.setEnabled(True)
+                self.actions.createLineStripMode.setEnabled(True)
+            elif createMode == 'point':
+                self.actions.createMode.setEnabled(True)
+                self.actions.createRectangleMode.setEnabled(True)
+                self.actions.createCircleMode.setEnabled(True)
+                self.actions.createLineMode.setEnabled(True)
+                self.actions.createPointMode.setEnabled(False)
+                self.actions.createLineStripMode.setEnabled(True)
+            elif createMode == "circle":
+                self.actions.createMode.setEnabled(True)
+                self.actions.createRectangleMode.setEnabled(True)
+                self.actions.createCircleMode.setEnabled(False)
+                self.actions.createLineMode.setEnabled(True)
+                self.actions.createPointMode.setEnabled(True)
+                self.actions.createLineStripMode.setEnabled(True)
+            elif createMode == "linestrip":
+                self.actions.createMode.setEnabled(True)
+                self.actions.createRectangleMode.setEnabled(True)
+                self.actions.createCircleMode.setEnabled(True)
+                self.actions.createLineMode.setEnabled(True)
+                self.actions.createPointMode.setEnabled(True)
+                self.actions.createLineStripMode.setEnabled(False)
+            else:
+                raise ValueError('Unsupported createMode: %s' % createMode)
+        self.actions.editMode.setEnabled(not edit)
+
+    def setEditMode(self):
+        self.toggleDrawMode(True)
+
+    def updateFileMenu(self):
+        current = self.filename
+
+        def exists(filename):
+            return osp.exists(str(filename))
+
+        menu = self.menus.recentFiles
+        menu.clear()
+        files = [f for f in self.recentFiles if f != current and exists(f)]
+        for i, f in enumerate(files):
+            icon = utils.newIcon('labels')
+            action = QtWidgets.QAction(
+                icon, '&%d %s' % (i + 1, QtCore.QFileInfo(f).fileName()), self)
+            action.triggered.connect(functools.partial(self.loadRecent, f))
+            menu.addAction(action)
+
+    def popLabelListMenu(self, point):
+        self.menus.labelList.exec_(self.labelList.mapToGlobal(point))
+
+    def validateLabel(self, label):
+        # no validation
+        if self._config['validate_label'] is None:
+            return True
+
+        for i in range(self.uniqLabelList.count()):
+            label_i = self.uniqLabelList.item(i).text()
+            if self._config['validate_label'] in ['exact', 'instance']:
+                if label_i == label:
+                    return True
+            if self._config['validate_label'] == 'instance':
+                m = re.match(r'^{}-[0-9]*$'.format(label_i), label)
+                if m:
+                    return True
+        return False
+
+    def editLabel(self, item=False):
+        if item and not isinstance(item, QtWidgets.QListWidgetItem):
+            raise TypeError('unsupported type of item: {}'.format(type(item)))
+
+        if not self.canvas.editing():
+            return
+        if not item:
+            item = self.currentItem()
+        if item is None:
+            return
+        shape = self.labelList.get_shape_from_item(item)
+        if shape is None:
+            return
+        text, flags = self.labelDialog.popUp(shape.label, flags=shape.flags)
+        if text is None:
+            return
+        if not self.validateLabel(text):
+            self.errorMessage('Invalid label',
+                              "Invalid label '{}' with validation type '{}'"
+                              .format(text, self._config['validate_label']))
+            return
+        shape.label = text
+        shape.flags = flags
+        item.setText(text)
+        self.setDirty()
+        if not self.uniqLabelList.findItems(text, Qt.MatchExactly):
+            self.uniqLabelList.addItem(text)
+            self.uniqLabelList.sortItems()
+
+    def fileSearchChanged(self):
+        self.importDirImages(
+            self.lastOpenDir,
+            pattern=self.fileSearch.text(),
+            load=False,
+        )
+
+    def fileSelectionChanged(self):
+        items = self.fileListWidget.selectedItems()
+        if not items:
+            return
+        item = items[0]
+
+        if not self.mayContinue():
+            return
+
+        currIndex = self.imageList.index(str(item.text()))
+        if currIndex < len(self.imageList):
+            filename = self.imageList[currIndex]
+            if filename:
+                self.loadFile(filename)
+
+    # React to canvas signals.
+    def shapeSelectionChanged(self, selected_shapes):
+        self._noSelectionSlot = True
+        for shape in self.canvas.selectedShapes:
+            shape.selected = False
+        self.labelList.clearSelection()
+        self.canvas.selectedShapes = selected_shapes
+        for shape in self.canvas.selectedShapes:
+            shape.selected = True
+            item = self.labelList.get_item_from_shape(shape)
+            item.setSelected(True)
+        self._noSelectionSlot = False
+        n_selected = len(selected_shapes)
+        self.actions.delete.setEnabled(n_selected)
+        self.actions.copy.setEnabled(n_selected)
+        self.actions.edit.setEnabled(n_selected == 1)
+        self.actions.shapeLineColor.setEnabled(n_selected)
+        self.actions.shapeFillColor.setEnabled(n_selected)
+
+    def addLabel(self, shape):
+        item = QtWidgets.QListWidgetItem(shape.label)
+        item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
+        item.setCheckState(Qt.Checked)
+        self.labelList.itemsToShapes.append((item, shape))
+        self.labelList.addItem(item)
+        if not self.uniqLabelList.findItems(shape.label, Qt.MatchExactly):
+            self.uniqLabelList.addItem(shape.label)
+            self.uniqLabelList.sortItems()
+        self.labelDialog.addLabelHistory(item.text())
+        for action in self.actions.onShapesPresent:
+            action.setEnabled(True)
+
+    def remLabels(self, shapes):
+        for shape in shapes:
+            item = self.labelList.get_item_from_shape(shape)
+            self.labelList.takeItem(self.labelList.row(item))
+
+    def loadShapes(self, shapes, replace=True):
+        self._noSelectionSlot = True
+        for shape in shapes:
+            self.addLabel(shape)
+        self.labelList.clearSelection()
+        self._noSelectionSlot = False
+        self.canvas.loadShapes(shapes, replace=replace)
+
+    def loadLabels(self, shapes):
+        s = []
+        for label, points, line_color, fill_color, shape_type, flags in shapes:
+            shape = Shape(label=label, shape_type=shape_type)
+            for x, y in points:
+                shape.addPoint(QtCore.QPointF(x, y))
+            shape.close()
+
+            if line_color:
+                shape.line_color = QtGui.QColor(*line_color)
+
+            if fill_color:
+                shape.fill_color = QtGui.QColor(*fill_color)
+
+            default_flags = {}
+            if self._config['label_flags']:
+                for pattern, keys in self._config['label_flags'].items():
+                    if re.match(pattern, label):
+                        for key in keys:
+                            default_flags[key] = False
+            shape.flags = default_flags
+            shape.flags.update(flags)
+
+            s.append(shape)
+        self.loadShapes(s)
+
+    def loadFlags(self, flags):
+        self.flag_widget.clear()
+        for key, flag in flags.items():
+            item = QtWidgets.QListWidgetItem(key)
+            item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
+            item.setCheckState(Qt.Checked if flag else Qt.Unchecked)
+            self.flag_widget.addItem(item)
+
+    def saveLabels(self, filename):
+        lf = LabelFile()
+
+        def format_shape(s):
+            return dict(
+                label=s.label.encode('utf-8') if PY2 else s.label,
+                line_color=s.line_color.getRgb()
+                if s.line_color != self.lineColor else None,
+                fill_color=s.fill_color.getRgb()
+                if s.fill_color != self.fillColor else None,
+                points=[(p.x(), p.y()) for p in s.points],
+                shape_type=s.shape_type,
+                flags=s.flags
+            )
+
+        shapes = [format_shape(shape) for shape in self.labelList.shapes]
+        flags = {}
+        for i in range(self.flag_widget.count()):
+            item = self.flag_widget.item(i)
+            key = item.text()
+            flag = item.checkState() == Qt.Checked
+            flags[key] = flag
+        try:
+            imagePath = osp.relpath(
+                self.imagePath, osp.dirname(filename))
+            imageData = self.imageData if self._config['store_data'] else None
+            if osp.dirname(filename) and not osp.exists(osp.dirname(filename)):
+                os.makedirs(osp.dirname(filename))
+            lf.save(
+                filename=filename,
+                shapes=shapes,
+                imagePath=imagePath,
+                imageData=imageData,
+                imageHeight=self.image.height(),
+                imageWidth=self.image.width(),
+                lineColor=self.lineColor.getRgb(),
+                fillColor=self.fillColor.getRgb(),
+                otherData=self.otherData,
+                flags=flags,
+            )
+            self.labelFile = lf
+            items = self.fileListWidget.findItems(
+                self.imagePath, Qt.MatchExactly
+            )
+            if len(items) > 0:
+                if len(items) != 1:
+                    raise RuntimeError('There are duplicate files.')
+                items[0].setCheckState(Qt.Checked)
+            # disable allows next and previous image to proceed
+            # self.filename = filename
+            return True
+        except LabelFileError as e:
+            self.errorMessage('Error saving label data', '<b>%s</b>' % e)
+            return False
+
+    def copySelectedShape(self):
+        added_shapes = self.canvas.copySelectedShapes()
+        self.labelList.clearSelection()
+        for shape in added_shapes:
+            self.addLabel(shape)
+        self.setDirty()
+
+    def labelSelectionChanged(self):
+        if self._noSelectionSlot:
+            return
+        if self.canvas.editing():
+            selected_shapes = []
+            for item in self.labelList.selectedItems():
+                shape = self.labelList.get_shape_from_item(item)
+                selected_shapes.append(shape)
+            if selected_shapes:
+                self.canvas.selectShapes(selected_shapes)
+
+    def labelItemChanged(self, item):
+        shape = self.labelList.get_shape_from_item(item)
+        label = str(item.text())
+        if label != shape.label:
+            shape.label = str(item.text())
+            self.setDirty()
+        else:  # User probably changed item visibility
+            self.canvas.setShapeVisible(shape, item.checkState() == Qt.Checked)
+
+    # Callback functions:
+
+    def newShape(self):
+        """Pop-up and give focus to the label editor.
+
+        position MUST be in global coordinates.
+        """
+        items = self.uniqLabelList.selectedItems()
+        text = None
+        flags = {}
+        if items:
+            text = items[0].text()
+        if self._config['display_label_popup'] or not text:
+            # instance label auto increment
+            if self._config['instance_label_auto_increment']:
+                previous_label = self.labelDialog.edit.text()
+                split = previous_label.split('-')
+                if len(split) > 1 and split[-1].isdigit():
+                    split[-1] = str(int(split[-1]) + 1)
+                    instance_text = '-'.join(split)
+                else:
+                    instance_text = previous_label
+                if instance_text != '':
+                    text = instance_text
+            text, flags = self.labelDialog.popUp(text)
+            if text is None:
+                self.labelDialog.edit.setText(previous_label)
+
+        if text and not self.validateLabel(text):
+            self.errorMessage('Invalid label',
+                              "Invalid label '{}' with validation type '{}'"
+                              .format(text, self._config['validate_label']))
+            text = ''
+        if text:
+            self.labelList.clearSelection()
+            self.addLabel(self.canvas.setLastLabel(text, flags))
+            self.actions.editMode.setEnabled(True)
+            self.actions.undoLastPoint.setEnabled(False)
+            self.actions.undo.setEnabled(True)
+            self.setDirty()
+        else:
+            self.canvas.undoLastLine()
+            self.canvas.shapesBackups.pop()
+
+    def scrollRequest(self, delta, orientation):
+        units = - delta * 0.1  # natural scroll
+        bar = self.scrollBars[orientation]
+        bar.setValue(bar.value() + bar.singleStep() * units)
+
+    def setZoom(self, value):
+        self.actions.fitWidth.setChecked(False)
+        self.actions.fitWindow.setChecked(False)
+        self.zoomMode = self.MANUAL_ZOOM
+        self.zoomWidget.setValue(value)
+
+    def addZoom(self, increment=1.1):
+        self.setZoom(self.zoomWidget.value() * increment)
+
+    def zoomRequest(self, delta, pos):
+        canvas_width_old = self.canvas.width()
+        units = 1.1
+        if delta < 0:
+            units = 0.9
+        self.addZoom(units)
+
+        canvas_width_new = self.canvas.width()
+        if canvas_width_old != canvas_width_new:
+            canvas_scale_factor = canvas_width_new / canvas_width_old
+
+            x_shift = round(pos.x() * canvas_scale_factor) - pos.x()
+            y_shift = round(pos.y() * canvas_scale_factor) - pos.y()
+
+            self.scrollBars[Qt.Horizontal].setValue(
+                self.scrollBars[Qt.Horizontal].value() + x_shift)
+            self.scrollBars[Qt.Vertical].setValue(
+                self.scrollBars[Qt.Vertical].value() + y_shift)
+
+    def setFitWindow(self, value=True):
+        if value:
+            self.actions.fitWidth.setChecked(False)
+        self.zoomMode = self.FIT_WINDOW if value else self.MANUAL_ZOOM
+        self.adjustScale()
+
+    def setFitWidth(self, value=True):
+        if value:
+            self.actions.fitWindow.setChecked(False)
+        self.zoomMode = self.FIT_WIDTH if value else self.MANUAL_ZOOM
+        self.adjustScale()
+
+    def togglePolygons(self, value):
+        for item, shape in self.labelList.itemsToShapes:
+            item.setCheckState(Qt.Checked if value else Qt.Unchecked)
+
+    def loadFile(self, filename=None):
+        """Load the specified file, or the last opened file if None."""
+        # changing fileListWidget loads file
+        if (filename in self.imageList and
+                self.fileListWidget.currentRow() !=
+                self.imageList.index(filename)):
+            self.fileListWidget.setCurrentRow(self.imageList.index(filename))
+            self.fileListWidget.repaint()
+            return
+
+        self.resetState()
+        self.canvas.setEnabled(False)
+        if filename is None:
+            filename = self.settings.value('filename', '')
+        filename = str(filename)
+        if not QtCore.QFile.exists(filename):
+            self.errorMessage(
+                'Error opening file', 'No such file: <b>%s</b>' % filename)
+            return False
+        # assumes same name, but json extension
+        self.status("Loading %s..." % osp.basename(str(filename)))
+        label_file = osp.splitext(filename)[0] + '.json'
+        if self.output_dir:
+            label_file_without_path = osp.basename(label_file)
+            label_file = osp.join(self.output_dir, label_file_without_path)
+        if QtCore.QFile.exists(label_file) and \
+                LabelFile.is_label_file(label_file):
+            try:
+                self.labelFile = LabelFile(label_file)
+            except LabelFileError as e:
+                self.errorMessage(
+                    'Error opening file',
+                    "<p><b>%s</b></p>"
+                    "<p>Make sure <i>%s</i> is a valid label file."
+                    % (e, label_file))
+                self.status("Error reading %s" % label_file)
+                return False
+            self.imageData = self.labelFile.imageData
+            self.imagePath = osp.join(
+                osp.dirname(label_file),
+                self.labelFile.imagePath,
+            )
+            if self.labelFile.lineColor is not None:
+                self.lineColor = QtGui.QColor(*self.labelFile.lineColor)
+            if self.labelFile.fillColor is not None:
+                self.fillColor = QtGui.QColor(*self.labelFile.fillColor)
+            self.otherData = self.labelFile.otherData
+        else:
+            self.imageData = LabelFile.load_image_file(filename)
+            if self.imageData:
+                self.imagePath = filename
+            self.labelFile = None
+        image = QtGui.QImage.fromData(self.imageData)
+
+        if image.isNull():
+            formats = ['*.{}'.format(fmt.data().decode())
+                       for fmt in QtGui.QImageReader.supportedImageFormats()]
+            self.errorMessage(
+                'Error opening file',
+                '<p>Make sure <i>{0}</i> is a valid image file.<br/>'
+                'Supported image formats: {1}</p>'
+                .format(filename, ','.join(formats)))
+            self.status("Error reading %s" % filename)
+            return False
+        self.image = image
+        self.filename = filename
+        if self._config['keep_prev']:
+            prev_shapes = self.canvas.shapes
+        self.canvas.loadPixmap(QtGui.QPixmap.fromImage(image))
+        if self._config['flags']:
+            self.loadFlags({k: False for k in self._config['flags']})
+        if self.labelFile:
+            self.loadLabels(self.labelFile.shapes)
+            if self.labelFile.flags is not None:
+                self.loadFlags(self.labelFile.flags)
+        if self._config['keep_prev'] and not self.labelList.shapes:
+            self.loadShapes(prev_shapes, replace=False)
+        self.setClean()
+        self.canvas.setEnabled(True)
+        self.adjustScale(initial=True)
+        self.paintCanvas()
+        self.addRecentFile(self.filename)
+        self.toggleActions(True)
+        self.status("Loaded %s" % osp.basename(str(filename)))
+        return True
+
+    def resizeEvent(self, event):
+        if self.canvas and not self.image.isNull()\
+           and self.zoomMode != self.MANUAL_ZOOM:
+            self.adjustScale()
+        super(MainWindow, self).resizeEvent(event)
+
+    def paintCanvas(self):
+        assert not self.image.isNull(), "cannot paint null image"
+        self.canvas.scale = 0.01 * self.zoomWidget.value()
+        self.canvas.adjustSize()
+        self.canvas.update()
+
+    def adjustScale(self, initial=False):
+        value = self.scalers[self.FIT_WINDOW if initial else self.zoomMode]()
+        self.zoomWidget.setValue(int(100 * value))
+
+    def scaleFitWindow(self):
+        """Figure out the size of the pixmap to fit the main widget."""
+        e = 2.0  # So that no scrollbars are generated.
+        w1 = self.centralWidget().width() - e
+        h1 = self.centralWidget().height() - e
+        a1 = w1 / h1
+        # Calculate a new scale value based on the pixmap's aspect ratio.
+        w2 = self.canvas.pixmap.width() - 0.0
+        h2 = self.canvas.pixmap.height() - 0.0
+        a2 = w2 / h2
+        return w1 / w2 if a2 >= a1 else h1 / h2
+
+    def scaleFitWidth(self):
+        # The epsilon does not seem to work too well here.
+        w = self.centralWidget().width() - 2.0
+        return w / self.canvas.pixmap.width()
+
+    def closeEvent(self, event):
+        if not self.mayContinue():
+            event.ignore()
+        self.settings.setValue(
+            'filename', self.filename if self.filename else '')
+        self.settings.setValue('window/size', self.size())
+        self.settings.setValue('window/position', self.pos())
+        self.settings.setValue('window/state', self.saveState())
+        self.settings.setValue('line/color', self.lineColor)
+        self.settings.setValue('fill/color', self.fillColor)
+        self.settings.setValue('recentFiles', self.recentFiles)
+        # ask the use for where to save the labels
+        # self.settings.setValue('window/geometry', self.saveGeometry())
+
+    # User Dialogs #
+
+    def loadRecent(self, filename):
+        if self.mayContinue():
+            self.loadFile(filename)
+
+    def openPrevImg(self, _value=False):
+        keep_prev = self._config['keep_prev']
+        if QtGui.QGuiApplication.keyboardModifiers() == \
+                (QtCore.Qt.ControlModifier | QtCore.Qt.ShiftModifier):
+            self._config['keep_prev'] = True
+
+        if not self.mayContinue():
+            return
+
+        if len(self.imageList) <= 0:
+            return
+
+        if self.filename is None:
+            return
+
+        currIndex = self.imageList.index(self.filename)
+        if currIndex - 1 >= 0:
+            filename = self.imageList[currIndex - 1]
+            if filename:
+                self.loadFile(filename)
+
+        self._config['keep_prev'] = keep_prev
+
+    def openNextImg(self, _value=False, load=True):
+        keep_prev = self._config['keep_prev']
+        if QtGui.QGuiApplication.keyboardModifiers() == \
+                (QtCore.Qt.ControlModifier | QtCore.Qt.ShiftModifier):
+            self._config['keep_prev'] = True
+
+        if not self.mayContinue():
+            return
+
+        if len(self.imageList) <= 0:
+            return
+
+        filename = None
+        if self.filename is None:
+            filename = self.imageList[0]
+        else:
+            currIndex = self.imageList.index(self.filename)
+            if currIndex + 1 < len(self.imageList):
+                filename = self.imageList[currIndex + 1]
+            else:
+                filename = self.imageList[-1]
+        self.filename = filename
+
+        if self.filename and load:
+            self.loadFile(self.filename)
+
+        self._config['keep_prev'] = keep_prev
+
+    def openFile(self, _value=False):
+        if not self.mayContinue():
+            return
+        path = osp.dirname(str(self.filename)) if self.filename else '.'
+        formats = ['*.{}'.format(fmt.data().decode())
+                   for fmt in QtGui.QImageReader.supportedImageFormats()]
+        filters = "Image & Label files (%s)" % ' '.join(
+            formats + ['*%s' % LabelFile.suffix])
+        filename = QtWidgets.QFileDialog.getOpenFileName(
+            self, '%s - Choose Image or Label file' % __appname__,
+            path, filters)
+        if QT5:
+            filename, _ = filename
+        filename = str(filename)
+        if filename:
+            self.loadFile(filename)
+
+    def changeOutputDirDialog(self, _value=False):
+        default_output_dir = self.output_dir
+        if default_output_dir is None and self.filename:
+            default_output_dir = osp.dirname(self.filename)
+        if default_output_dir is None:
+            default_output_dir = self.currentPath()
+
+        output_dir = QtWidgets.QFileDialog.getExistingDirectory(
+            self, '%s - Save/Load Annotations in Directory' % __appname__,
+            default_output_dir,
+            QtWidgets.QFileDialog.ShowDirsOnly |
+            QtWidgets.QFileDialog.DontResolveSymlinks,
+        )
+        output_dir = str(output_dir)
+
+        if not output_dir:
+            return
+
+        self.output_dir = output_dir
+
+        self.statusBar().showMessage(
+            '%s . Annotations will be saved/loaded in %s' %
+            ('Change Annotations Dir', self.output_dir))
+        self.statusBar().show()
+
+        current_filename = self.filename
+        self.importDirImages(self.lastOpenDir, load=False)
+
+        if current_filename in self.imageList:
+            # retain currently selected file
+            self.fileListWidget.setCurrentRow(
+                self.imageList.index(current_filename))
+            self.fileListWidget.repaint()
+
+    def saveFile(self, _value=False):
+        assert not self.image.isNull(), "cannot save empty image"
+        if self._config['flags'] or self.hasLabels():
+            if self.labelFile:
+                # DL20180323 - overwrite when in directory
+                self._saveFile(self.labelFile.filename)
+            elif self.output_file:
+                self._saveFile(self.output_file)
+                self.close()
+            else:
+                self._saveFile(self.saveFileDialog())
+
+    def saveFileAs(self, _value=False):
+        assert not self.image.isNull(), "cannot save empty image"
+        if self.hasLabels():
+            self._saveFile(self.saveFileDialog())
+
+    def saveFileDialog(self):
+        caption = '%s - Choose File' % __appname__
+        filters = 'Label files (*%s)' % LabelFile.suffix
+        if self.output_dir:
+            dlg = QtWidgets.QFileDialog(
+                self, caption, self.output_dir, filters
+            )
+        else:
+            dlg = QtWidgets.QFileDialog(
+                self, caption, self.currentPath(), filters
+            )
+        dlg.setDefaultSuffix(LabelFile.suffix[1:])
+        dlg.setAcceptMode(QtWidgets.QFileDialog.AcceptSave)
+        dlg.setOption(QtWidgets.QFileDialog.DontConfirmOverwrite, False)
+        dlg.setOption(QtWidgets.QFileDialog.DontUseNativeDialog, False)
+        basename = osp.basename(osp.splitext(self.filename)[0])
+        if self.output_dir:
+            default_labelfile_name = osp.join(
+                self.output_dir, basename + LabelFile.suffix
+            )
+        else:
+            default_labelfile_name = osp.join(
+                self.currentPath(), basename + LabelFile.suffix
+            )
+        filename = dlg.getSaveFileName(
+            self, 'Choose File', default_labelfile_name,
+            'Label files (*%s)' % LabelFile.suffix)
+        if QT5:
+            filename, _ = filename
+        filename = str(filename)
+        return filename
+
+    def _saveFile(self, filename):
+        if filename and self.saveLabels(filename):
+            self.addRecentFile(filename)
+            self.setClean()
+
+    def closeFile(self, _value=False):
+        if not self.mayContinue():
+            return
+        self.resetState()
+        self.setClean()
+        self.toggleActions(False)
+        self.canvas.setEnabled(False)
+        self.actions.saveAs.setEnabled(False)
+
+    def getLabelFile(self):
+        if self.filename.lower().endswith('.json'):
+            label_file = self.filename
+        else:
+            label_file = osp.splitext(self.filename)[0] + '.json'
+
+        return label_file
+
+    def deleteFile(self):
+        mb = QtWidgets.QMessageBox
+        msg = 'You are about to permanently delete this label file, ' \
+              'proceed anyway?'
+        answer = mb.warning(self, 'Attention', msg, mb.Yes | mb.No)
+        if answer != mb.Yes:
+            return
+
+        label_file = self.getLabelFile()
+        if osp.exists(label_file):
+            os.remove(label_file)
+            logger.info('Label file is removed: {}'.format(label_file))
+
+            item = self.fileListWidget.currentItem()
+            item.setCheckState(Qt.Unchecked)
+
+            self.resetState()
+
+    # Message Dialogs. #
+    def hasLabels(self):
+        if not self.labelList.itemsToShapes:
+            self.errorMessage(
+                'No objects labeled',
+                'You must label at least one object to save the file.')
+            return False
+        return True
+
+    def hasLabelFile(self):
+        if self.filename is None:
+            return False
+
+        label_file = self.getLabelFile()
+        return osp.exists(label_file)
+
+    def mayContinue(self):
+        if not self.dirty:
+            return True
+        mb = QtWidgets.QMessageBox
+        msg = 'Save annotations to "{}" before closing?'.format(self.filename)
+        answer = mb.question(self,
+                             'Save annotations?',
+                             msg,
+                             mb.Save | mb.Discard | mb.Cancel,
+                             mb.Save)
+        if answer == mb.Discard:
+            return True
+        elif answer == mb.Save:
+            self.saveFile()
+            return True
+        else:  # answer == mb.Cancel
+            return False
+
+    def errorMessage(self, title, message):
+        return QtWidgets.QMessageBox.critical(
+            self, title, '<p><b>%s</b></p>%s' % (title, message))
+
+    def currentPath(self):
+        return osp.dirname(str(self.filename)) if self.filename else '.'
+
+    def chooseColor1(self):
+        color = self.colorDialog.getColor(
+            self.lineColor, 'Choose line color', default=DEFAULT_LINE_COLOR)
+        if color:
+            self.lineColor = color
+            # Change the color for all shape lines:
+            Shape.line_color = self.lineColor
+            self.canvas.update()
+            self.setDirty()
+
+    def chooseColor2(self):
+        color = self.colorDialog.getColor(
+            self.fillColor, 'Choose fill color', default=DEFAULT_FILL_COLOR)
+        if color:
+            self.fillColor = color
+            Shape.fill_color = self.fillColor
+            self.canvas.update()
+            self.setDirty()
+
+    def toggleKeepPrevMode(self):
+        self._config['keep_prev'] = not self._config['keep_prev']
+
+    def deleteSelectedShape(self):
+        yes, no = QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No
+        msg = 'You are about to permanently delete {} polygons, ' \
+              'proceed anyway?'.format(len(self.canvas.selectedShapes))
+        if yes == QtWidgets.QMessageBox.warning(self, 'Attention', msg,
+                                                yes | no):
+            self.remLabels(self.canvas.deleteSelected())
+            self.setDirty()
+            if self.noShapes():
+                for action in self.actions.onShapesPresent:
+                    action.setEnabled(False)
+
+    def chshapeLineColor(self):
+        color = self.colorDialog.getColor(
+            self.lineColor, 'Choose line color', default=DEFAULT_LINE_COLOR)
+        if color:
+            for shape in self.canvas.selectedShapes:
+                shape.line_color = color
+            self.canvas.update()
+            self.setDirty()
+
+    def chshapeFillColor(self):
+        color = self.colorDialog.getColor(
+            self.fillColor, 'Choose fill color', default=DEFAULT_FILL_COLOR)
+        if color:
+            for shape in self.canvas.selectedShapes:
+                shape.fill_color = color
+            self.canvas.update()
+            self.setDirty()
+
+    def copyShape(self):
+        self.canvas.endMove(copy=True)
+        self.labelList.clearSelection()
+        for shape in self.canvas.selectedShapes:
+            self.addLabel(shape)
+        self.setDirty()
+
+    def moveShape(self):
+        self.canvas.endMove(copy=False)
+        self.setDirty()
+
+    def openDirDialog(self, _value=False, dirpath=None):
+        if not self.mayContinue():
+            return
+
+        defaultOpenDirPath = dirpath if dirpath else '.'
+        if self.lastOpenDir and osp.exists(self.lastOpenDir):
+            defaultOpenDirPath = self.lastOpenDir
+        else:
+            defaultOpenDirPath = osp.dirname(self.filename) \
+                if self.filename else '.'
+
+        targetDirPath = str(QtWidgets.QFileDialog.getExistingDirectory(
+            self, '%s - Open Directory' % __appname__, defaultOpenDirPath,
+            QtWidgets.QFileDialog.ShowDirsOnly |
+            QtWidgets.QFileDialog.DontResolveSymlinks))
+        self.importDirImages(targetDirPath)
+
+    @property
+    def imageList(self):
+        lst = []
+        for i in range(self.fileListWidget.count()):
+            item = self.fileListWidget.item(i)
+            lst.append(item.text())
+        return lst
+
+    def importDirImages(self, dirpath, pattern=None, load=True):
+        self.actions.openNextImg.setEnabled(True)
+        self.actions.openPrevImg.setEnabled(True)
+
+        if not self.mayContinue() or not dirpath:
+            return
+
+        self.lastOpenDir = dirpath
+        self.filename = None
+        self.fileListWidget.clear()
+        for filename in self.scanAllImages(dirpath):
+            if pattern and pattern not in filename:
+                continue
+            label_file = osp.splitext(filename)[0] + '.json'
+            if self.output_dir:
+                label_file_without_path = osp.basename(label_file)
+                label_file = osp.join(self.output_dir, label_file_without_path)
+            item = QtWidgets.QListWidgetItem(filename)
+            item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)
+            if QtCore.QFile.exists(label_file) and \
+                    LabelFile.is_label_file(label_file):
+                item.setCheckState(Qt.Checked)
+            else:
+                item.setCheckState(Qt.Unchecked)
+            self.fileListWidget.addItem(item)
+        self.openNextImg(load=load)
+
+    def scanAllImages(self, folderPath):
+        extensions = ['.%s' % fmt.data().decode("ascii").lower()
+                      for fmt in QtGui.QImageReader.supportedImageFormats()]
+        images = []
+
+        for root, dirs, files in os.walk(folderPath):
+            for file in files:
+                if file.lower().endswith(tuple(extensions)):
+                    relativePath = osp.join(root, file)
+                    images.append(relativePath)
+        images.sort(key=lambda x: x.lower())
+        return images

+ 6 - 0
DataAnnotation/labelme/labelme/cli/__init__.py

@@ -0,0 +1,6 @@
+# flake8: noqa
+
+from . import draw_json
+from . import draw_label_png
+from . import json_to_dataset
+from . import on_docker

+ 58 - 0
DataAnnotation/labelme/labelme/cli/draw_json.py

@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+
+import argparse
+import base64
+import json
+import os
+import sys
+
+import matplotlib.pyplot as plt
+
+from labelme import utils
+
+
+PY2 = sys.version_info[0] == 2
+
+
+def main():
+    parser = argparse.ArgumentParser()
+    parser.add_argument('json_file')
+    args = parser.parse_args()
+
+    json_file = args.json_file
+
+    data = json.load(open(json_file))
+
+    if data['imageData']:
+        imageData = data['imageData']
+    else:
+        imagePath = os.path.join(os.path.dirname(json_file), data['imagePath'])
+        with open(imagePath, 'rb') as f:
+            imageData = f.read()
+            imageData = base64.b64encode(imageData).decode('utf-8')
+    img = utils.img_b64_to_arr(imageData)
+
+    label_name_to_value = {'_background_': 0}
+    for shape in sorted(data['shapes'], key=lambda x: x['label']):
+        label_name = shape['label']
+        if label_name in label_name_to_value:
+            label_value = label_name_to_value[label_name]
+        else:
+            label_value = len(label_name_to_value)
+            label_name_to_value[label_name] = label_value
+    lbl = utils.shapes_to_label(img.shape, data['shapes'], label_name_to_value)
+
+    label_names = [None] * (max(label_name_to_value.values()) + 1)
+    for name, value in label_name_to_value.items():
+        label_names[value] = name
+    lbl_viz = utils.draw_label(lbl, img, label_names)
+
+    plt.subplot(121)
+    plt.imshow(img)
+    plt.subplot(122)
+    plt.imshow(lbl_viz)
+    plt.show()
+
+
+if __name__ == '__main__':
+    main()

Some files were not shown because too many files changed in this diff