目录

1 事先准备的文件:

1.1 需要训练的图片

1.2 标注的xml文件

2 功能:

3 用法:

4 注意事项:


1 事先准备的文件:

1.1 需要训练的图片

要求路径中有一个子目录名称是 images (或 imgs ) ,训练程序需要通过 /images/ (或 /imgs/ )  替换为 /labels/ 找同名.txt文件提取标注数据
       默认情况下,yolov5是 images, yolov4是 imgs
       图片无需拷贝到yolo目录

1.2 标注的xml文件

# 支持xml格式 或 voc 格式,可用标注精灵或labelimg。后者是python程序,但连续标注效率高,推荐使用

2 功能:

1)将标注数据转为yolo格式,保存到 <labeltxtpath>/<img>.txt

# <labeltxtpath>=<imgpath> 中最后一个 images (或 imgs ) 换为 labels,扩展名改为txt
    2)生成 data/obj.names,类别名称列表
    3)创建清单文件 data/train.txt,val.txt,test.txt

# 三者按指定比例随机比例, 不重复。5000-1万以上的图片,建议val 500左右,test 100 左右

3 用法:

1) 测试、调整图片配比
 python make_label_yolo.py --runtest yes --imgpath E:\models\test1\images --labelxmlpath E:\models\test1\xmls --train_percent 0.9 --val_percent 0.08 --test_percent 0.02

2) 正式转换
 python make_label_yolo.py --imgpath E:\models\test1\images --labelxmlpath E:\models\test1\xmls --train_percent 0.9 --val_percent 0.08 --test_percent 0.02

4 注意事项:

#1)忽略 images 和 labelsxml 以.开头的文件;
#2)labelsxml中的标签文件,只有在 imgpath 存在同名图片才采用。
#3)需要训练的图片无需拷贝到 <yolo>/data/images
#4)根据yolo要求,txt标注文件生成在实际图片 images (或 imgs ) 并列目录 labels
#5)训练用到的文件清单描述文件,保存在 <yolo>/data/train.txt, val.txt, test.txt
#6)跳过宽w或高h小于指定大小的标注
#7)train/训练,val/校准,test/测验配比默认为 0.9 0.08 0.02,命令行参数修改
#8)视频提取的图片文件名称带 grp_ 前缀,这些文件不参与训练时校准val、测验test

脚本文件1: make_label_yolo.py,转换格式、随机分配 train val test清单

# 事先准备的文件:
#   需要训练的图片
#       要求路径中有一个子目录名称是 images (或 imgs ) ,训练程序需要通过 /images/ (或 /imgs/ )  替换为 /labels/ 找同名.txt文件提取标注数据
#       默认情况下,yolov5是 images, yolov4是 imgs
#       图片无需拷贝到yolo目录
#   标注的xml文件 # xml格式 或 voc 格式
# 功能:
#    1)将标注数据转为yolo格式,保存到 <labeltxtpath>/<img>.txt # <labeltxtpath>=<imgpath> 中最后一个 images (或 imgs ) 换为 labels,扩展名改为txt
#    3)生成 data/obj.names
#    4)创建清单文件 data/train.txt,val.txt,test.txt # 三者分配比例由命令行参数确定, 不重复
#    5)坐标越界的标注,会自动纠正,所以不应担心中间异常数据导致中途退出
# 用法:
# 测试、调整图片配比
# python make_label_yolo.py --runtest yes --imgpath E:\models\test1\images --labelxmlpath E:\models\test1\xmls --train_percent 0.9 --val_percent 0.08 --test_percent 0.02
# 正式转换
# python make_label_yolo.py --imgpath E:\models\test1\images --labelxmlpath E:\models\test1\xmls --train_percent 0.9 --val_percent 0.08 --test_percent 0.02#注意事项:
#1)忽略 images 和 labelsxml 以.开头的文件;
#2)labelsxml中的标签文件,只有在 imgpath 存在同名图片才采用。
#3)需要训练的图片无需拷贝到 <yolo>/data/images
#4)根据yolo要求,txt标注文件生成在实际图片 images (或 imgs ) 并列目录 labels
#5)训练用到的文件清单描述文件,保存在 <yolo>/data/train.txt, val.txt, test.txt
#6)跳过宽w或高h小于指定大小的标注
#7)train/训练,val/校准,test/测验配比默认为 0.9 0.08 0.02,命令行参数修改
#8)视频提取的图片文件名称带 grp_ 前缀,这些文件不参与训练时校准val、测验test# 入参 see def parse_opt(known=False):import time
import xml.etree.ElementTree as ET
import os
import random
# from os import listdir, getcwd
# from os.path import join
from pathlib import Path
import argparse
import sysFILE = Path(__file__).resolve()
ROOT = FILE.parents[0]  # YOLOv5 root directory
if str(ROOT) not in sys.path:sys.path.append(str(ROOT))  # add ROOT to PATH
ROOT = Path(os.path.relpath(ROOT, Path.cwd()))  # relative# IMG_FORMATS = 'bmp', 'dng', 'jpeg', 'jpg', 'mpo', 'png', 'tif', 'tiff', 'webp'  # include image suffixes
file_ext_sets = ['.jpg', '.jpeg','.png','.bmp','.tif','.tiff','.ppm','.webp']
clsfilename="data/obj.names"
g_fileprefix="grp_"label_totalnum=0
label_oldfilenum=0
label_newfilenum=0
label_skipnum=0classes = []
gPicFileList= []
gPicFilemap= {}
# 不存在xml标注文件的图片文件名称,make_yololabel()
skipPicList_nolabelxml=[] # print(f"not exist xmlfile={xmlfile}, p={lastps}")
# 没有合格标签而被删除标签文件的图片文件名称,make_yololabel() --> convert_annotation()
skipPicList_annotation=[] # print(f"skip {image_filename} when convert_annotation, no suitable labels ")
# 不存在标签文件的图片文件名称, make_trainvaltest_list()
skipPicList_nolabeltxt=[] # print(f"skip {fn} when make_trainvaltest_list,not exist labelFile={labelFile1}")# 分析标注文件列表,分配 train test val 清单,其中 val 随机选择
# 要求必须在imgpath存在同名的图片文件, 如果已经生成 yolo的txt标注,则还需在该目录存在同名文件
def make_trainvaltest_list():global label_totalnumglobal skipPicList_nolabeltxtglobal g_fileprefixlabelsxmlpath=opt.labelxmlpathlabelstxtpath=getlabelpath(opt.imgpath)if not os.path.exists(labelstxtpath):os.makedirs(labelstxtpath)filetype = ""global gPicFileListif len(gPicFileList)<=0:gPicFileList=getPicfilelist(opt.imgpath)total_pic=[] # not grp 文件, total_pic.clear()total_pic_grp=[] # grp文件, 不参与 val testfor file1 in gPicFileList:   #遍历所有文件st1 = os.path.splitext(file1)fn = st1[0]ext= st1[1]if file1.startswith('.'):continuexmlfile=os.path.join(labelsxmlpath,fn+".xml")if not os.path.exists(xmlfile):xmlfile=os.path.join(labelsxmlpath,fn+".XML")if not os.path.exists(xmlfile):# print(f"not exist xmlfile={xmlfile}")continueif label_totalnum>0: # 目前判断已生成 yolo txt的策略。如果有变化,相应做修改labelFile1=os.path.join(labelstxtpath, fn+'.txt')if not os.path.exists(labelFile1):# print(f"skip {fn} when make_trainvaltest_list,not exist labelFile={labelFile1}")skipPicList_nolabeltxt.append(fn)continueif file1.startswith(g_fileprefix):total_pic_grp.append(file1)else:total_pic.append(file1)if len(filetype)==0:filetype=check_labeltype(xmlfile)totalnum =  len(total_pic)totallist = range(totalnum)# val test 数量valtestn = totalnum * (opt.val_percent + opt.test_percent)if valtestn<2:valtestn=2valtestnum = int(valtestn) # val+test的数量# val test 列表valtestList = random.sample(totallist, valtestnum)# test数量testn = int( valtestnum* (opt.test_percent/(opt.val_percent + opt.test_percent)) )if testn<1:testn=1# test 列表testList = random.sample(valtestList, testn)num_train=0num_val=0    num_test=0txtsets = ['train.txt','val.txt','test.txt']ftrain = open(os.path.join("data/", txtsets[0]), 'w')fval = open(os.path.join("data/", txtsets[1]), 'w')ftest = open(os.path.join("data/", txtsets[2]), 'w')for i in totallist:picfile1=os.path.join(opt.imgpath, total_pic[i])+'\n' # 取文件名if i in valtestList:if i in testList:if opt.runtest=="no":ftest.write(picfile1)num_test+=1else:if opt.runtest=="no":fval.write(picfile1)num_val+=1else:if opt.runtest=="no":ftrain.write(picfile1)num_train+=1for file1 in total_pic_grp:picfile1=os.path.join(opt.imgpath, file1)+'\n' # 取文件名if opt.runtest=="no":ftrain.write(picfile1)num_train+=1ftrain.close()fval.close()ftest.close()print(f"""
train/val/test pic file:ref labelsxmlpath={labelsxmlpath}filetype={filetype}total={totalnum}num_train={num_train}num_val={num_val}num_test={num_test}output=data/: {txtsets}""")def save_nolabel_pic():global skipPicList_nolabelxmlglobal skipPicList_annotationglobal skipPicList_nolabeltxtskipPicList_xml_str=fprintlist(skipPicList_nolabelxml,5)skipPicList_str=fprintlist(skipPicList_annotation,5)skipPicList_txt_str=fprintlist(skipPicList_nolabeltxt,5)skipfilelist=[]skipUse={}skipfilelist, skipUse=getFilelist(skipfilelist, skipUse, skipPicList_nolabelxml)skipfilelist, skipUse=getFilelist(skipfilelist, skipUse, skipPicList_annotation)skipfilelist, skipUse=getFilelist(skipfilelist, skipUse, skipPicList_nolabeltxt)print(f"""debug info:skip image num={len(skipPicList_nolabelxml)} when make_yololabel,not exist labelxmlFile, {skipPicList_xml_str}skip image num={len(skipPicList_annotation)} when convert_annotation, no suitable labels, {skipPicList_str}skip image num={len(skipPicList_nolabeltxt)} when make_trainvaltest_list,not exist labeltxtFile, {skipPicList_txt_str}total skip image num={len(skipfilelist)}, detail list see data/skippic.txt""")fskipfile = open("data/skippic.txt", 'w')if opt.runtest=="no":fskipfile.write('\n'.join(skipfilelist)+"\n")fskipfile.close()# x1,y1,x2,y2 --> x_center,y_center,w,h(归一化)
def convert_normalize(size, box):w0 = size[0]h0 = size[1]xmin,xmax,ymin,ymax = box[0],box[1],box[2],box[3]if xmin<0:xmin=0if xmax>=w0:xmax=w0-1if ymin<0:ymin=0if ymax>=h0:ymax=h0-1dw = 1. / w0dh = 1. / h0x = (box[0] + box[1]) / 2.0y = (box[2] + box[3]) / 2.0w = box[1] - box[0]h = box[3] - box[2]if h>=h0:h=h0-1if w>=w0:w=w0-1if w<opt.labelminsize or h<opt.labelminsize or w*h<300:return (0, 0, 0, 0),Falsex = x * dww = w * dwy = y * dhh = h * dhreturn (x, y, w, h),True# xml:xml格式; voc:voc格式
def check_labeltype(labelxmlpathfileIn):in_file = open(labelxmlpathfileIn)tree = ET.parse(in_file)root = tree.getroot()o1 = root.find('outputs')if o1 != None:o2 = o1.find('object')if o2 != None:if o2.find('item') != None:return "xml"o1 = root.find('object')if o1 != None:o2 = o1.find('bndbox')if o2 != None:return "voc"return "unknown"def convert_annotation(image_filename, xmlfile, labeltxtpathIn):global classesglobal label_totalnumglobal label_oldfilenumglobal label_newfilenumglobal label_skipnumglobal skipPicList_annotationin_file = open(xmlfile) # 'data/labelxmlpath/%s.xml' % (image_filename)labelFile1=os.path.join(labeltxtpathIn, image_filename+'.txt')if opt.forcetxt!="yes" and os.path.exists(labelFile1):  # defaulttxtf1=open(labelFile1, "r")labellist=txtf1.readlines()for str1 in labellist:if len(str1.strip())>0:label_totalnum+=1label_oldfilenum+=1returnlabel_newfilenum+=1out_file = open(labelFile1, 'w')tree = ET.parse(in_file)root = tree.getroot()size = root.find('size')w = int(size.find('width').text)h = int(size.find('height').text)label_usenum=0attrTest = 'outputs'if root.find(attrTest) != None: # if attrTest in root.tag: # if root.get(attrTest) == 'outputs':# print(f"------type=xml, image_filename={image_filename}------")itemsRoot = root.find('outputs').find("object")for obj in itemsRoot.iter('item'):cls = obj.find('name').text.strip()if cls not in classes :classes.append(cls) # continuecls_id = classes.index(cls)xmlbox = obj.find('bndbox')b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text),float(xmlbox.find('ymax').text))bb,Flag = convert_normalize((w, h), b)label_totalnum+=1if Flag==False:label_skipnum+=1continueif opt.runtest=="no":out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')label_usenum+=1else:# print(f"------type=voc, image_filename={image_filename}------", image_filename)for obj in root.iter('object'):difficult = obj.find('difficult').textif int(difficult) == 1:continuecls = obj.find('name').textif cls not in classes:classes.append(cls) # continuecls_id = classes.index(cls)xmlbox = obj.find('bndbox')b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text),float(xmlbox.find('ymax').text))bb,Flag = convert_normalize((w, h), b)label_totalnum+=1if Flag==False:label_skipnum+=1continueif opt.runtest=="no":out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')label_usenum+=1out_file.close()if label_usenum<=0 and os.path.exists(labelFile1):skipPicList_annotation.append(image_filename) # print(f"skip {image_filename} when convert_annotation, no suitable labels ")os.remove(labelFile1)# 创建yolo需要的格式,每图片一个txt,每行一个对象
# class/类别编号 x_center/x中心坐标 y_center/y中心坐标 width/宽 height/高, 参数均为0-1归一化
def make_yololabel():global classesglobal file_ext_setsglobal label_totalnumglobal label_oldfilenumglobal label_newfilenumglobal label_skipnumglobal clsfilenameglobal skipPicList_nolabelxmllabelsxmlpath=opt.labelxmlpathlabelstxtpath=getlabelpath(opt.imgpath)if not os.path.exists(labelstxtpath):os.makedirs(labelstxtpath)ticks = time.time()global gPicFileListif len(gPicFileList)<=0:gPicFileList=getPicfilelist(opt.imgpath)count1=0pnum=0lastp=0.0for file1 in gPicFileList:   #遍历所有文件# if os.path.isdir(file1):   #如果是文件夹则跳过#     continue# # file1=file1.lower()# st1 = os.path.splitext(file1)# fn = st1[0]# ext= st1[1]# # print("--splitext",os.path.splitext(file1))# if file1.startswith('.') or ext.lower() not in file_ext_sets:#     continuefn = os.path.splitext(file1)[0]pnum+=1xmlfile=os.path.join(labelsxmlpath,fn+".xml")if not os.path.exists(xmlfile):xmlfile=os.path.join(labelsxmlpath,fn+".XML")if not os.path.exists(xmlfile):skipPicList_nolabelxml.append(fn)
#           p2 = 100.0*float(pnum)/float(len(gPicFileList))
#           if p2>lastp+10.0:
#               lastp=p2
#               lastps="%0.2f%%" % (lastp)
#               print(f"not exist xmlfile={xmlfile}, p={lastps}")continuecount1 += 1convert_annotation(fn, xmlfile, labelstxtpath) # xmlfile, labeltxtpathIn# time.sleep(0.01)if time.time()-ticks>=1.5:ticks=time.time()p1 = 100.0*float(count1)/float(len(gPicFileList))print(time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime()),', %5.1f%%' % p1 )# save obj.namescls_file = open(clsfilename, 'w')if opt.runtest=="no":cls_file.write("\n".join(classes) + '\n')usep="%0.2f" % (100.0*float(label_totalnum-label_skipnum)/float(label_totalnum))print(f"""label info:pic_num={pnum}labeltxt={labelstxtpath}label_totalnum={label_totalnum}label_oldfilenum={label_oldfilenum}label_newfilenum={label_newfilenum}label_usenum={label_totalnum-label_skipnum}, {usep}%label_skipnum={label_skipnum}, obj too smallclasses={clsfilename}, num={len(classes)}""")# images (或 imgs )
def getlabelpath(imgPath):i1 = imgPath.rfind('images')if i1>=0:labelp = imgPath[:i1]+"labels"+imgPath[i1+len("images"):]return labelpi1 = imgPath.rfind('imgs')if i1>=0:labelp = imgPath[:i1]+"labels"+imgPath[i1+len("imgs"):]return labelpreturn os.path.join(imgPath,"../labels")def ftest():if True:p1 = "E:\\opencv_org/windows\\Opencv4\\sources.base\\data\\haarcascades_cudA/haarcascade_eye.xml"imgPathspilit=p1.lower().replace('\\','/').split('/')print("----imgPathspilit=",imgPathspilit)returnif False:if not os.path.exists(txtsaveTempPath):os.makedirs(txtsaveTempPath)pf1 = os.path.join(txtsaveTempPath, "train.txt")print("----pf1=",pf1)if False:in_file = open('E:/opencv_org/models/smoke/test1/outputs-xml/000000.xml')tree = ET.parse(in_file)root = tree.getroot()attrTest = 'outputs'print("---find=", root.find(attrTest))if root.find(attrTest) != None: # if attrTest in root.tag: # if root.get(attrTest) == 'outputs':print("---xml")else:print("---voc")def parse_opt(known=False):parser = argparse.ArgumentParser()# 图片路径。需要有一个子目录名称为 images 或 imgs ; 标签txt位置,通过将该子目录名称替换为 labels 获得parser.add_argument('--imgpath', type=str, default=ROOT / 'data/images', help='images path')# voc 或 xml 格式的标注文件,可用 标注精灵 或 lableimg 工具,后者是个python程序,推荐使用parser.add_argument('--labelxmlpath', type=str, default=ROOT / 'data/labelxmlpath', help='labels xml path')# w 或 h 小于指定值的标签被忽略parser.add_argument('--labelminsize', type=int, default=12, help='labels min width and height, and w*h>=300')# 图片分配比例# val 比例, 总数控制 500 左右?# test 比例, 总数控制100左右? ( 训练期间不参与,训练完成后,用来人工检测识别成果 )    parser.add_argument('--train_percent', type=float, default=0.90, help='train_percent, train+val+test=1.0')parser.add_argument('--val_percent', type=float, default=0.08, help='val_percent, train+val+test=1.0')parser.add_argument('--test_percent', type=float, default=0.02, help='test_percent, train+val+test=1.0')# 强制重建yolo格式标签文件,否则跳过已存在的文件parser.add_argument('--forcetxt', type=str, default='yes', help='force rebuild yolo label txt file')# 在 xml 标签文件目录中,如果在 images 目录下没有同名图片文件,则该 xml标签文件 被移到 xmlbak 目录parser.add_argument('--movexmlbak', type=str, default='no', help='move xml label file when no same name image file')# 仅测试, 不写文件yolo txt文件、train/val/test 文件parser.add_argument('--runtest', type=str, default='no', help='run ftest() only')opt = parser.parse_known_args()[0] if known else parser.parse_args()return optdef getPicfilelist(imgPath):global file_ext_setsglobal gPicFilemapgPicFilemap.clear()picFileListOut = []picFileList0 = os.listdir(imgPath)# print("--picFileList0",picFileList0)for file1 in picFileList0:   #遍历所有文件if os.path.isdir(file1):   #如果是文件夹则跳过continuest1 = os.path.splitext(file1)fn = st1[0]ext= st1[1]# print("--splitext",os.path.splitext(file1))if (not file1.startswith('.')) and ext.lower() in file_ext_sets:picFileListOut.append(file1)gPicFilemap[fn]=file1print(f"get picFileList={len(picFileListOut)}")return picFileListOut# 不以.开头、扩展名为 file_ext_sets 的文件数
# images (或 imgs )
def getpicfilenum(imgPath):if not os.path.exists(imgPath):print(f"--imgpath not exist={imgPath}")return -1imgPathspilit=imgPath.lower().replace('\\','/').split('/')if "images" not in imgPathspilit and "imgs" not in imgPathspilit:print("--imgpath need contains images or imgs subdir")return -1global gPicFileListif len(gPicFileList)<=0:gPicFileList=getPicfilelist(imgPath)return len(gPicFileList)# 不以.开头、扩展名为xml的文件数
def getxmlfilenum(labelsxmlPath):if not os.path.exists(labelsxmlPath):print(f"--labelsxmlPath not exist={labelsxmlPath}")return -1xmlFileList = os.listdir(labelsxmlPath)count=0for file1 in xmlFileList:   #遍历所有文件if os.path.isdir(file1):   #如果是文件夹则跳过continuefile1=file1.lower()if (not file1.startswith('.')) and file1.endswith('.xml'):count += 1return countdef fprintlist(listIn, num):str1=""if len(listIn)>num:str1="%s"%listIn[:num]+"..."else:str1="%s"%listInreturn str1def getFilelist(skipfilelist, skipUse, listIn):for fn in listIn:if skipUse.get(fn)!=None:continueskipUse[fn]=1f1=os.path.join(opt.imgpath,gPicFilemap[fn])if os.path.exists(f1):skipfilelist.append(f1)return skipfilelist,skipUsedef movexmlfile(labelsxmlPath):global gPicFileListglobal gPicFilemapif not os.path.exists(labelsxmlPath):print(f"--labelsxmlPath not exist={labelsxmlPath}")return -1print(f"--enter move not use xml file")if len(gPicFileList)<=0:gPicFileList=getPicfilelist(imgPath)labelsxmlPathBak=labelsxmlPath+"_bak"if not os.path.exists(labelsxmlPathBak):os.makedirs(labelsxmlPathBak)xmlFileList = os.listdir(labelsxmlPath)for file1 in xmlFileList:   #遍历所有文件if os.path.isdir(file1):   #如果是文件夹则跳过continuefile2=file1.lower()if (file2.startswith('.')) or not file2.endswith('.xml'):continuefn = os.path.splitext(file1)[0]if gPicFilemap.get(fn)==None: # xml文件在 images 没有同名文件os.replace(os.path.join(labelsxmlPath, file1), os.path.join(labelsxmlPathBak, file1))print(f"--end to move xml file")# 执行重建yolo txt文件时,将全部已有文件移到 labels_bak
def movetxtfile(labelstxtPath):if not os.path.exists(labelstxtPath):print(f"--labelstxtPath not exist={labelstxtPath}")return -1print(f"--enter move exist txt file")labelstxtPathBak=labelstxtPath+"_bak"if not os.path.exists(labelstxtPathBak):os.makedirs(labelstxtPathBak)FileList = os.listdir(labelstxtPath)for file1 in FileList:   #遍历所有文件if os.path.isdir(file1):   #如果是文件夹则跳过continueos.replace(os.path.join(labelstxtPath, file1), os.path.join(labelstxtPathBak, file1))print(f"--end to move txt file")def finitLoad():global classesclasses.clear()# obj.namesif os.path.exists(clsfilename):cls_file = open(clsfilename, 'r')clsList1=cls_file.readlines()for cls in clsList1:cls=cls.strip()if len(cls)>0:classes.append(cls)print("classes load from file=",classes)returndef fmain(opt):global skipPicList_nolabelxmlglobal skipPicList_annotationglobal skipPicList_nolabeltxtglobal gPicFilemapfinitLoad()if opt.labelminsize<8:opt.labelminsize=12pn=getpicfilenum(opt.imgpath)if pn<=0:if pn==0:print("no pic file in --imgpath ")exit(0)xn=getxmlfilenum(opt.labelxmlpath)if xn<=0:if xn==0:print("no xml file in --labelxmlpath ")exit(0)# if True:if opt.movexmlbak!="no":movexmlfile(opt.labelxmlpath)  # 将 xml 文件中,在 images 没有对应图片的xml文件移到 xmlbak 目录if opt.forcetxt=="yes":movetxtfile(getlabelpath(opt.imgpath))# print("cur dir=", getcwd())make_yololabel()make_trainvaltest_list()save_nolabel_pic()if __name__ == "__main__":opt = parse_opt()print("\nargparse:")print(vars(opt))print("\n")#    if True:if False:# movetxtfile("E:\opencv_org\models\dataset\smoke,dataset\labels_test")exit(0)if False:ftest()exit(0)fmain(opt)

脚本文件2:打开视频文件,按指定的间隔提取图片,文件名称 grp_<videoname>_<nnnnnn>.jpg

# e.g.
# cls && python make_video_pic.py --source G:\archive\fire_sample\t1.mp4 --imageoutput G:\archive\v1  --interval 0.2
# cls && python make_video_pic.py --source G:\archive\fire_sample\smoke9.avi --imageoutput G:\archive\v1  --interval 2.0
# 提取的图片文件名称带 grp_ 前缀,这些文件不参与训练时校准val、测验test# Python 2/3 compatibility
from __future__ import print_function
import argparse
import numpy as np
import cv2 as cv
import os
import sys
from pathlib import Path
# import utils
import timeFILE = Path(__file__).resolve()
ROOT = FILE.parents[0]  # YOLOv5 root directory
if str(ROOT) not in sys.path:sys.path.append(str(ROOT))  # add ROOT to PATH
ROOT = Path(os.path.relpath(ROOT, Path.cwd()))  # relativeg_fileprefix="grp_"WHlimited=640 # maxn(w,h)<WHlimited时,将其放大为 WHlimiteddef parse_opt(known=False):parser = argparse.ArgumentParser()# 视频文件。parser.add_argument('--source', type=str, default=ROOT / 'data/videofile', help='videofile')parser.add_argument('--imageoutput', type=str, default=ROOT / 'data/imageoutput', help='imageoutput path')# interval 每张间隔秒数parser.add_argument('--interval', type=float, default=0.5, help='interval')# 正常播放速度parser.add_argument('--play', type=str, default='no', help='play')# image 文件前缀parser.add_argument('--prefix', type=str, default='', help='image file prefix')# 仅测试, 不写image文件parser.add_argument('--runtest', type=str, default='no', help='run ftest() only')opt = parser.parse_known_args()[0] if known else parser.parse_args()return optdef main():def decode_fourcc(v):v = int(v)return "".join([chr((v >> 8 * i) & 0xFF) for i in range(4)])
# 检测源文件是否存在if not os.path.exists(opt.source):print(f"not exist: {opt.source}")exit(0)
# 目标目录不存在则创建if not os.path.exists(opt.imageoutput):os.makedirs(opt.imageoutput)
# 每秒取多少图片if opt.interval<=0.0:opt.interval=0.5fpsgrab = float( 1.0/float(opt.interval) ) # 每秒取多少图片
# 打开视频cap = cv.VideoCapture(opt.source) # VideoCapture(0)if not cap.isOpened():print(f"open fail, video={opt.source}")# cap.set(cv.CAP_PROP_AUTOFOCUS, 0)  # Known bug: https://github.com/opencv/opencv/pull/5474if opt.play=="yes":cv.namedWindow("Video")
#    convert_rgb = True
# 视频的帧率,每帧延时fps = float(cap.get(cv.CAP_PROP_FPS))if fps<0.0001:fps=25.0delay1 = float(1.0)/fps# focus = int(min(cap.get(cv.CAP_PROP_FOCUS) * 100, 2**31-1))  # ceil focus to C_LONG as Python3 int can go to +inf# cv.createTrackbar("FPS", "Video", int(fps), 30, lambda v: cap.set(cv.CAP_PROP_FPS, v))# cv.createTrackbar("Focus", "Video", focus, 100, lambda v: cap.set(cv.CAP_PROP_FOCUS, v / 100))frameWidth = int(cap.get(cv.CAP_PROP_FRAME_WIDTH))frameHeight = int(cap.get(cv.CAP_PROP_FRAME_HEIGHT))
# 视频宽 高缩放比例f1 = float(frameWidth)if frameWidth < frameHeight:f1 = float(frameHeight)if f1<1.0:print(f"get w h fail, video={opt.source},fps={fps},w={frameWidth},h={frameHeight}")returnresize_ratio = -1.0if float(WHlimited)> f1:resize_ratio = float(WHlimited) / f1ticksPrn = time.time()count=0findex=0 #从零开始countSeg=int(fps/fpsgrab) # 每隔多少帧抓取一张indexseg=0print(f"video={opt.source},fps={fps},delay={delay1},w={frameWidth},h={frameHeight},countSeg={countSeg}")global g_fileprefixwhile True:ticks1 = time.time()hasFrame, img = cap.read()if not hasFrame or img is None:if count==0:print('No frames grabbed!')breakfourcc = decode_fourcc(cap.get(cv.CAP_PROP_FOURCC))count+=1indexseg+=1if opt.play=="yes":ticks2 = time.time()-ticks1d1 = delay1-ticks2if d1>0.0001:time.sleep(d1)ticks1 = time.time()-ticks1
#       if not bool(cap.get(cv.CAP_PROP_CONVERT_RGB)):
#           if fourcc == "MJPG":
#               img = cv.imdecode(img, cv.IMREAD_GRAYSCALE)
#           elif fourcc == "YUYV":
#               img = cv.cvtColor(img, cv.COLOR_YUV2GRAY_YUYV)
#           else:
#               print("unsupported format")
#               breakif time.time()-ticksPrn>=1.5:ticksPrn=time.time()p1 = 1000.0*float(ticks1)print(time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime()),', tick=%5.1f ms' % p1 )if resize_ratio>0.01:img = cv.resize(img, (0, 0), fx=resize_ratio, fy=resize_ratio)if indexseg>=countSeg:indexseg=0findex+=1NewFile = os.path.join(opt.imageoutput, g_fileprefix+opt.prefix+str(findex).zfill(6)+".jpg")if opt.runtest!="yes":cv.imwrite(NewFile, img)print(f"save to={NewFile}")if opt.play=="yes":cv.imshow("Video", img)k = cv.waitKey(1)if k == 27:break
#        elif k == ord('g'):
#            convert_rgb = not convert_rgb
#            cap.set(cv.CAP_PROP_CONVERT_RGB, 1 if convert_rgb else 0)cap.release()  # 释放print('Done')def ftest():returnif __name__ == '__main__':opt = parse_opt()# 获取视频文件的名称if len(opt.prefix)==0:f1 = os.path.basename(opt.source)opt.prefix = os.path.splitext(f1)[0]+"_"print("\nargparse:")print(vars(opt))print("\n")if False:ftest()exit(0)main()cv.destroyAllWindows()

yolo标注文件转换工具,python做的相关推荐

  1. Easy Data Transform for mac (Excel和CSV编程文件转换工具) v1.11.1激活版

    Easy Data Transform mac版是一款很优秀好用的Excel和CSV编程文件转换工具.Easy Data Transform功能强大,操作简单,使用后可以帮助用户更轻松便捷的转换表格文 ...

  2. HTML批量转换jpg,万能文件转换工具(word,excel,powerpiont,PDF,TXT,JPG,HTML互转)

    All Office Converter Platinum v6.1 官方简体中文注册版是一款易于使用和专业的文件转换工具.它可以高质量的支持批量转换文件,网页和图像,以改善工作效率.有了这个强大的转 ...

  3. Plist Converter for mac(plist文件转换工具)

    Plist Converter for mac是应用在mac上的一款plist文件转换工具,以最快,最简单的方法为您转换plist文件,并且还可以在一次操作中批量转换许多plist文件. Plist ...

  4. html文件转换Excel2016文件,万能文件转换工具(word,excel,powerpiont,PDF,TXT,JPG,HTML互转)...

    All Office Converter Platinum v6.1 官方简体中文注册版是一款易于使用和专业的文件转换工具.它可以高质量的支持批量转换文件,网页和图像,以改善工作效率.有了这个强大的转 ...

  5. vce 题库导入_VCE Converter下载|VCE题库文件转换工具最新免费版V1.0 下载_当游网...

    VCE题库文件转换工具是一款电脑文件转换软件,该工具可以将VCE格式文件转换为VCEM格式,是Visual CertExam用户的必备软件,快下载使用吧! 软件介绍 VCE Converter官方版是 ...

  6. PDF,Word文件转换工具

    前言 前段时间一直使用到word文档转pdf或者pdf转word,寻思着用Java应该是可以实现的,于是花了点时间写了个文件转换工具 源码weloe/FileConversion (github.co ...

  7. txt格式转换成prg_Advanced CSV Converter v6.69下载(csv文件转换工具)

    CSV文件是一个纯文本文件,有的时候,由于使用需求,需要将CSV转换为其他的格式使用,在这里,小编向大家推荐这款Advanced CSV Converter转换工具,它支持将CSV格式的文件转换成DB ...

  8. 全球最优秀的免费软件下载-压缩工具-文件转换工具-下载工具-杀毒工具-图片编辑器-网络管理工具...

    [ 标题] 全球最优秀的免费软件下载 [ 关键字] 压缩工具- 文件转换工具- 下载工具- 杀毒工具- 图片编辑器- 网络管理工具- 即时软件  误删除文件恢复工具-文本编辑器-系统设置工具-虚拟工作 ...

  9. python代码:VOC to cityscapes标注文件转换

    在进行语义分割训练时,不同算法支持的数据集格式不同(例如mmsegmentation中每个算法的主页都给出了文件支持的数据集格式),因此有时需要转换数据集的格式 一.数据集简介 1.1 关于VOC 在 ...

  10. html文件怎么用Python做后端,利用python实现后端写网页(flask框架).pdf

    利利用用python实实现现后后端端写写网网页页 ((flask框框架架)) 如何用python做后端写网页-flask框架 什么是Flask安装flask模块Hello World更深一步:数据绑 ...

最新文章

  1. 从零开始学python人工智能课程_从零开始学人工智能(12)--Python · 决策树(零)· 简介...
  2. 是什么原因让你选择做程序员
  3. js 递归查询所有的叶子结点_浅谈mysql的查询过程
  4. 分享改进 高性能通用分表归档存储过程测试结果更新
  5. 【报告分享】第七次全国人口普查主要数据情况报告.pdf(附下载链接)
  6. mysql双活存储容量 TB_Mysql双活方案 - osc_fted3syf的个人空间 - OSCHINA - 中文开源技术交流社区...
  7. C++ 基于凸包的Delaunay三角网生成算法
  8. wxcharts.js结合java后台在小程序中的使用(柱状图,其它同理)
  9. python定义常量、装饰器_Python 装饰器
  10. ARM启动流程及启动代码分析
  11. 计算机硬盘有坏道,硬盘有坏道就不能用了吗?别再吃哑巴亏了,今天跟大家再说一次!...
  12. 华硕路由器的虚拟服务器,华硕(ASUS)路由器中继设置_华硕路由器无线中继模式设置教程-192路由网...
  13. 计算机快捷键知识点,电脑常用快捷键复习知识点.pdf
  14. 打印 Java 数组的最简单方法是什么?
  15. 测试用的美国信用卡账号
  16. [Android]混淆Android代码
  17. 成人c语言培训,C语言程序设计在成人教育中教学.doc
  18. python有vlookup的功能么,vlookup函数功能非常强大,那在Python中如何实现?
  19. 【Nowcoder】2018 ACM-ICPC 上海大都会赛 Matrix Game (网络流 最大流)
  20. opensll zbar交叉编译(君正平台)

热门文章

  1. 安卓pdf阅读器_2020年双十一有哪些电纸书、电子书阅读器值得买?Kindle、掌阅、文石、科大讯飞哪个好?...
  2. SQL中的日期差函数
  3. Django框架详解
  4. Elman神经网络原理
  5. --》【日常】程序员常用网站
  6. SQL中ALTER TABLE 语句
  7. mySQL及可视化界面navicat在window的配置
  8. php的一些编码问题
  9. “网红”Cat-1模组
  10. java jdk下载_jdk1.7下载|Java Development Kit (JDK) 下载「64位」-太平洋下载中心