labelme2voc.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. #!/usr/bin/env python
  2. from __future__ import print_function
  3. import argparse
  4. import glob
  5. import os
  6. import os.path as osp
  7. import sys
  8. import imgviz
  9. import labelme
  10. try:
  11. import lxml.builder
  12. import lxml.etree
  13. except ImportError:
  14. print('Please install lxml:\n\n pip install lxml\n')
  15. sys.exit(1)
  16. def main():
  17. parser = argparse.ArgumentParser(
  18. formatter_class=argparse.ArgumentDefaultsHelpFormatter
  19. )
  20. parser.add_argument('input_dir', help='input annotated directory')
  21. parser.add_argument('output_dir', help='output dataset directory')
  22. parser.add_argument('--labels', help='labels file', required=True)
  23. parser.add_argument(
  24. '--noviz', help='no visualization', action='store_true'
  25. )
  26. args = parser.parse_args()
  27. if osp.exists(args.output_dir):
  28. print('Output directory already exists:', args.output_dir)
  29. sys.exit(1)
  30. os.makedirs(args.output_dir)
  31. os.makedirs(osp.join(args.output_dir, 'JPEGImages'))
  32. os.makedirs(osp.join(args.output_dir, 'Annotations'))
  33. if not args.noviz:
  34. os.makedirs(osp.join(args.output_dir, 'AnnotationsVisualization'))
  35. print('Creating dataset:', args.output_dir)
  36. class_names = []
  37. class_name_to_id = {}
  38. for i, line in enumerate(open(args.labels).readlines()):
  39. class_id = i - 1 # starts with -1
  40. class_name = line.strip()
  41. class_name_to_id[class_name] = class_id
  42. if class_id == -1:
  43. assert class_name == '__ignore__'
  44. continue
  45. elif class_id == 0:
  46. assert class_name == '_background_'
  47. class_names.append(class_name)
  48. class_names = tuple(class_names)
  49. print('class_names:', class_names)
  50. out_class_names_file = osp.join(args.output_dir, 'class_names.txt')
  51. with open(out_class_names_file, 'w') as f:
  52. f.writelines('\n'.join(class_names))
  53. print('Saved class_names:', out_class_names_file)
  54. for filename in glob.glob(osp.join(args.input_dir, '*.json')):
  55. print('Generating dataset from:', filename)
  56. label_file = labelme.LabelFile(filename=filename)
  57. base = osp.splitext(osp.basename(filename))[0]
  58. out_img_file = osp.join(
  59. args.output_dir, 'JPEGImages', base + '.jpg')
  60. out_xml_file = osp.join(
  61. args.output_dir, 'Annotations', base + '.xml')
  62. if not args.noviz:
  63. out_viz_file = osp.join(
  64. args.output_dir, 'AnnotationsVisualization', base + '.jpg')
  65. img = labelme.utils.img_data_to_arr(label_file.imageData)
  66. imgviz.io.imsave(out_img_file, img)
  67. maker = lxml.builder.ElementMaker()
  68. xml = maker.annotation(
  69. maker.folder(),
  70. maker.filename(base + '.jpg'),
  71. maker.database(), # e.g., The VOC2007 Database
  72. maker.annotation(), # e.g., Pascal VOC2007
  73. maker.image(), # e.g., flickr
  74. maker.size(
  75. maker.height(str(img.shape[0])),
  76. maker.width(str(img.shape[1])),
  77. maker.depth(str(img.shape[2])),
  78. ),
  79. maker.segmented(),
  80. )
  81. bboxes = []
  82. labels = []
  83. for shape in label_file.shapes:
  84. if shape['shape_type'] != 'rectangle':
  85. print('Skipping shape: label={label}, shape_type={shape_type}'
  86. .format(**shape))
  87. continue
  88. class_name = shape['label']
  89. class_id = class_names.index(class_name)
  90. (xmin, ymin), (xmax, ymax) = shape['points']
  91. # swap if min is larger than max.
  92. xmin, xmax = sorted([xmin, xmax])
  93. ymin, ymax = sorted([ymin, ymax])
  94. bboxes.append([ymin, xmin, ymax, xmax])
  95. labels.append(class_id)
  96. xml.append(
  97. maker.object(
  98. maker.name(shape['label']),
  99. maker.pose(),
  100. maker.truncated(),
  101. maker.difficult(),
  102. maker.bndbox(
  103. maker.xmin(str(xmin)),
  104. maker.ymin(str(ymin)),
  105. maker.xmax(str(xmax)),
  106. maker.ymax(str(ymax)),
  107. ),
  108. )
  109. )
  110. if not args.noviz:
  111. captions = [class_names[label] for label in labels]
  112. viz = imgviz.instances2rgb(
  113. image=img,
  114. labels=labels,
  115. bboxes=bboxes,
  116. captions=captions,
  117. font_size=15,
  118. )
  119. imgviz.io.imsave(out_viz_file, viz)
  120. with open(out_xml_file, 'wb') as f:
  121. f.write(lxml.etree.tostring(xml, pretty_print=True))
  122. if __name__ == '__main__':
  123. main()