经过对各个版本的调查发现我目前用的这套yolo十分的,简陋,所以功能实现会比正常版本复杂的多,所以如果你用的结构和我不同,我不建议认真对待这个文章,因为真的很草,建议你找找更相关的东东
或者你可以从这个解决问题实现功能的过程汲取一下灵感
如果你碰巧用上了和我这个结构类似的yolo,那么我为你感到悲哀,但是至少你还能找到我这篇文章,也算是不幸中的万幸。我这一套带角度识别且运行速度较原yolo快些,代码也更简洁,所以也不完全一无是处,需要的话可以留言私信要
我是个懒人,搞上一套数据集的时候用了近两万张,现在要进行数据集拓展和修正,有点不想弄了,于是就想着整个全自动打标签工具吧。我们用的yolo版本或者结构可能不同,但是应该也不会差多少,我这里提供一个思路,供大家学习和参考。
但是说实话,我用的这套yolo算是十分简陋的了,只有最基本的功能所以需要改很多地方,如果你用的是基本的yolov5之类的,那会很简单只需要改个参数之类的就可以
注:如果要进行全自动打标签,必须要有一个相对完善且完备的模型(数据集),如果没有,请先整一个,如果懒,可以使用半自动打标签方法
可以参考以下链接
快速给语义分割任务打标签----eiseg教程_eiseg安装-CSDN博客https://blog.csdn.net/qq_36079986/article/details/128467417?ops_request_misc=&request_id=&biz_id=102&utm_term=%E5%8D%8A%E8%87%AA%E5%8A%A8%E6%A0%87%E6%B3%A8eiseg&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-0-128467417.142%5Ev100%5Epc_search_result_base9&spm=1018.2226.3001.4187 完成标注后,正常json转txt就可,如果你是用的obb,可以先json转正常txt然后进行计算得到obb的txt,代码太长我就不放了,如果你需要可以留言。
然后是我用的yolo_mater项目的来源,但是现在源码没法下载了,想要的可以留言我给你发一份
YOLO5 旋转模型图片标注及训练_yolov5旋转框模型训练-CSDN博客https://blog.csdn.net/My_Precision/article/details/128177301 下面开始全自动打标签的 大致 教程
首先你要明白原理,全自动打标签,说白了就是用你原有的模型进行识别,如果你把置信度阈值放的很低,即便是没有标注过的东西也会多少识别出来一点,这样识别到你想要的东西之后,保存识别的图片,并且保存相关参数与信息,然后你就可以再进行二次修改让它成为可以训练的数据集然后就Ok了。
运行初始代码的话也会保存图片和数据,但是运行后识别图像会覆盖,到最后只剩一张,且所有识别内容都保存在同一个txt里,很大便
正常yolov5只需要在这里修改就可以实现功能,但是这个不可以,你从他简陋的参数选择就可以看出(save-txt我修改过,没用)
审视全部代码后,最核心的代码部分就在这里
其中rbox2txt是对识别到的东西的数据进行处理和记录
plot_one _rotated_box是对识别到的东西进行识别框绘制,如果你要进行数据集处理,那么最后保存的图片最好是不带识别框的,防止影响训练,可以在labelme之类的里面通过记录的数据进行查看和修改,所以如果你想这样,就直接把这个删掉。
然后顺着引用去找rbox2txt,为如下
def rbox2txt(rbox, classname, conf, img_name, out_path, pi_format=False):
"""
将分割图片的目标信息填入原始图片.txt中
@param robx: rbox:[tensor(x),tensor(y),tensor(l),tensor(s),tensor(θ)]
@param classname: string
@param conf: string
@param img_name: string
@param path: 文件夹路径 str
@param pi_format: θ是否为pi且 θ ∈ [-pi/2,pi/2) False说明 θ∈[0,179]
"""
if isinstance(rbox, torch.Tensor):
rbox = rbox.cpu().float().numpy()
#rbox = np.array(x)
if pi_format: # θ∈[-pi/2,pi/2)
rbox[-1] = (rbox[-1] * 180 / np.pi) + 90 # θ∈[0,179]
# rect=[(x_c,y_c),(w,h),Θ] Θ:flaot[0-179] -> (-180,0)
rect = longsideformat2cvminAreaRect(rbox[0], rbox[1], rbox[2], rbox[3], (rbox[4] - 179.9))
# poly = [(x1,y1),(x2,y2),(x3,y3),(x4,y4)]
poly = np.float32(cv2.boxPoints(rect)) # 返回rect对应的四个点的值
poly = np.int0(poly).reshape(8)
splitname = img_name.split('__') # 分割待merge的图像的名称 eg:['P0706','1','0','_0']
oriname = splitname[0] # 获得待merge图像的原图像名称 eg:P706
# 目标所属图片名称_分割id 置信度 poly classname
lines = img_name + ' ' + conf + ' ' + ' '.join(list(map(str, poly))) + ' ' + classname
# 移除之前的输出文件夹,并新建输出文件夹
if not os.path.exists(out_path):
os.makedirs(out_path) # make new output folder
with open(str(out_path + '/' + oriname) + '.txt', 'a') as f:
f.writelines(lines + '\n')
通过观察可以知道这就是保存识别内容到txt的部分,但是由于识别图像始终在相互覆盖导致图片有且只有“0.png”,这个命名被引用到这里后所有的识别内容就都被写进同一个0.txt里了,所以首要目标是修改代码中的oriname引用来源
oriname来自于splitname[0],splitname[0]来自于img_name,所以一劳永逸的方法就是修改img_name,这个img_name引自源代码的Path(p).stem
已知最后保存的txt名称都是0.txt,根据 with open(str(out_path + '/' + oriname) + '.txt', 'a') as f:
可以直接推测oriname和splitname[0]和img_name和Path(p).stem就只是个纯名称或数字,所以可以直接把Path(p).stem随便改成个整数变量,然后再进行字符化保存,完成后整数+1,这样就能避免txt相互覆盖。
这里直接在全代码前面加一个ddd定义,然后在detect函数内gobal一下(不global会报错的)
然后把后面Path(p).stem改成ddd,执行完之后ddd+1就完成了第一步
还没完,回到txt部分会发现他对原命名进行了一些处理,这些处理直接用在我们的整数型变量上会报错,所以直接删了算了,即如下部分
splitname = img_name.split('__') # 分割待merge的图像的名称 eg:['P0706','1','0','_0']
oriname = splitname[0] # 获得待merge图像的原图像名称 eg:P706
,并且把最后的oriname改成img_name,并且由于整数型不能直接参与文件处理,所以加一个str化
with open(str(out_path + '/' + str(img_name)) + '.txt', 'a') as f:
f.writelines(lines + '\n')
然后是对保存的数据进行修改,obb对数据的要求是
类别,x,y,长,宽,角度
就直接根据这个进行修改lines就好
到这txt部分就完事了,下一步需要整图片保存
图片保存是和save_path绑定的,所以就去找这部分
找到了
save_path = str(Path(out) / Path(p).name) # 图片保存路径+图片名字
直接改成字符化的ddd就好
这下运行后就没啥问题了
然后,如果你想进行labelme的标签查看和修改,需要把txt改为xml格式,这个网上有很多教程
但是!
草的是,我要用的是rolabeimg,导致两者结构不一样,并且还差很多东西,所以需要自己手动对转换代码进行修改,改成恰当的格式后就能使用rolabelimg了
未训练肯定会有偏差,此时就可以手动进行识别框微调或者分类调整(忽略potato)
然后整完了再xml转txt,然后txt再使用官方的tranform转为训练格式即可。
ps:如果你用的是半自动打标签,那也是多边形json转txt,然后txt转xml,然后xml转txt,然后txt转训练格式,其中txt转xml的时候由于没有角度参数需要进行计算,这也是个大坑,有需要的我可以给资源或者教程