根据我接触到的项目经验来看,需要我们进行检测的不是自然场景下的任意物体,而是特定场景下一类物体。典型的就是钢管识别,这些照片一般都是在厂区里面拍的、是对着钢管拍的,拍摄的目的是识别出钢管的数量。这里就为YOLO一类目标检测技术提供了空间,通过基于自定义数据集的迁移学习,能够实现一些效果,这里将相关东西整理出来。 ![image](33c842f8-0409-4166-ad8b-bd1b493be9ae_files/eff905f8-557e-4852-9268-a12e34d66f67.jpg) **基础环境:** 标注工具分为**本机标注**和网络**智能标注**。LabelImg能够提供不错的操作体验,在windows上我只找到一个老版本的,能够生成voc的数据格式;在linux上的最新版本可以直接生成yolo的格式。 ![image](33c842f8-0409-4166-ad8b-bd1b493be9ae_files/7c408e77-5b7b-48c3-ac4e-dda582c0e5a2.jpg) easydate能够提供只能标注,简单来说就是你只需要标注几张图片(不同数据数量不同),它可以先训练一个小模型,辅助你继续进行标注。 ![image](33c842f8-0409-4166-ad8b-bd1b493be9ae_files/cd9f6899-4e9f-4383-9afe-734497c31e3b.jpg) 这个的价值肯定是不言而喻的。在标注这块,我还编码实现了**基于传统算法的标签生成工具**。具体来说,就是基于传统算法,生成初略的数据集,将这里的结果作为标签导入模型训练中去。 ![image](33c842f8-0409-4166-ad8b-bd1b493be9ae_files/699322dc-6494-4152-8a43-2b1f61c1a1b1.jpg) 多措并举,能够有效提高数据标注速度。当然,标注仍然是一个痛苦的过程。 在训练这块,我使用了基于Kaggle的yolo官方notebook(https://www.kaggle.com/code/jsxyhelu2019/yolov5),进行一些删改后使用。这样能够有效使用免费的GPU,而且相对来说也比较方便。 ![image](33c842f8-0409-4166-ad8b-bd1b493be9ae_files/b15ae5f6-faca-4ec6-b54d-e1d3802b6ed4.png) **实验一:筷子识别** 第一个例子使用了网络上找到的数据集“筷子识别”,他最大的优势就是提供了完整的数据集。 **1、图片的采集,**可以看到这里的数据是比较集中的、质量是比较高的。数量大概210左右。 ![image](33c842f8-0409-4166-ad8b-bd1b493be9ae_files/88d57cac-661a-4336-8ad2-56e8ab9ef17c.jpg) **2、labelimg标注。**原作者提供了标注好的voc结果,可以直接使用,也可以拿过来自己体会一下。 ![image](33c842f8-0409-4166-ad8b-bd1b493be9ae_files/1d843a7a-57e2-4bfe-a56c-f5401b238ee6.jpg) **3、智能标注扩充。**生成3张图像,使用easydl进行智能进行扩充。注意这里如果无标注数据太少,智能标注会开启失败。 ![image](33c842f8-0409-4166-ad8b-bd1b493be9ae_files/ef332bcd-ea42-450f-bf9d-a2d569bdf560.png) ![image](33c842f8-0409-4166-ad8b-bd1b493be9ae_files/b5b0f555-7ca2-443e-a69d-75af3c394196.png) **4、修正结果** ![image](33c842f8-0409-4166-ad8b-bd1b493be9ae_files/7133b153-4666-44b5-a7ed-2e379d31eef1.jpg) **5、数据格式转换。**需要将voc格式转换成为yolo格式。**注意这里的label和前面标注的label是一样的。** ` **import** **os** **import** **xml**.etree.ElementTree as ET classes = ["label"] # 将x1, y1, x2, y2转换成yolov5所需要的x, y, w, h格式 **def** xyxy2xywh(size, box): dw = 1. / size[0] dh = 1. / size[1] x = (box[0] + box[2]) / 2 * dw y = (box[1] + box[3]) / 2 * dh w = (box[2] - box[0]) * dw h = (box[3] - box[1]) * dh **return** (x, y, w, h) # 返回的都是标准化后的值 **def** voc2yolo(path): # 可以打印看看该路径是否正确 **print**(**len**(**os**.listdir(path))) # 遍历每一个xml文件 **for** file **in** **os**.listdir(path): # xml文件的完整路径 label_file = path + file # 最终要改成的txt格式文件,这里我是放在voc2007/labels/下面 out_file = **open**(path.replace('Annotations', 'labels') + file.replace('xml', 'txt'), 'w') # print(label_file) # 开始解析xml文件 tree = ET.parse(label_file) root = tree.getroot() size = root.**find**('size') # 图片的shape值 w = **int**(size.**find**('width').text) h = **int**(size.**find**('height').text) **for** obj **in** root.iter('object'): difficult = obj.**find**('difficult').text cls = obj.**find**('name').text **if** cls **not** **in** classes **or** **int**(difficult) == 1: **continue** # 将名称转换为id下标 cls_id = classes.index(cls) # 获取整个bounding box框 bndbox = obj.**find**('bndbox') # xml给出的是x1, y1, x2, y2 box = [**float**(bndbox.**find**('xmin').text), **float**(bndbox.**find**('ymin').text), **float**(bndbox.**find**('xmax').text), **float**(bndbox.**find**('ymax').text)] # 将x1, y1, x2, y2转换成yolov5所需要的x, y, w, h格式 bbox = xyxy2xywh((w, h), box) # 写入目标文件中,格式为 id x y w h out_file.write(**str**(cls_id) + " " + " ".join(**str**(x) **for** x **in** bbox) + '\n') **if** **__name__** == '__main__': # 这里要改成自己数据集路径的格式 path = 'E:/DatasetId_1624813_1657795900/Annotations/' voc2yolo(path) ` ![image](33c842f8-0409-4166-ad8b-bd1b493be9ae_files/1c0c366e-9466-44c9-9362-c95797649d0f.png) 我还特地验证一下效果。 ![image](33c842f8-0409-4166-ad8b-bd1b493be9ae_files/fd6cc78b-fa59-4700-b8b9-61d6891c9f8e.jpg) **6、kaggle训练** 数据上传注意需要都是zip格式的。 编写的一些内容: ![image](33c842f8-0409-4166-ad8b-bd1b493be9ae_files/1381a841-7912-43be-bb5e-078283f26f60.png) ![image](33c842f8-0409-4166-ad8b-bd1b493be9ae_files/805e8f07-4416-42ba-83c1-275a87e07591.png) `path: datasets/kuaizi # dataset root dir train: train val: val test: # Classes nc: 1 names: ['label']` ![image](33c842f8-0409-4166-ad8b-bd1b493be9ae_files/6c5de8d7-a821-4920-9ee8-f0f365062eab.png) 使用现有资源,进行训练. ![image](33c842f8-0409-4166-ad8b-bd1b493be9ae_files/d8b11f91-449e-4a66-8bab-56fad4b35e9f.png) 注意这里的iamges和labels是放在一起的。 ![image](33c842f8-0409-4166-ad8b-bd1b493be9ae_files/3494ffd7-bd80-41f5-b8a7-f0183d437a09.jpg) 相关结果查看。 ![image](33c842f8-0409-4166-ad8b-bd1b493be9ae_files/55f2478d-46c0-4605-bd6b-6a2bbaac36f6.png) ![image](33c842f8-0409-4166-ad8b-bd1b493be9ae_files/c38de46f-ce79-431a-b153-b400abb2d523.png) model下载,可以作为infer来使用。最好是能够测试,直接使用infer测试也是不错. 模型训练完成后,将runs/exp/weights下的模型(best.pt)复制在yolov5文件夹下。如下图所示: ![image](33c842f8-0409-4166-ad8b-bd1b493be9ae_files/5b18e0d0-5a13-498f-b2d7-2866f07d9f29.png) **实验二:钢管识别** 有了前面的经验,可以更加放手做一些工作。 钢管数据的特点就是需要自己标注,所以这里我使用了很多trick来完成这个目标。 **1、首先,单模型使用小标签(P)方便显示** ![image](33c842f8-0409-4166-ad8b-bd1b493be9ae_files/1cec7d5c-9e4c-4039-9966-516414b07d52.jpg) **2、使用现有工具,能够完成一些东西。那么数据需要重新来做,并且把里面重复的东西确实的去掉。** ![image](33c842f8-0409-4166-ad8b-bd1b493be9ae_files/699322dc-6494-4152-8a43-2b1f61c1a1b1.jpg) 我现在给出的是这个代码可以生产coco json 的结果 **3、使用easyDL进行标注管理。也需要做好多轮标注的准备** ![image](33c842f8-0409-4166-ad8b-bd1b493be9ae_files/75a67ea9-1b45-4373-8cad-6fd6446cef27.jpg) 数据标注量很大,无法保证数据集的高可用,必须寻找到有效的迭代方法。比如这样图像的标注,实在是太费事了 ![image](33c842f8-0409-4166-ad8b-bd1b493be9ae_files/353b18db-eb3a-4d50-8ca5-da073b788fdb.jpg) 开启easydl智能标注,需要60张左右; **4、最终easyDL给出了不错的错误观测界面,**这个对于我数据分析来说是有用的 ![image](33c842f8-0409-4166-ad8b-bd1b493be9ae_files/0c146170-2087-4be8-aad6-1571037c7ba3.jpg) ![image](33c842f8-0409-4166-ad8b-bd1b493be9ae_files/7f989b3a-5725-4954-9df8-8ee4f5e1eff6.jpg) ![image](33c842f8-0409-4166-ad8b-bd1b493be9ae_files/b8dfe579-cc2a-4d5b-af1c-da835b0dbcd1.png) 这个训练花了4个小时,这个也是需要注意一下的时间。最后就是部署这块 ![image](33c842f8-0409-4166-ad8b-bd1b493be9ae_files/1dc88ec6-7c24-4636-b039-4f6fb2e1447e.png) **5、easydl提供了一些模式,但是需要和设备进行绑定。**对于现在的我来说了,绑定不符合SMD的预期模式,所以先不看。我需要的还是YOLO原生,然后尽可能达到同样的MAP等 ![image](33c842f8-0409-4166-ad8b-bd1b493be9ae_files/d38cd0be-f25a-4b75-92b3-77b185ed9d93.png) 这里的mAP到底是否可用?我查了一些资料证明还是可行的 ![image](33c842f8-0409-4166-ad8b-bd1b493be9ae_files/9e9985db-e2d1-4b14-a1e7-0883538f83c5.png) 那这么看来目前这个值还是很高的。 **6、方面验证是可行的**,但是效果不尽如人意,其根本原因是我数据标注的不够。相关的技术需要研究出来去购买数据,这是另一个维度的问题。此外在软件使用过程中,如果能够将数据标注的过程反馈出来,那就是更上一个层次。 ![image](33c842f8-0409-4166-ad8b-bd1b493be9ae_files/f8ad09bb-b18c-4855-84c4-19106b078c28.jpg) **实验三:毛发识别** 实际上,毛发识别存在尺度、方向等多个问题,并且需要解决的是3对象,难度是更大的。首先还是以现有的方法来进行处理,然后再思考其他。 ![image](33c842f8-0409-4166-ad8b-bd1b493be9ae_files/4e9d703f-e809-48d4-9bd0-c02dfe352f78.jpg) 说实话,我对使用深度学习解决毛发识别问题不是有完全的信息,因为这不是一个典型的问题,比如对象不是一个矩形框,而应该是自定义四边形。 ![image](33c842f8-0409-4166-ad8b-bd1b493be9ae_files/2c6c2f5f-b3a2-41f0-9963-0a7fe36917e7.png) 如果使用举行进行标注,可以发现重叠非常多: ![image](33c842f8-0409-4166-ad8b-bd1b493be9ae_files/78b6e863-4286-4856-ab6d-9efca6e051b0.jpg) 平行思考,如果基于AI去做语义分割的话,意义也不是很大,传统算法已经能够做很好的分割。 毛发识别算法的关键在于去除粘连,特别在根据现有的硬件进行精度测量,这样才能够获得高效的东西。 **实验小结:** 讨论一下传统方法和AI方法之间的关系: **1、AI能够解决很多传统方法无法解决、解决不好的问题,但AI不是万能的、仍然有很多问题目前无法解决;** **2、使用传统方法为AI生产数据集、全流程地参与到AI生产中,可能是未来出路;** **3、AI只不过是增加了一种解决问题的、不同维度的方法,它出来了很多模型和工具,但是解决问题的思路仍然关键决定因素。** 感谢阅读至此,希望有所帮助。
来自为知笔记(Wiz)
标签:ad8b,bd1b493be9ae,4166,检测,image,yolo,BLOG,0409,33c842f8 From: https://www.cnblogs.com/jsxyhelu/p/16946312.html