pascal voc数据转coco

  1. 准备pascal voc数据

    1
    2
    3
    Annotations
    ImageSets
    JPEGImages

    转的过程中没用到ImagesSets文件夹

  2. 转换后输出json文件

  3. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    import xml.etree.ElementTree as ET
    import os
    import json

    coco = dict()
    coco['images'] = []
    coco['type'] = 'instances'
    coco['annotations'] = []
    coco['categories'] = []

    category_set = dict()
    image_set = set()

    category_item_id = -1
    image_id = 20180000000
    annotation_id = 0


    def addCatItem(name):
    global category_item_id
    category_item = dict()
    category_item['supercategory'] = 'none'
    category_item_id += 1
    category_item['id'] = category_item_id
    category_item['name'] = name
    coco['categories'].append(category_item)
    category_set[name] = category_item_id
    return category_item_id


    def addImgItem(file_name, size):
    global image_id
    if file_name is None:
    raise Exception('Could not find filename tag in xml file.')
    if size['width'] is None:
    raise Exception('Could not find width tag in xml file.')
    if size['height'] is None:
    raise Exception('Could not find height tag in xml file.')
    image_id += 1
    image_item = dict()
    image_item['id'] = image_id
    image_item['file_name'] = file_name
    image_item['width'] = size['width']
    image_item['height'] = size['height']
    coco['images'].append(image_item)
    image_set.add(file_name)
    return image_id


    def addAnnoItem(object_name, image_id, category_id, bbox):
    global annotation_id
    annotation_item = dict()
    annotation_item['segmentation'] = []
    seg = []
    # bbox[] is x,y,w,h
    # left_top
    seg.append(bbox[0])
    seg.append(bbox[1])
    # left_bottom
    seg.append(bbox[0])
    seg.append(bbox[1] + bbox[3])
    # right_bottom
    seg.append(bbox[0] + bbox[2])
    seg.append(bbox[1] + bbox[3])
    # right_top
    seg.append(bbox[0] + bbox[2])
    seg.append(bbox[1])

    annotation_item['segmentation'].append(seg)

    annotation_item['area'] = bbox[2] * bbox[3]
    annotation_item['iscrowd'] = 0
    annotation_item['ignore'] = 0
    annotation_item['image_id'] = image_id
    annotation_item['bbox'] = bbox
    annotation_item['category_id'] = category_id
    annotation_id += 1
    annotation_item['id'] = annotation_id
    coco['annotations'].append(annotation_item)


    def parseXmlFiles(xml_path):
    for f in os.listdir(xml_path):
    if not f.endswith('.xml'):
    continue

    bndbox = dict()
    size = dict()
    current_image_id = None
    current_category_id = None
    file_name = None
    size['width'] = None
    size['height'] = None
    size['depth'] = None

    xml_file = os.path.join(xml_path, f)
    print(xml_file)

    tree = ET.parse(xml_file)
    root = tree.getroot()
    if root.tag != 'annotation':
    raise Exception('pascal voc xml root element should be annotation, rather than {}'.format(root.tag))

    # elem is <folder>, <filename>, <size>, <object>
    for elem in root:
    current_parent = elem.tag
    current_sub = None
    object_name = None

    if elem.tag == 'folder':
    continue

    if elem.tag == 'filename':
    file_name = elem.text
    if file_name in category_set:
    raise Exception('file_name duplicated')

    # add img item only after parse <size> tag
    elif current_image_id is None and file_name is not None and size['width'] is not None:
    if file_name not in image_set:
    current_image_id = addImgItem(file_name, size)
    print('add image with {} and {}'.format(file_name, size))
    else:
    raise Exception('duplicated image: {}'.format(file_name))
    # subelem is <width>, <height>, <depth>, <name>, <bndbox>
    for subelem in elem:
    bndbox['xmin'] = None
    bndbox['xmax'] = None
    bndbox['ymin'] = None
    bndbox['ymax'] = None

    current_sub = subelem.tag
    if current_parent == 'object' and subelem.tag == 'name':
    object_name = subelem.text
    if object_name not in category_set:
    current_category_id = addCatItem(object_name)
    else:
    current_category_id = category_set[object_name]

    elif current_parent == 'size':
    if size[subelem.tag] is not None:
    raise Exception('xml structure broken at size tag.')
    size[subelem.tag] = int(subelem.text)

    # option is <xmin>, <ymin>, <xmax>, <ymax>, when subelem is <bndbox>
    for option in subelem:
    if current_sub == 'bndbox':
    if bndbox[option.tag] is not None:
    raise Exception('xml structure corrupted at bndbox tag.')
    bndbox[option.tag] = int(option.text)

    # only after parse the <object> tag
    if bndbox['xmin'] is not None:
    if object_name is None:
    raise Exception('xml structure broken at bndbox tag')
    if current_image_id is None:
    raise Exception('xml structure broken at bndbox tag')
    if current_category_id is None:
    raise Exception('xml structure broken at bndbox tag')
    bbox = []
    # x
    bbox.append(bndbox['xmin'])
    # y
    bbox.append(bndbox['ymin'])
    # w
    bbox.append(bndbox['xmax'] - bndbox['xmin'])
    # h
    bbox.append(bndbox['ymax'] - bndbox['ymin'])
    print('add annotation with {},{},{},{}'.format(object_name, current_image_id, current_category_id,
    bbox))
    addAnnoItem(object_name, current_image_id, current_category_id, bbox)


    if __name__ == '__main__':
    xml_path = 'Z:\pycharm_projects\ssd\VOCtest60\Annotations' # 这是xml文件所在的地址
    json_file = './test.json' # 这是你要生成的json文件
    parseXmlFiles(xml_path) # 只需要改动这两个参数就行了
    json.dump(coco, open(json_file, 'w'))