将VOC转化为coco数据

在跑SNIPER时,需要用到coco数据,所以进行了转化。后期由于需要用到一个预训练的pkl文件,没能跑成功,所以不知道数据能不能用,不管怎样,先记录下来吧。

对图片和txt进行重命名

#coding=utf-8
import os
import cv2


img_dir='/media/tf/Elements/deetct_car/data_1000/VOCdevkit2007/VOC2007_rename/JPEGImages/'
images=os.listdir(img_dir)

#生成字典
dir_name={}
for i,img in enumerate(images):
    new_name=str(i+1).zfill(12)
    new_name='COCO_train2014_%s.jpg'%new_name
    dir_name[img]=new_name
def get_key(dict_c,value):
    return [v for k,v in dict_c.items() if k==value][0]
"""
#重命名图片并保存
new_dir='/media/tf/Elements/deetct_car/data_1000/VOCdevkit2007/VOC2007_rename/JPEGImages_new/'
if not os.path.exists(new_dir):
    os.mkdir(new_dir)

for i,img_name in enumerate(images):
    img=cv2.imread(img_dir+img_name)
    #print dir_name[img_name]
    print i
    cv2.imwrite(new_dir+dir_name[img_name],img)
"""

"""
#重命名txt文件并保存,用于生成xml
txt_r=open('./train_b.txt','r')
txt_w=open('./train_b_rename.txt','w')

lines=txt_r.readlines()
for line in lines:
    a=get_key(dir_name,line.split()[0])
    txt_w.writelines(a)
    b=line.split()[1:]
    for c in b:
        txt_w.writelines(' '+c)
    txt_w.writelines('\n')
"""

由转化后的txt生成xml

from xml.dom.minidom import Document  
import os  
import os.path   

def writeXml(tmp, imgname, w, h, objbud):  
    doc = Document()  
    #owner  
    annotation = doc.createElement('annotation')  
    doc.appendChild(annotation)  
    #owner  
    folder = doc.createElement('folder')  
    annotation.appendChild(folder)  
    folder_txt = doc.createTextNode("VOC2007")  
    folder.appendChild(folder_txt)  

    filename = doc.createElement('filename')  
    annotation.appendChild(filename)  
    filename_txt = doc.createTextNode(imgname)  
    filename.appendChild(filename_txt)  
    #ones#  
    source = doc.createElement('source')  
    annotation.appendChild(source)  

    database = doc.createElement('database')  
    source.appendChild(database)  
    database_txt = doc.createTextNode("My Database")  
    database.appendChild(database_txt)  

    annotation_new = doc.createElement('annotation')  
    source.appendChild(annotation_new)  
    annotation_new_txt = doc.createTextNode("VOC2007")  
    annotation_new.appendChild(annotation_new_txt)  

    image = doc.createElement('image')  
    source.appendChild(image)  
    image_txt = doc.createTextNode("flickr")  
    image.appendChild(image_txt) 
    #owner
    owner = doc.createElement('owner')  
    annotation.appendChild(owner)  

    flickrid = doc.createElement('flickrid')  
    owner.appendChild(flickrid)  
    flickrid_txt = doc.createTextNode("NULL")  
    flickrid.appendChild(flickrid_txt) 

    ow_name = doc.createElement('name')  
    owner.appendChild(ow_name)  
    ow_name_txt = doc.createTextNode("idannel")  
    ow_name.appendChild(ow_name_txt)
    #onee#  
    #twos#  
    size = doc.createElement('size')  
    annotation.appendChild(size)  

    width = doc.createElement('width')  
    size.appendChild(width)  
    width_txt = doc.createTextNode(str(w))  
    width.appendChild(width_txt)  

    height = doc.createElement('height')  
    size.appendChild(height)  
    height_txt = doc.createTextNode(str(h))  
    height.appendChild(height_txt)  

    depth = doc.createElement('depth')  
    size.appendChild(depth)  
    depth_txt = doc.createTextNode("3")  
    depth.appendChild(depth_txt)  
    #twoe#  
    segmented = doc.createElement('segmented')  
    annotation.appendChild(segmented)  
    segmented_txt = doc.createTextNode("0")  
    segmented.appendChild(segmented_txt)  

    for i in range(0,len(objbud)/4):  
        #threes#  
        object_new = doc.createElement("object")  
        annotation.appendChild(object_new)  

        name = doc.createElement('name')  
        object_new.appendChild(name)  
        name_txt = doc.createTextNode('car')  
        name.appendChild(name_txt)  

        pose = doc.createElement('pose')  
        object_new.appendChild(pose)  
        pose_txt = doc.createTextNode("Unspecified")  
        pose.appendChild(pose_txt)  

        truncated = doc.createElement('truncated')  
        object_new.appendChild(truncated)  
        truncated_txt = doc.createTextNode("0")  
        truncated.appendChild(truncated_txt)  

        difficult = doc.createElement('difficult')  
        object_new.appendChild(difficult)  
        difficult_txt = doc.createTextNode("0")  
        difficult.appendChild(difficult_txt)  
        #threes-1#  
        bndbox = doc.createElement('bndbox')  
        object_new.appendChild(bndbox)  

        xmin = doc.createElement('xmin')  
        bndbox.appendChild(xmin)  
        xmin_txt = doc.createTextNode(objbud[i*4])  
        xmin.appendChild(xmin_txt)  

        ymin = doc.createElement('ymin')  
        bndbox.appendChild(ymin)  
        ymin_txt = doc.createTextNode(objbud[i*4+1])  
        ymin.appendChild(ymin_txt)  

        xmax = doc.createElement('xmax')  
        bndbox.appendChild(xmax)  
        xmax_txt = doc.createTextNode(objbud[i*4+2])  
        xmax.appendChild(xmax_txt)  

        ymax = doc.createElement('ymax')  
        bndbox.appendChild(ymax)  
        ymax_txt = doc.createTextNode(objbud[i*4+3])  
        ymax.appendChild(ymax_txt)  
        #threee-1#  
        #threee#  

    tempfile = tmp +"%s.xml"%imgname[:-4]  
    with open(tempfile, 'w') as f:
        f.write(doc.toprettyxml(indent='\t', encoding='utf-8'))
    return  



gt_txt=open('/media/tf/Elements/add_picture/train_b_rename.txt','r')
xml_path = '/media/tf/Elements/add_picture/xml_rename/'

if not os.path.exists(xml_path):  
    os.mkdir(xml_path)  

index=0
lines=gt_txt.readlines()
for line in lines:
    index+=1
    image_name=line.split()[0]
    print image_name,'-------',index
    gts=line.split()[1:]
    writeXml(xml_path, image_name, 1069, 500, gts)

利用xml和images生成json

# -*- coding:utf-8 -*-
# !/usr/bin/env python

import argparse
import json
import matplotlib.pyplot as plt
import skimage.io as io
import cv2
#from labelme import utils
import numpy as np
import glob
import PIL.Image
import os,sys


class PascalVOC2coco(object):
    def __init__(self, xml=[], save_json_path=''):
        '''
        :param xml: 所有Pascal VOC的xml文件路径组成的列表
        :param save_json_path: json保存位置
        '''
        self.xml = xml
        self.save_json_path = save_json_path
        self.images = []
        self.categories = []
        self.annotations = []
        # self.data_coco = {}
        self.label = []
        self.annID = 1
        self.height = 500
        self.width = 1069

        self.save_json()

    def data_transfer(self):
        for num, json_file in enumerate(self.xml):

            # 进度输出
            sys.stdout.write('\r>> Converting image %d/%d' % (
                num + 1, len(self.xml)))
            sys.stdout.flush()

            self.json_file = json_file
            self.num = num
            path = os.path.dirname(self.json_file)
            path = os.path.dirname(path)
            # path=os.path.split(self.json_file)[0]
            # path=os.path.split(path)[0]
            obj_path = glob.glob(os.path.join(path, 'JPEGImages_new', '*.jpg'))
            with open(json_file, 'r') as fp:
                for p in fp:
                    # if 'folder' in p:
                    #     folder =p.split('>')[1].split('<')[0]
                    if 'filename' in p:
                        self.filen_ame = p.split('>')[1].split('<')[0]

                        self.path = os.path.join(path, 'JPEGImages_new', self.filen_ame.split('.')[0] + '.jpg')
                        if self.path not in obj_path:
                            break


                    if 'width' in p:
                        self.width = int(p.split('>')[1].split('<')[0])
                    if 'height' in p:
                        self.height = int(p.split('>')[1].split('<')[0])

                        self.images.append(self.image())

                    if '<object>' in p:
                        # 类别
                        d = [next(fp).split('>')[1].split('<')[0] for _ in range(9)]
                        self.supercategory = d[0]
                        if self.supercategory not in self.label:
                            self.categories.append(self.categorie())
                            self.label.append(self.supercategory)

                        # 边界框
                        x1 = int(d[-4]);
                        y1 = int(d[-3]);
                        x2 = int(d[-2]);
                        y2 = int(d[-1])
                        self.rectangle = [x1, y1, x2, y2]
                        self.bbox = [x1, y1, x2 - x1, y2 - y1]  # COCO 对应格式[x,y,w,h]

                        self.annotations.append(self.annotation())
                        self.annID += 1

        sys.stdout.write('\n')
        sys.stdout.flush()

    def image(self):
        image = {}
        image['height'] = self.height
        image['width'] = self.width
        image['id'] = self.num + 1
        image['file_name'] = self.filen_ame
        return image

    def categorie(self): 
        categorie = {}
        categorie['supercategory'] = self.supercategory
        categorie['id'] = len(self.label) + 1  # 0 默认为背景
        categorie['name'] = self.supercategory
        return categorie

    def annotation(self):
        annotation = {}
        # annotation['segmentation'] = [self.getsegmentation()]
        annotation['segmentation'] = [list(map(float, self.getsegmentation()))]
        annotation['iscrowd'] = 0
        annotation['image_id'] = self.num + 1
        # annotation['bbox'] = list(map(float, self.bbox))
        annotation['area'] = int(self.bbox[-1]*self.bbox[-2])
        annotation['bbox'] = self.bbox
        annotation['category_id'] = self.getcatid(self.supercategory)
        annotation['id'] = self.annID
        return annotation

    def getcatid(self, label):
        for categorie in self.categories:
            if label == categorie['name']:
                return categorie['id']
        return -1

    def getsegmentation(self):

        try:
            return [0]
            """
            mask_1 = cv2.imread(self.path, 0)
            mask = np.zeros_like(mask_1, np.uint8)
            rectangle = self.rectangle
            mask[rectangle[1]:rectangle[3], rectangle[0]:rectangle[2]] = mask_1[rectangle[1]:rectangle[3],
                                                                         rectangle[0]:rectangle[2]]

            # 计算矩形中点像素值
            mean_x = (rectangle[0] + rectangle[2]) // 2
            mean_y = (rectangle[1] + rectangle[3]) // 2

            end = min((mask.shape[1], int(rectangle[2]) + 1))
            start = max((0, int(rectangle[0]) - 1))

            flag = True
            for i in range(mean_x, end):
                x_ = i;
                y_ = mean_y
                pixels = mask_1[y_, x_]
                if pixels != 0 and pixels != 220:  # 0 对应背景 220对应边界线
                    mask = (mask == pixels).astype(np.uint8)
                    flag = False
                    break
            if flag:
                for i in range(mean_x, start, -1):
                    x_ = i;
                    y_ = mean_y
                    pixels = mask_1[y_, x_]
                    if pixels != 0 and pixels != 220:
                        mask = (mask == pixels).astype(np.uint8)
                        break
            self.mask = mask

            return self.mask2polygons()
            """
        except:
            """
            return [0]
            """
            mask_1 = cv2.imread(self.path, 0)
            mask = np.zeros_like(mask_1, np.uint8)
            rectangle = self.rectangle
            mask[rectangle[1]:rectangle[3], rectangle[0]:rectangle[2]] = mask_1[rectangle[1]:rectangle[3],
                                                                         rectangle[0]:rectangle[2]]

            # 计算矩形中点像素值
            mean_x = (rectangle[0] + rectangle[2]) // 2
            mean_y = (rectangle[1] + rectangle[3]) // 2

            end = min((mask.shape[1], int(rectangle[2]) + 1))
            start = max((0, int(rectangle[0]) - 1))

            flag = True
            for i in range(mean_x, end):
                x_ = i;
                y_ = mean_y
                pixels = mask_1[y_, x_]
                if pixels != 0 and pixels != 220:  # 0 对应背景 220对应边界线
                    mask = (mask == pixels).astype(np.uint8)
                    flag = False
                    break
            if flag:
                for i in range(mean_x, start, -1):
                    x_ = i;
                    y_ = mean_y
                    pixels = mask_1[y_, x_]
                    if pixels != 0 and pixels != 220:
                        mask = (mask == pixels).astype(np.uint8)
                        break
            self.mask = mask

            return self.mask2polygons()


    def mask2polygons(self):
        contours = cv2.findContours(self.mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)  # 找到轮廓线
        bbox=[]
        for cont in contours[1]:
            [bbox.append(i) for i in list(cont.flatten())]
            # map(bbox.append,list(cont.flatten()))
        return bbox # list(contours[1][0].flatten())

    # '''
    def getbbox(self, points):
        # img = np.zeros([self.height,self.width],np.uint8)
        # cv2.polylines(img, [np.asarray(points)], True, 1, lineType=cv2.LINE_AA)  # 画边界线
        # cv2.fillPoly(img, [np.asarray(points)], 1)  # 画多边形 内部像素值为1
        polygons = points
        mask = self.polygons_to_mask([self.height, self.width], polygons)
        return self.mask2box(mask)

    def mask2box(self, mask):
        '''从mask反算出其边框
        mask:[h,w]  0、1组成的图片
        1对应对象,只需计算1对应的行列号(左上角行列号,右下角行列号,就可以算出其边框)
        '''
        # np.where(mask==1)
        index = np.argwhere(mask == 1)
        rows = index[:, 0]
        clos = index[:, 1]
        # 解析左上角行列号
        left_top_r = np.min(rows)  # y
        left_top_c = np.min(clos)  # x

        # 解析右下角行列号
        right_bottom_r = np.max(rows)
        right_bottom_c = np.max(clos)

        # return [(left_top_r,left_top_c),(right_bottom_r,right_bottom_c)]
        # return [(left_top_c, left_top_r), (right_bottom_c, right_bottom_r)]
        # return [left_top_c, left_top_r, right_bottom_c, right_bottom_r]  # [x1,y1,x2,y2]
        return [left_top_c, left_top_r, right_bottom_c - left_top_c,
                right_bottom_r - left_top_r]  # [x1,y1,w,h] 对应COCO的bbox格式

    def polygons_to_mask(self, img_shape, polygons):
        mask = np.zeros(img_shape, dtype=np.uint8)
        mask = PIL.Image.fromarray(mask)
        xy = list(map(tuple, polygons))
        PIL.ImageDraw.Draw(mask).polygon(xy=xy, outline=1, fill=1)
        mask = np.array(mask, dtype=bool)
        return mask

    # '''
    def data2coco(self):
        data_coco = {}
        data_coco['images'] = self.images
        data_coco['categories'] = self.categories#这是总的类别的个数
        data_coco['annotations'] = self.annotations
        return data_coco

    def save_json(self):
        self.data_transfer()
        self.data_coco = self.data2coco()
        # 保存json文件
        json.dump(self.data_coco, open(self.save_json_path, 'w'), indent=4)  # indent=4 更加美观显示


xml_file = glob.glob('./xml_rename/*.xml')
# xml_file=['./Annotations/000032.xml']

PascalVOC2coco(xml_file, './new_rename_noseg.json')
要将VOC数据集格式转换为COCO数据集格式,可以按照以下步骤进行操作: 1. 安装Python COCO API库 COCO API库可以帮助我们处理COCO数据集格式。可以使用以下命令安装COCO API库: ``` pip install pycocotools ``` 2. 编写转换脚本 可以编写Python脚本来将VOC数据集格式转换为COCO数据集格式。下面是一个简单的脚本示例: ``` import os import json from xml.etree import ElementTree as ET from collections import defaultdict def parse_xml(xml_file): tree = ET.parse(xml_file) root = tree.getroot() size = root.find('size') width = int(size.find('width').text) height = int(size.find('height').text) objects = [] for obj in root.findall('object'): name = obj.find('name').text bbox = obj.find('bndbox') xmin = int(bbox.find('xmin').text) ymin = int(bbox.find('ymin').text) xmax = int(bbox.find('xmax').text) ymax = int(bbox.find('ymax').text) objects.append({'name': name, 'bbox': [xmin, ymin, xmax-xmin, ymax-ymin]}) return {'width': width, 'height': height, 'objects': objects} def convert_voc_to_coco(voc_dir, coco_file): images = [] annotations = [] categories = defaultdict(dict) category_id = 1 annotation_id = 1 for root, _, files in os.walk(voc_dir): for file in files: if file.endswith('.xml'): xml_file = os.path.join(root, file) image_file = os.path.splitext(xml_file)[0] + '.jpg' image_id = len(images) + 1 image = {'id': image_id, 'file_name': image_file} images.append(image) data = parse_xml(xml_file) for obj in data['objects']: category_name = obj['name'] if category_name not in categories: categories[category_name] = {'id': category_id, 'name': category_name} category_id += 1 category = categories[category_name] annotation = {'id': annotation_id, 'image_id': image_id, 'category_id': category['id'], 'bbox': obj['bbox']} annotations.append(annotation) annotation_id += 1 coco_data = {'images': images, 'annotations': annotations, 'categories': list(categories.values())} with open(coco_file, 'w') as f: json.dump(coco_data, f) if __name__ == '__main__': voc_dir = 'path/to/voc' coco_file = 'path/to/coco.json' convert_voc_to_coco(voc_dir, coco_file) ``` 在这个脚本中,我们使用`parse_xml`函数从VOC格式的XML文件中解析出图像和目标位置信息,然后使用`convert_voc_to_coco`函数将整个VOC数据集转换为COCO格式的JSON文件。 3. 运行脚本 将VOC格式的数据集放置在指定的目录下,然后运行上面的Python脚本即可将VOC数据集格式转换为COCO数据集格式。 ``` python voc_to_coco.py ``` 转换后的COCO格式的JSON文件将保存在指定的位置。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值