yolov3从头实现(一)-- xml标签制作与读取

标签制作与读取

这里说的标签制作并非yolov3所需要的标签,而是一般的没有处理的标签

一、标签的制作

1、制作工具及制作结果

制作工具使用的是:labelImg
在这里插入图片描述用labelimg制作完成后的标签
在这里插入图片描述

二、xml标签的读取方法及实现

1、数据文件结构

在这里插入图片描述

2、定义xml文件解析器类,用于获取xml文件中的标注信息

类名:

3、测试xml文件解析类功能

在这里插入图片描述

4、xml文件解析器类实现代码

import numpy as np
from xml.etree.ElementTree import parse  # xml解析器模块
class PascalVocXmlParser(object):    # 定义xml解析器类
    def __init__(self):
        pass
    # 1、依据xml文件的地址获取标注图片名称
    def get_fname(self, annotation_file):
        '''
        依据xml文件的地址获取标注图片名称
        :param annotation_file: xml文件的地址
        :return: 标注图片名称
        '''
        root = self._root_tag(annotation_file)
        return root.find("filename").text
    # 2、依据xml文件的地址获取标注图片的宽
    def get_width(self, annotation_file):
        '''
        依据xml文件的地址获取标注图片的宽
        :param annotation_file: xml文件的地址
        :return: 标注图片的宽
        '''
        tree = self._tree(annotation_file)
        for elem in tree.iter():
            if 'width' in elem.tag:
                return int(elem.text)
    # 3、依据xml文件的地址获取标注图片的高
    def get_height(self, annotation_file):
        '''
        依据xml文件的地址获取标注图片的高
        :param annotation_file: xml文件的地址
        :return: 标注图片的高
        '''
        tree = self._tree(annotation_file)
        for elem in tree.iter():
            if 'height' in elem.tag:
                return int(elem.text)
    # 4、依据xml文件的地址获取标注图片的所有标注框的分类类别
    def get_labels(self, annotation_file):
        '''
        依据xml文件的地址获取标注图片的所有标注框的分类类别
        :param annotation_file: xml文件的地址
        :return: 所有标注框的分类类别列表
        '''
        root = self._root_tag(annotation_file)
        labels = []
        obj_tags = root.findall("object")
        for t in obj_tags:
            labels.append(t.find("name").text)
        return labels
    # 5、依据xml文件的地址获取标注图片的所有标注框的坐标(左上右下形式的坐标)
    def get_boxes(self, annotation_file):
        '''
        依据xml文件的地址获取标注图片的所有标注框的坐标(左上右下形式的坐标)
        :param annotation_file: xml文件的地址
        :return: 依据xml文件的地址获取标注图片的所有标注框的坐标(左上右下形式的坐标)列表
        '''
        root = self._root_tag(annotation_file)
        bbs = []
        obj_tags = root.findall("object")
        for t in obj_tags:
            box_tag = t.find("bndbox")
            x1 = box_tag.find("xmin").text
            y1 = box_tag.find("ymin").text
            x2 = box_tag.find("xmax").text
            y2 = box_tag.find("ymax").text
            box = np.array([int(float(x1)), int(float(y1)), int(float(x2)), int(float(y2))])
            bbs.append(box)
        bbs = np.array(bbs)
        return bbs
    # 6、依据xml文件的地址获取xml文件信息
    def _root_tag(self, fname):
        '''
        依据xml文件的地址获取xml文件信息
        :param fname: xml文件的地址
        :return: xml内容对象
        '''
        tree = parse(fname)
        root = tree.getroot()
        return root
    # 7、依据xml文件的地址获取xml文件解析器
    def _tree(self, fname):
        '''
         依据xml文件的地址获取xml文件解析器
        :param fname: xml文件的地址
        :return: xml解析器
        '''
        tree = parse(fname)
        return tree


xmlpath = "D:\\pythonproject\\yolov3\\基于yolov3的门牌号识别\\data\\ann\\2.xml"
p = PascalVocXmlParser()
print(p.get_fname(xmlpath))
print(p.get_width(xmlpath))
print(p.get_height(xmlpath))
print(p.get_labels(xmlpath))
print(p.get_boxes(xmlpath))

三、简单的目录操作

# 1、获取当前目录
import os
PROJECT_ROOT = os.path.dirname(__file__)  # D:/pythonproject/yolov3/基于yolov3的门牌号识别
# 2、组合字符串
ann_dir = os.path.join(PROJECT_ROOT, "data", "ann",
                       "*.xml")  # 组合字符串 得到'D:/pythonproject/yolov3/基于yolov3的门牌号识别\\data\\ann\\*.xml'
img_dir = os.path.join(PROJECT_ROOT, "data", "img")  # 组合字符串 得到'D:/pythonproject/yolov3/基于yolov3的门牌号识别\\data\\img'
train_ann_fnames = glob.glob(ann_dir)  # 以列表形式获取到当前目录下符合字符串的所有文件的绝对地址,D:\pythonproject\yolov3\基于yolov3的门牌号识别下的data下的img下的所有xml文件的绝对地址
# 形如 ['D:/pythonproject/yolov3/基于yolov3的门牌号识别\\data\\ann\\1.xml', 'D:/pythonproject/yolov3/基于yolov3的门牌号识别\\data\\ann\\10.xml', 'D:/pythonproject/yolov3/基于yolov3的门牌号识别\\data\\ann\\11.xml']

四、制作标签列表

将一个标签信息都整合到一个自定义类中

1、定义一个类,用于存放标签信息

另外还有就是计算当前的xml文件对应的图片的绝对路径

class Annotation(object):
    def __init__(self, filename):
        self.fname = filename       # xml文件对应的图片的地址
        self.labels = []            # 存放标注框的分类名称
        self.coded_labels = []      # 存放标注框的分类编码
        self.boxes = None           # 存放一张图上的多个标注框信息的矩阵

    def add_object(self, x1, y1, x2, y2, name, code):
        '''
        :param x1: 标注框的左上坐标x值
        :param y1: 标注框的左上坐标y值
        :param x2: 标注框的右下坐标x值
        :param y2: 标注框的右下坐标y值
        :param name: 标注框的分类名称
        :param code: 标注框的分类编码   属于(0,1,...,n)中的一个
        :return:
        '''
        self.labels.append(name)            # 将标注框的分类名称添加到labels列表中
        self.coded_labels.append(code)      # 将标注框的分类编码添加到coded_labels列表中
        
        if self.boxes is None:              # 如果boxes 为空,则将本次标注框信息转化成矩阵格式添加到boxes中
            self.boxes = np.array([x1, y1, x2, y2]).reshape(-1,4)
        else:
            box = np.array([x1, y1, x2, y2]).reshape(-1, 4)      # 将坐标值转换成 矩阵格式 形状为 [x1, y1, x2, y2]
            self.boxes = np.concatenate([self.boxes, box])      # 如果boxes不为空 利用矩阵拼接函数将self.boxes和box拼接到一起,

2、将数据中的所有xml文件信息整合到Annotation类中

def parse_annotation(ann_fname, img_dir, labels_naming=[]):
    '''
    :param ann_fname: xml文件的地址
    :param img_dir: 存放所有图片的文件夹地址
    :param labels_naming: 标签列表即分类种类 ['分类名1','分类名2',...,'分类名n']
    :return: [图片地址] [[图片中第1个标注框坐标]...[图片中第n个标注框坐标]],[[图片中第1个标注框坐标的分类标签]...[图片中第n个标注框坐标的分类标签]
    例如:D:/pythonproject/yolov3/基于yolov3的门牌号识别\data\img\2.png [[ 99   5 113  28][114   8 122  31][121   6 133  29]] [2, 1, 0]
    '''
    parser = PascalVocXmlParser()
    fname = parser.get_fname(ann_fname)  # 依据xml文件的地址,获取到xml文件对应的标注图片名称
    # os.path.join(img_dir, fname)获取到xml文件对应的图片的地址
    annotation = Annotation(os.path.join(img_dir, fname))  # 创建

    labels = parser.get_labels(ann_fname)  # 依据xml文件的地址,获取到xml文件对应的标注图片的所有标注框的分类标签
    boxes = parser.get_boxes(ann_fname)  # 依据xml文件的地址,获取到xml文件对应的标注图片的所有标注框的左上右下坐标
    
    for label, box in zip(labels, boxes):   # 一起遍历 一张图片上的标注框分类标签和标注框
        x1, y1, x2, y2 = box                # 获取到标注框的四个坐标值
        if label in labels_naming:          # 如果标注框分类标签在目标分类种类中 即 ['分类名1','分类名2',...,'分类名n']中
            # labels_naming.index(label) 计算label在['分类名1','分类名2',...,'分类名n']中的下标,作为分类的编码
            annotation.add_object(x1, y1, x2, y2, name=label, code=labels_naming.index(label))  # 将标注框信息添加到annotation类的boxes属性中
    return annotation.fname, annotation.boxes, annotation.coded_labels  # 返回一张图片的所有标注框的分类名称,标注框信息,编码标签

五、总结

通过函数parse_annotation()可以读取到一个xml文件的信息,并能过获取到xml文件对应的图片的地址。
例如:
D:/pythonproject/yolov3/基于yolov3的门牌号识别\data\img\2.png --xml文件对应的图片的地址。
[[ 99 5 113 28][114 8 122 31][121 6 133 29]] --图片上的anchor的左上右下坐标
[2, 1, 0] --每个anchor的分类

  • 1
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值