有一些损坏图片能够正常打开,但是在训练中可能会报错。我的文件夹如图所示。
运行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)
标签标注常见错误如下:没有图片尺寸;图片尺寸为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文件夹,里面有输出信息。
如果是类别错误、坐标越界和没有标注坐标,只能手动修改。如果是图片尺寸有误,可通过以下代码批量修改。
先运行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 = """\
VOC2007
%06d.jpg
NULL
company
%d
%d
%d
0
"""
objstr = """\
"""
tailstr = '''\
'''
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--检查图片是否损坏、图片后缀是否与实际图片类型对应