VOC格式数据集的图片和标注文件有效性检查

1.检查图片是否损坏

有一些损坏图片能够正常打开,但是在训练中可能会报错。我的文件夹如图所示。

运行is_valid.py,检查图片是否损坏。

import os
from PIL import Image

def IsValidImage(path):
    '''
      检查文件是否损坏
      '''
    try:
        bValid = True
        fileObj = open(path, 'rb')  # 以二进制形式打开
        buf = fileObj.read()
        if not buf.startswith(b'\xff\xd8'):  # 是否以\xff\xd8开头
            bValid = False
        elif buf[6:10] in (b'JFIF', b'Exif'):  # “JFIF”的ASCII码
            if not buf.rstrip(b'\0\r\n').endswith(b'\xff\xd9'):  # 是否以\xff\xd9结尾
                bValid = False
        else:
            try:
                Image.open(fileObj).verify()
            except Exception as e:
                bValid = False
                print(e)
    except Exception as e:
        return False
    return bValid


root = "JPEGImages"
valid_path=[]
invalid_path=[]
img = os.listdir(root)  # 文件夹下文件名列表
for i in range(len(img)):
    path = os.path.join(root, img[i])
    if IsValidImage(path):
       valid_path.append(path)
    else:
       invalid_path.append(path)
       #os.remove(path)  # 删除无效文件
print(invalid_path)

2.检查标签是否正确

标签标注常见错误如下:没有图片尺寸;图片尺寸为0;类别错误;坐标越界;没有标注坐标。

运行 label_check.py

import xml.etree.ElementTree as ET
import os
from PIL import Image

classes = ["face", "mask"]
def check(image_id, img_size):
    in_file = open('Annotations/%s.xml'%(image_id), 'r', encoding='UTF-8')
    tree = ET.parse(in_file)
    root = tree.getroot()
    # 坐标是否存在
    if root.find('object') is None:
        coordinate.write(str(image_id) + '\n')
    # 图片尺寸坐标是否存在
    size = root.find('size')
    try:
        w = size.find('width').text
        h = size.find('height').text
        if int(w) == 0 or int(h) == 0: #检查图片尺寸是否为0
           imagesize.write(str(image_id) + '\n')
    except AttributeError:
        imagesize.write(str(image_id) + '\n')
    for obj in root.iter('object'):
        # 标签是否正确
        # difficult = obj.find('difficult').text
        cls = obj.find('name').text
        if cls not in classes:
            lable_class.write(str(image_id) + '\n')
        # 坐标是否越界
        xmlbox = obj.find('bndbox')
        b = (int(xmlbox.find('xmin').text), int(xmlbox.find('ymin').text), int(xmlbox.find('xmax').text), int(xmlbox.find('ymax').text))
        if b[0] < 0 or b[1] < 0 or b[2] > img_size[0] or b[3] > img_size[1] or b[2] < 0 or b[3] < 0:
            cross.write(str(image_id) + '\n')
        elif b[2]==0 or b[3]==0:
            cross.write(str(image_id) + '\n')

def list(root):
    all_file=[]
    img = os.listdir(root)
    for i in range(len(img)):
        file = os.path.splitext(img[i])[0]
        all_file.append(int(file))
    all_file.sort()
    print(all_file)
    with open('list.txt', 'w') as f:
        for i in range(len(all_file)):
            f.write('%06d\n' % (all_file[i]))
        f.close()

#产生list.txt文件
list("JPEGImages")

#检查lable
image_ids = open('list.txt').read().strip().split()
if not os.path.exists("Check"):
    os.mkdir("Check")
lable_class = open('Check/classes.txt', 'w')
cross = open('Check/cross.txt', 'w')
coordinate=open('Check/coordinate.txt', 'w')
imagesize = open('Check/imagesize.txt', 'w')
for image_id in image_ids:
    print(image_id)
    img = Image.open('JPEGImages/%s.jpg'%(image_id))
    check(image_id, img.size)
cross.close()
imagesize.close()

得到Check文件夹,里面有输出信息。

3.图片尺寸修改

如果是类别错误、坐标越界和没有标注坐标,只能手动修改。如果是图片尺寸有误,可通过以下代码批量修改。

先运行create_txt.py,生成test.txt。

import os
import xml.etree.ElementTree as ET

with open('test.txt', 'w') as f:
    file = open('Check/imagesize.txt', 'r')
    for line in file.readlines():
        filename=line.strip('\n')
        print(filename)
        in_file = open('Annotations/%s.xml'%(filename),'r', encoding='UTF-8')
        f.write(("JPEGImages"+"/"+str(filename)+".jpg") + '\n')
        tree=ET.parse(in_file)
        root = tree.getroot()
        i=0
        for obj in root.iter('object'):
            cls = obj.find('name').text
            i+=1
        f.write(str(i) + '\n')
        for obj in root.iter('object'):
            cls = obj.find('name').text
            if cls == "face":
                f.write(str(0) + ' ')
            elif cls == "mask":
                f.write(str(1) + ' ')
            xmlbox = obj.find('bndbox')
            f.write((xmlbox.find('xmin').text + ' ' + xmlbox.find('ymin').text + ' ' + xmlbox.find('xmax').text + ' ' + xmlbox.find('ymax').text) + '\n')
f.close()

然后运行create_voc.py,替换Annotations中的xml文件。

# -*- coding: utf-8 -*-
"""
Created on 18-5-13
@author: CHR
"""
from skimage import io
import shutil
import random
import os
import string

headstr = """\
<annotation>
    <folder>VOC2007</folder>
    <filename>%06d.jpg</filename>
    <source>
        <database>My Database</database>
        <annotation>PASCAL VOC2007</annotation>
        <image>flickr</image>
        <flickrid>NULL</flickrid>
    </source>
    <owner>
        <flickrid>NULL</flickrid>
        <name>company</name>
    </owner>
    <size>
        <width>%d</width>
        <height>%d</height>
        <depth>%d</depth>
    </size>
    <segmented>0</segmented>
"""
objstr = """\
    <object>
        <name>%s</name>
        <pose>Unspecified</pose>
        <truncated>0</truncated>
        <difficult>0</difficult>
        <bndbox>
            <xmin>%d</xmin>
            <ymin>%d</ymin>
            <xmax>%d</xmax>
            <ymax>%d</ymax>
        </bndbox>
    </object>
"""

tailstr = '''\
</annotation>
'''


def all_path(filename):
    return os.path.join(filename)


def writexml(idx, head, bbxes, tail):
    filename = all_path("Annotations/%06d.xml" % (idx))
    f = open(filename, "w")
    f.write(head)
    for bbx in bbxes:
        if bbx[0] == 0:
            f.write(objstr % ('face', bbx[1], bbx[2], bbx[3], bbx[4]))
        elif bbx[0] == 1:
            f.write(objstr % ('mask', bbx[1], bbx[2], bbx[3], bbx[4]))

    f.write(tail)
    f.close()

def replace_xml():
    f_bbx = open('test.txt', 'r')
    file = open('Check/imagesize.txt', 'r')
    a=[]
    for line in file.readlines():
        fname=line.strip('\n')
        a.append(fname)
    print(a)
    # a = open('check/imagesize.txt').read().strip().split()
    i=0
    while True:
        filename = f_bbx.readline().strip('\n')
        print(filename)
        if not filename:
            break
        im = io.imread(all_path(filename))
        idx = int(a[i])
        print(idx)
        head = headstr % (idx, im.shape[1], im.shape[0], im.shape[2])
        nums = f_bbx.readline().strip('\n')
        bbxes = []
        for ind in range(int(nums)):
            bbx_info = f_bbx.readline().strip(' \n').split(' ')
            bbx_in = bbx_info
            bbx = [int(float(bbx_in[i])) for i in range(len(bbx_in))]
            bbxes.append(bbx)
        writexml(idx, head, bbxes, tailstr)
        i+=1
        idx =int(a[i])
    f_bbx.close()
    file.close()
    return idx

if __name__ == '__main__':
   replace_xml()

 

部分参考

widerface数据集下载及转voc2007格式

python--检查图片是否损坏、图片后缀是否与实际图片类型对应

  • 4
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值