从mask生成anchor标签【pascal格式及coco格式】

现在手中数据标签只有Mask,做检测任务需要将其转化为bbox的pascal格式、coco格式,任务如下:

从mask生成anchor标签【pascal格式及coco格式】_第1张图片 mask图像(.png) 从mask生成anchor标签【pascal格式及coco格式】_第2张图片 step1: 标出外围框bbox 从mask生成anchor标签【pascal格式及coco格式】_第3张图片 step2: 生成xml文件(voc格式)

完整代码稍后更新到github


Step1 : 根据mask生成外围框   

########## for test
image = cv2.imread('00080.png')
# 灰度图像
gray = cv2.cvtColor(image.copy(), cv2.COLOR_BGR2GRAY)

# contours记录的是所有的框的信息,
ret, thresh = cv2.threshold(gray, 127, 255,cv2.THRESH_BINARY )
thresh_cont, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# 每次输出框的坐标(x,y,w,h),并画出带框图片
for i in range(len(contours)):
    x, y, w, h = cv2.boundingRect(contours[i])
    cv2.rectangle(image, (x, y), (x + w, y + h), (255, 0, 0), 2)
cv2.imwrite('test.png', image)

Step2 : 记录框的坐标并转化为pascal\coco格式  

  1. pascal格式
######## 生成xml文件
import xml.etree.cElementTree as ET
import numpy as np
import os
import cv2

def beatau(e,level=0):
    if len(e)>0:
        e.text='\n'+'\t'*(level+1)
        for child in e:
           beatau(child,level+1)
        child.tail=child.tail[:-1]
    e.tail='\n' + '\t'*level
 
def ToXml(name, contours):
    root = ET.Element('annotation')#根节点
    erow1 = ET.Element('folder')#节点1
    erow1.text= "VOC"
    
    
    erow2 = ET.Element('filename')#节点2
    erow2.text= str(name)
    
    erow3 = ET.Element('size')#节点3
    erow31 = ET.Element('width')
    erow31.text = "512"
    erow32 = ET.Element('height')
    erow32.text = "512"
    erow33 = ET.Element('depth')
    erow33.text = "3" 
    erow3.append(erow31)
    erow3.append(erow32)
    erow3.append(erow33)
    root.append(erow1)
    root.append(erow2)
    root.append(erow3)  
    for i in range(len(contours)):
        x, y, w, h = cv2.boundingRect(contours[i]) 
        if w >=3 and h>=3:
            erow4 = ET.Element('object')
            erow41 = ET.Element('name')
            erow41.text = 'lesion'
            erow42 = ET.Element('bndbox')
            erow4.append(erow41)
            erow4.append(erow42)
            erow421 = ET.Element('xmin')
            erow421.text = str(x)
            erow422 = ET.Element('ymin')
            erow422.text = str(y)
            erow423 = ET.Element('xmax')
            erow423.text = str(x + np.round(w).astype(int))
            erow424 = ET.Element('ymax')
            erow424.text = str(y + np.round(h).astype(int))
            erow42.append(erow421)
            erow42.append(erow422)
            erow42.append(erow423)
            erow42.append(erow424)
            root.append(erow4) 
    beatau(root)      
    
    return ET.ElementTree(root)

# 记录转化数k
k = 0
for img in os.listdir('./label_color'):
    image = cv2.imread('./label_color/'+img)
    if img[-1] == 'g':
        print(img, k)
        k = k+1
        gray = cv2.cvtColor(image.copy(), cv2.COLOR_BGR2GRAY)
        ret, thresh = cv2.threshold(gray, 127, 255,cv2.THRESH_BINARY )
        thresh_cont, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        # 每次输出框的坐标(x,y,w,h)
        for i in range(len(contours)):
            x, y, w, h = cv2.boundingRect(contours[i])
            # 对于像素小于3*3的框,忽略,不作为检测框
            #if w>=3 and h>=3:
            #    cv2.rectangle(image, (x, y), (x + w, y + h), (255, 0, 0), 2)
        cv2.imwrite('./brain_data/label_recolor/test_'+ img, image)
        # 生成XML文件
        XML = ToXml(img, contours)
        XML.write('./brain_data/label_xml/{}.xml'.format(img[:-4]))

2. coco格式(从pasal转成coco)

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 = 0
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 , , , 
        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  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 , , , , 
            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 , , , , when subelem is 
                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  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 = './keras-retinanet/VOC2007/Annotations'
    json_file = './coco.json'
    parseXmlFiles(xml_path)
    json.dump(coco, open(json_file, 'w')) 
  

 

你可能感兴趣的:(medical,image,python,pascal,python,pascal)