文章目录

    • 代码
  • 20200708 无需读取图片分辨率 直接指定

在做yolo标注时,有时我们需要剔除标注中的一些错误的标注或者超过一定范围的标注,

比如我们希望将中心点靠近图像边缘Δ距离的标注框给剔除,可以使用以下方法

代码

# -*- coding: utf-8 -*-
"""
@File    : yolo_annotation_clean.py
@Time    : 2020/5/13 15:29
@Author  : Dontla
@Email   : sxana@qq.com
@Software: PyCharm
"""
import os
import re
import shutilimport cv2
import random# 排序函数,对文件列表进行排序(filenames为文件夹文件的文件名的字符串列表,pattern为正则表达式,它是字符串类型)
def sort_filenames(filenames, pattern):# (1)可以以len排序,len相同的字符串,会再以0-9排序,能获得我们想要的结果# filenames.sort(key=len)# (2)这种排序失败了# filenames.sort(key=lambda x: x[16:])# print(filenames[0][16:])# 1).txt# (3)用lambda配合正则表达式(将filenames中对象一一取出赋给x,通过冒号后的表达式运算后将结果返回给key)# 数字字符串排序貌似还是以字符顺序而不是数字大小来排的,可能要先转化为数字(而re.findall('\((.*?)\)', x)返回的是字符串列表,要把它转换成数字列表)filenames.sort(key=lambda x: list(map(eval, re.findall(pattern, x))))def extract_content(content_):# 注意,一开始用的第一种,结果只有一行的情况没有被提取出来,要去掉后面的\n,谨记# content_extract = re.findall('(.*?) (.*?) (.*?) (.*?) (.*?)\n', content)# content_extract = re.findall('(.*?) (.*?) (.*?) (.*?) (.*?)', content)content_extract_ = re.findall('(\d+.?\d*) (\d+.?\d*) (\d+.?\d*) (\d+.?\d*) (\d+.?\d*)', content_)return content_extract_if __name__ == '__main__':# 记得路径尾部加“/”,不然调用join方法是它会用“\”替代,那样不好,容易造成转义字符问题。# ../表示上一层路径# 以下三个路径是相对当前文件的source_img_path = './source_img/'source_txt_path = './source_txt/'target_txt_path = './target_txt/'# 读取source_txt_path路径下所有文件(包括子文件夹下文件)filenames = os.listdir(source_txt_path)# 调用自定义的sort_filenames函数对filenames重新排序(如果不重新排序它貌似会以1、10、100...的顺序排而不是以1、2、3...的顺序)# \是转义字符# pattern = '\((.*?)\)'# Dontla 20200204 现在文件名就是纯数字,所以pattern也得改pattern = '(.*?).txt'sort_filenames(filenames, pattern)# print(filenames)# ['1.txt', '2.txt', '3.txt', '4.txt', '5.txt', '6.txt', '7.txt', '8.txt', '9.txt', '10.txt']# 打开文件提取其中数字并将内容重构后写入新文件for filename in filenames:# 打开文件:with open(os.path.join(source_txt_path, filename), 'r', encoding='utf-8') as f:# 读取文本文件全部内容content = f.read()# 提取数据content_extract = extract_content(content)# print(content_extract)# [('0', '0.631250', '0.270833', '0.156250', '0.277778'), ('0', '0.372656', '0.861111', '0.156250', '0.277778'), ('0', '0.448437', '0.447222', '0.156250', '0.277778'), ('0', '0.837500', '0.637500', '0.156250', '0.277778'), ('0', '0.155469', '0.268056', '0.156250', '0.277778')]# ...# 获取当前图片分辨率信息(这样不论图片尺寸多少都能成功转换)(re.findall()返回的是列表,需要将它转换成字符串)# 读取图片img = cv2.imread('{}{}.jpg'.format(source_img_path, ''.join(re.findall('(.*?).txt', filename))))# 获取图片分辨率img_width = img.shape[1]img_height = img.shape[0]# print(img_height, img_width)    # 720 1280# 创建写入内容变量write_content = ''# 读取标注框数据for box_tuple in content_extract:# 将元组字符串转换成列表数字box_evar = list(map(eval, box_tuple))# print(box_evar)# [0, 0.63125, 0.270833, 0.15625, 0.277778]# ...# 映射变量class_id = box_evar[0]x, y = box_evar[1] * img_width, box_evar[2] * img_heightw, h = box_evar[3] * img_width, box_evar[4] * img_height# print(class_id, x, y, w, h)# 0 808.0 194.99975999999998 200.0 200.00016000000002# 【错误类筛选】if class_id != 0:print('【类标注错误】:')print(filename)print(box_evar)print('[{}, {}, {}, {}, {}]'.format(round(x - w / 2), round(y - h / 2), round(x + w / 2),round(y + h / 2), class_id))print('\n')continue# 【中心点超出范围】    elif x < 0 or x >= img_width or y < 0 or y >= img_height:print('【标注框中心点超出图片范围】:')print(filename)print(box_evar)print('[{}, {}, {}, {}, {}]'.format(round(x - w / 2), round(y - h / 2), round(x + w / 2),round(y + h / 2), class_id))print('\n')continue# 【标注框顶点超出范围】elif round(x - w / 2) < 0 \or round(x + w / 2) > img_width \or round(x - w / 2) >= round(x + w / 2) \or round(y - h / 2) < 0 \or round(y + h / 2) > img_height \or round(y - h / 2) >= round(y + h / 2):print('【标注框顶点超出范围】:')print(filename)print(box_evar)print('[{}, {}, {}, {}, {}]'.format(round(x - w / 2), round(y - h / 2), round(x + w / 2),round(y + h / 2), class_id))print('\n')continue# 【框的长宽差太多】elif w / h > 2 or h / w > 2:print('【框的长宽比不合适】:')print(filename)print(box_evar)print('[{}, {}, {}, {}, {}]'.format(round(x - w / 2), round(y - h / 2), round(x + w / 2),round(y + h / 2), class_id))print('\n')continue# 【不是方形框】# elif w / h < 0.99:#     print('【不是方形框】:')#     print(filename)#     print(box_evar)#     print('[{}, {}, {}, {}, {}]'.format(round(x - w / 2), round(y - h / 2), round(x + w / 2),#                                         round(y + h / 2), class_id))#     print('\n')#     continue# 【框太小或太大(边长小于80或大于300)】elif w < 80 or w > 300 or h < 80 or h > 300:print('【标注框大小有问题】:')print(filename)print(box_evar)print('[{}, {}, {}, {}, {}]'.format(round(x - w / 2), round(y - h / 2), round(x + w / 2),round(y + h / 2), class_id))print('\n')continue# 将筛选后的标注框加入到write_content中:write_content += '{} {} {} {} {}\n'.format(box_evar[0], box_evar[1], box_evar[2], box_evar[3],box_evar[4])# print(filename)# print(write_content)# 【去除空文件】# if write_content == '':#     print('空文件:{}'.format(filename))#     # print('content:{}'.format(content))#     cv2.imwrite('null_img\\{}.jpg'.format(''.join(re.findall('(.*?).txt', filename))), img)#     print('将图片拷贝到“空文件”文件夹')#     continue# else:#     write_content = write_content.strip()#     with open(os.path.join(target_txt_path, filename), 'w', encoding='utf-8') as f2:#         f2.write(write_content)# 【不去除空文件】write_content = write_content.strip()with open(os.path.join(target_txt_path, filename), 'w', encoding='utf-8') as f2:f2.write(write_content)

20200708 无需读取图片分辨率 直接指定


# -*- coding: utf-8 -*-
"""
@File    : yolo_annotation_clean.py
@Time    : 2020/5/13 15:29
@Author  : Dontla
@Email   : sxana@qq.com
@Software: PyCharm
"""
import os
import re
import shutilimport cv2
import random# 排序函数,对文件列表进行排序(filenames为文件夹文件的文件名的字符串列表,pattern为正则表达式,它是字符串类型)
def sort_filenames(filenames, pattern):# (1)可以以len排序,len相同的字符串,会再以0-9排序,能获得我们想要的结果# filenames.sort(key=len)# (2)这种排序失败了# filenames.sort(key=lambda x: x[16:])# print(filenames[0][16:])# 1).txt# (3)用lambda配合正则表达式(将filenames中对象一一取出赋给x,通过冒号后的表达式运算后将结果返回给key)# 数字字符串排序貌似还是以字符顺序而不是数字大小来排的,可能要先转化为数字(而re.findall('\((.*?)\)', x)返回的是字符串列表,要把它转换成数字列表)filenames.sort(key=lambda x: list(map(eval, re.findall(pattern, x))))def extract_content(content_):# 注意,一开始用的第一种,结果只有一行的情况没有被提取出来,要去掉后面的\n,谨记# content_extract = re.findall('(.*?) (.*?) (.*?) (.*?) (.*?)\n', content)# content_extract = re.findall('(.*?) (.*?) (.*?) (.*?) (.*?)', content)content_extract_ = re.findall('(\d+.?\d*) (\d+.?\d*) (\d+.?\d*) (\d+.?\d*) (\d+.?\d*)', content_)return content_extract_if __name__ == '__main__':# 记得路径尾部加“/”,不然调用join方法是它会用“\”替代,那样不好,容易造成转义字符问题。# ../表示上一层路径# 以下三个路径是相对当前文件的source_txt_path = './source_txt/'target_txt_path = './target_txt/'# 获取图片分辨率img_width = 1280img_height = 720# 错误标注计数器error_boxs_num = 0# 读取source_txt_path路径下所有文件(包括子文件夹下文件)filenames = os.listdir(source_txt_path)# 调用自定义的sort_filenames函数对filenames重新排序(如果不重新排序它貌似会以1、10、100...的顺序排而不是以1、2、3...的顺序)# \是转义字符# pattern = '\((.*?)\)'# Dontla 20200204 现在文件名就是纯数字,所以pattern也得改pattern = '(.*?).txt'sort_filenames(filenames, pattern)# print(filenames)# ['1.txt', '2.txt', '3.txt', '4.txt', '5.txt', '6.txt', '7.txt', '8.txt', '9.txt', '10.txt']# 打开文件提取其中数字并将内容重构后写入新文件for filename in filenames:# 打开文件:with open(os.path.join(source_txt_path, filename), 'r', encoding='utf-8') as f:# 读取文本文件全部内容content = f.read()# 提取数据content_extract = extract_content(content)# 创建写入内容变量write_content = ''# 读取标注框数据for box_tuple in content_extract:# 将元组字符串转换成列表数字box_evar = list(map(eval, box_tuple))# print(box_evar)# [0, 0.63125, 0.270833, 0.15625, 0.277778]# ...# 映射变量class_id = box_evar[0]x, y = box_evar[1] * img_width, box_evar[2] * img_heightw, h = box_evar[3] * img_width, box_evar[4] * img_height# print(class_id, x, y, w, h)# 0 808.0 194.99975999999998 200.0 200.00016000000002# 【错误类筛选】if class_id != 0:error_boxs_num += 1print('【类标注错误】:')print(filename)print(box_evar)print('[{}, {}, {}, {}, {}]'.format(round(x - w / 2), round(y - h / 2), round(x + w / 2),round(y + h / 2), class_id))print('\n')continue# 【中心点超出范围】    elif x < 0 or x >= img_width or y < 0 or y >= img_height:error_boxs_num += 1print('【标注框中心点超出图片范围】:')print(filename)print(box_evar)print('[{}, {}, {}, {}, {}]'.format(round(x - w / 2), round(y - h / 2), round(x + w / 2),round(y + h / 2), class_id))print('\n')continue# 【标注框顶点超出范围】elif round(x - w / 2) < 0 \or round(x + w / 2) > img_width \or round(x - w / 2) >= round(x + w / 2) \or round(y - h / 2) < 0 \or round(y + h / 2) > img_height \or round(y - h / 2) >= round(y + h / 2):error_boxs_num += 1print('【标注框顶点超出范围】:')print(filename)print(box_evar)print('[{}, {}, {}, {}, {}]'.format(round(x - w / 2), round(y - h / 2), round(x + w / 2),round(y + h / 2), class_id))print('\n')continue# 【框的长宽差太多】elif w / h > 2 or h / w > 2:error_boxs_num += 1print('【框的长宽比不合适】:')print(filename)print(box_evar)print('[{}, {}, {}, {}, {}]'.format(round(x - w / 2), round(y - h / 2), round(x + w / 2),round(y + h / 2), class_id))print('\n')continue# 【框太小或太大(边长小于80或大于300)】elif w < 100 or w > 300 or h < 100 or h > 300:error_boxs_num += 1print('【标注框大小有问题】:')print(filename)print(box_evar)print('[{}, {}, {}, {}, {}]'.format(round(x - w / 2), round(y - h / 2), round(x + w / 2),round(y + h / 2), class_id))print('\n')continue# 将筛选后的标注框加入到write_content中:write_content += '{} {} {} {} {}\n'.format(box_evar[0], box_evar[1], box_evar[2], box_evar[3],box_evar[4])# 不去除空文件write_content = write_content.strip()with open(os.path.join(target_txt_path, filename), 'w', encoding='utf-8') as f2:f2.write(write_content)# 打印错误标注框数量print('错误标注框数量:{}'.format(error_boxs_num))

结果:

yolo标注的数据清洗相关推荐

  1. 标注(annotation)的反向优化策略 将Yunyang tensorflow-yolov3 predicted转换为正常yolo标注

    文章目录 原 20200708 当起始图片序号不是1时,可改成以下代码 原 执行evaluate.py后,会在predicted文件夹生成预测信息 如图,将Yunyang tensorflow-yol ...

  2. yolo 标注转VOC格式(标注转换器)

    参考文章1:yolo标注转voc 参考文章2:YOLOV3 将自己的txt转为XML,再将XML转为符合YOLO要求的txt格式 参考文章3:yolov3 制作voc数据格式:xml转换成txt 参考 ...

  3. 彻底搞懂VOC/YOLO标注格式《补充》

    引言:在深度学习中,标注格式占据了半壁江山,没有这些标注,深度学习就是盲人摸象(只针对有监督学习哦!!!),就像是深度学习网络的先验知识,或者说是'考试时,老师画的重点'.在很长一段时间处于迷茫状态, ...

  4. Yolo标注工具-labelImg的详细使用

    Yolo标注工具-labelImg的详细使用 1. 运行环境 Window平台(该软件原来在linux平台)+ python3(需要在安装python环境) 2. 标注过程 2.1 工具下载 下载数据 ...

  5. 将yolo标注转换为tensorflow_yolov3标注生成train.txt和test.txt同时做数据清洗

    文章目录 代码: 20200218 貌似上面代码有点bug,新的如下(解决了目标只有单行无法提取的bug,新增了将空目标图片汇总到文件夹的功能): 代码: # -*- encoding: utf-8 ...

  6. 【数据清洗】yolo标注补全 生成空的标注txt文件

    # -*- coding: utf-8 -*- """ @File : generate_null_txt.py @Time : 2020/5/16 11:09 @Aut ...

  7. 修改labelImg软件的yolo标注写入格式(.txt文件不换行的解决办法)(将换行符'\n'替换成'\r\n')

    labelImg标注的写入格式貌似有点问题: 写出来是这样的,换行都没了 在软件程序中查找write()函数,在这里找到了写入的位置: 我尝试着将它改改貌似还是不对 后来发现是这个问题: 修改后就可以 ...

  8. python 批处理yolo标注的图像 图像与标签同步处理

    在实际生活中,有时候负样本并不是那么好收集.(这里负样本指的是图像中某部分特征区域,形状与正样本完全不同,例如隔离开关的状态)此时,需要用极少的负样本去生成大量的负样本,就需要将实际的负样本截取处理之 ...

  9. 如何将yolo的标注(annotations).txt 坐标转换成tensorflow-yolov3(YunYang1994)的.txt 标注坐标?

    文章目录 原理 示例 实现代码 实际操作方法 原理 示例 如,这是Yolo的: 转换后就变成酱紫了: 注意:图像坐标原点在左上角 注意:作者引用图片路径时使用的时绝对路径,我们使用相对路径不知是否会出 ...

最新文章

  1. 算法精解:DAG有向无环图
  2. python内置函数sorted(x)的作用是_Python内置filter与sorted函数
  3. Rails字符集问题
  4. thinkphp验证是否登录并跳转
  5. python with语句与contextlib
  6. ping(团队作业)
  7. android:descendantFocusability用法简析
  8. IntelliJ IDEA 中的Java Web项目的资源文件复制新增如何更新到部署包中?
  9. php怎样下载网上的文件,php怎样实现文件下载
  10. 正则表达式的一些规则
  11. 与计算机交朋友优秀教案,《与计算机交朋友》教学设计-20210608120218.pdf-原创力文档...
  12. esp32找不到com端口_玩转GPIO之ESP32点灯大法(MicroPython版)
  13. Linux一些有用的操作
  14. MCS51单片机的型号与组成
  15. 吃豆豆--Java小游戏
  16. C相关笔试题或者面试题中的概念以及技巧题2
  17. Re27:读论文 LADAN Distinguish Confusing Law Articles for Legal Judgment Prediction
  18. 怎么用cmd强制修改密码
  19. SQL-SERVER的STUFF函数group by 分组,字符串合并
  20. 调用API接口,查询手机号码归属地(3)

热门文章

  1. linux sh文件case,Shell脚本case语句简明教程
  2. 环球易购选品:既然选品绕不过,那就让我们好好研究
  3. linux的php优化,linux优化转载
  4. python numpy 子数组_Python利用Numpy数组进行数据处理(一)
  5. 【MM模块】 Info Record 采购信息记录
  6. SAP顾问,市场的双重需求
  7. 关于未达账项的账务处理
  8. 调用BAPI_MATERIAL_SAVEDATA批量创建/修改物料
  9. check上传模板中的金额字段中的千分位
  10. 启用轻资产、重运营、降杠杆,红星美凯龙能否瘦成“家得宝”?