背景

  CV 的场景都是数据集来输入到模型 (素材),通过对素材图片或者视频分帧的素材图片,标记不同的 label_name,最终模型训练多少轮进行反向传播梯度下降的结论和数据集的质量是有关的。
  做过的可知,在标注本身是合格,不会出现框线不准。如果你的数据集雷同高,最后就算 loss 很低,但是实际效果也是不行的。雷同是指一个 label_name,因为通过拍摄视频获取素材数量,素材都是连贯场景 (指背景色,方位等相似度很高的)。
  好的数据集多样性,覆盖到实际应用中可能遇到的各种情况,背景阴影面噪声、不同的视角 (光照位置 - 摄像机 - 人的视野) 和尺度等。好的数据集往往
  做数据增广的,这里讲得不是一个普适的需求。服务场景是细化 label_name,比如汽车 label_name 里面,指名对象的汽车里面的特斯拉,那么特斯拉就是细化的 label_name。  把细化的特斯拉出现在不同的街道 (场景) 上面,真实去找这些图和去模拟本身是一样的。
本文只是提供了一种提升效率的获取 cv 数据的办法,后面会分享关于文本数据增广的。

思考变革

  能不能通过机器来帮切割出来,然后在由人去分拣,去挑选出素材,对素材进行变换八个方向,在进行打标。这里有个关键性的理解是,不一定整体这个步骤是多节省时间,起码是提高了数据集的质量,质量不高来回训练才是真正浪费时间。
  首先我们这个功能是在图片进行预处理 - 图像增强环节的。如果需要对该图片不变性其他算法进行使用的,可以在增强环节之前记录原始素材的位置。
  整理流程 - 预处理图像增强-->图像缩放和填充-->图像归一化-->图像编码格式。
  那么为什么 8 个方向是有用的呢,CV 选择是 YOLO 系列,这里不区分版本,YOLO 工作方式是将输入的图像划分为一个 S*S 的网格,对每一个小网格进行预测来逐步识别是否包含 label_name 的概率。
  IoU 会和网格绘制出来的真实的框,网格组成的框里面就是目标的对象,如果图片被 8 个方向的转换了一次,如果目标体不是一个只有 4 个角并且规则的物体,在进行卷积核处理训练时就会带来真实的帮助,下面在第二步会介绍 8 个方向的概念。
  思考后顶下的目标是把这个 000001.xml 和 000001.png 或者 jpg 变成大于 8 张以上的图,是多生成一点在进行分拣。
  不想计算那边麻烦,也是可以用随机翻转,但是需要人为拣选的流程又多了一步,人为拣选的多了,意味着没法用自动化尽可能做到串联。

第一步:产出素材的办法

  自己去拍或者找人提供。常见的方案是视频分帧生成素材,在过程中通过大间隔找打自己记录时间推演的关键帧,对关键帧之间的素材进行洗牌 (PS:如果不是分开训练这部分可以不必,随机性图片对于训练结论没有差异)。
  关键帧简述:
  视觉上显著和代表性的帧,画面变化背景变换明显的帧,实际场景里面需要考虑来回切换的问题。
  通常目标是按一个 lable_name 素材是 300 张图,按一万张图里面,选出 300。下面是一段数据描述的假设:
  1 帧或者指定 3-5 帧一张图,分出图后,根据录制图片描述段落的时间和视频平均帧数,算出接近 450 张图开始内容变换为第二段,然后第一段截图了 5/300 张,然后第二段,这种是一个手动记录的办法。
  代表性的这种,最好是具备错觉式蒙太奇的分帧效果,也就是对周围图片通过有记忆的时间序列进行感知后,推理出关键帧。
  每个像素的 RGB 值之差来评估帧之间的视觉差异,干扰点是因为业务视频场景切换不排除是不丝滑和来回切换的,这种特征是标注在时间序列之上的。
  连贯的图片会让用户可以区分出来后面的变换,错觉式蒙太奇,架设在有记忆的时间序列上面的,就是让你区分不到后面的变换,场景跳转的差异比较大。在自动获取的差异帧基础上绘制曲线,这个曲线的特征会根据目标对象的数量和解析帧率浮动来决策。
  可能会有一个疑问点是如果我跳的帧时间久点是不是也一样,如果不在意损失一些拍摄的素材和不做目标跟踪,是可以。上面的带记忆的时间序列本身也是其他 cv 的核心推动组件,用于目标跟踪方向,目标跟踪很复杂。

第二步:转换生成八个方向的图

  八个方向的概念是 2D 物体,游戏内角色是 3D 透视的,但是在截图快照时,3D 的图也是 2D 的表现,这里还是用笛卡尔坐标系 (高端的是 3D 转 2D 还是 3D 的坐标,这块还没研究出来,要把描边等都自动抠出来在展开)。
  说下基本概念,和怎么去转代码也有关系,假设按现有的图片上面的目标的摆放是 O 起点,O 的角度在图片上面是 dx,dy,dx 和 dy 可以落到四个象限的哪个格子就知道目前输入哪个方位,在进行顺时针转换就是其他方向,要精准点,可以设置转 7 次回到原点。
  这里是不需要知道 label_name 哪个是正面哪个是反面,是整个对象一起转。
  这里是一个最终的形态,不要直接保存为 YOLO 格式,处理起来会比较麻烦,voc 格式的 xml 才是十分合适的,下面是一个例子。
  VOC 是一个训练集比赛的名称,是一种标注格式,会存放在 annotation 文件下面,frame 里面的名字.xml 就是完整的文件,size 就是整个图片的大小。
  object 就是 label_name 打标的对象,这里分别有 person 和 firearms 枪械。

<annotation>
    <frame>000001</frame>
    <object>
        <name>person</name>
        <bndbox>
            <xmin>712</xmin>
            <ymin>415</ymin>
            <xmax>838</xmax>
            <ymax>573</ymax>
        </bndbox>
    </object>
    <object>
        <name>firearms</name>
        <bndbox>
            <xmin>129</xmin>
            <ymin>940</ymin>
            <xmax>300</xmax>
            <ymax>1080</ymax>
        </bndbox>
    </object>
    <size>
        <width>1920</width>
        <height>1080</height>
    </size>
</annotation>

  变量参数方面:除了保存位置之外,需要每张图片增强次数的变量,用于跳出 while 条件。
  编写二个工具类,1.数据增强包含 8 个方向的工具类;2.解析 VOLXml 的工具类。工具类八个方向旋转也是通过 bbox 的处理,VOLXml 处理后是增广图片和 xml 文件是被标记过的。
  就算很精密的计算,也会出现方向图片有黑边的问题,用 cv2.Canny,然后识别轮廓后,进行切除。一般业务的目标对象观测点都在非边框,这里推荐做法用外边框直接设置一定像素的切除也是可行的。这里切除后,后面展示时可以做出拼装成一张大图进行存储。

  八个方向觉得开发起来麻烦的,可以使用左右平移,上下旋转,对角旋转,也是通过 voc 的 bbox 进行处理后 cutout。
  做这块的输入是几张需要做膨胀处理的图片和 Voc 打标方式 -->数据增广的预处理。
  数据增广输出结论是后数据是一个 Json 结构,里面有标签来说明哪些图片对应的 xml 是什么样的功能产出的,匹配标签的是用 id 段来进行计算。
  不同的标签比如八个方向 - 带异常屏的图,降低亮度带蒙板的图,带噪点的图。
  id 段可以自己设计,上面对应标签的分别 id 段的首尾,比如 500-600 之间的是带蒙板的图,这个在 VOLXml 的工具类内部进行实现。

功能落地场景

  打标的推荐使用最佳情况是和打标工具集成在一起。
  打标的推荐使用 labelImg,这个的依赖文件的 torch 和 torchvision 和 Python 环境可以参考下面的 Python 数据结构,来进行安装。

version_mapping = {
    '1.0.1': {'torchvision': '0.2.2', 'python': ['2.7', '3.5', '3.6', '3.7']},
    '1.1.0': {'torchvision': '0.3.0', 'python': ['2.7', '3.5', '3.6', '3.7']},
    '1.2.0': {'torchvision': '0.4.0', 'python': ['2.7', '3.5', '3.6', '3.7']},
    '1.3.0': {'torchvision': '0.4.1', 'python': ['2.7', '3.5', '3.6', '3.7']},
    '1.3.1': {'torchvision': '0.4.2', 'python': ['2.7', '3.5', '3.6', '3.7']},
    '1.4.0': {'torchvision': '0.5.0', 'python': ['2.7', '3.5', '3.6', '3.7']},
    '1.5.0': {'torchvision': '0.6.0', 'python': ['2.7', '3.5', '3.6', '3.7', '3.8']},
    '1.5.1': {'torchvision': '0.6.1', 'python': ['2.7', '3.5', '3.6', '3.7', '3.8']},
    '1.6.0': {'torchvision': '0.7.0', 'python': ['3.6', '3.7', '3.8']},
    '1.7.0': {'torchvision': '0.8.0', 'python': ['3.6', '3.7', '3.8']},
    '1.7.0': {'torchvision': '0.8.1', 'python': ['3.6', '3.7', '3.8']},
    '1.7.1': {'torchvision': '0.8.2', 'python': ['3.6', '3.7', '3.8', '3.9']},
    '1.8.0': {'torchvision': '0.9.0', 'python': ['3.6', '3.7', '3.8', '3.9']},
    '1.8.1': {'torchvision': '0.9.1', 'python': ['3.6', '3.7', '3.8', '3.9']},
    '1.9.0': {'torchvision': '0.10.0', 'python': ['3.6', '3.7', '3.8', '3.9']},
    '1.9.1': {'torchvision': '0.10.1', 'python': ['3.6', '3.7', '3.8', '3.9']},
    '1.10.0': {'torchvision': '0.11.0', 'python': ['3.6', '3.7', '3.8', '3.9']},
    '1.10.1': {'torchvision': '0.11.1', 'python': ['3.6', '3.7', '3.8', '3.9']},
    '1.11.0': {'torchvision': '0.12.0', 'python': ['3.6', '3.7', '3.8', '3.9']},
    '1.11.1': {'torchvision': '0.12.1', 'python': ['3.6', '3.7', '3.8', '3.9']},
    '1.12.0': {'torchvision': '0.13.0', 'python': ['3.7', '3.8', '3.9', '3.10']},
    '1.12.1': {'torchvision': '0.13.1', 'python': ['3.7', '3.8', '3.9', '3.10']},
    '1.13.0': {'torchvision': '0.14.0', 'python': ['3.7', '3.8', '3.9', '3.10']},
    '1.13.1': {'torchvision': '0.14.1', 'python': ['3.7', '3.8', '3.9', '3.10']},
    '2.0.0': {'torchvision': '0.15.0', 'python': ['3.8', '3.9', '3.10', '3.11']},
    '2.0.1': {'torchvision': '0.15.1', 'python': ['3.8', '3.9', '3.10', '3.11']}
}

可以二次开发内容:

  1. 新建 utils/数据增广的文件,开发出增广的函数 (8 个方向)。
  2. 在 labelImg 里面,对 action 偏函数方法,新增一个转换的功能按钮,入口的嵌入的方式 action() 函数的输入参数,第一个 str 是显示按钮的名称 (新增按钮,可以写个字典做中英文切换),第二个是对应的触发函数 (新增的功能的方法),第三个是快捷键 (可以调整为自己想要的热键,抽象出来),第四个是 icon(resources/icons,可以找一些特征明显 icon 替换进去)
  3. 数据增广的文件和正常打标的文件都在保存的瞬间上传到自建文件服务,比如下面:
    路径的推荐:f"/cv-auto/{project_id}/data/{file_type}" project_id:项目编号 file_type:Image 还是 Annotations。 如果上传时需要自动分拆出训练集,按比例,就是多一个文件夹。 PS: 同样开发其他功能也是在这里进行处理,比如新增一个制造花屏的,那也是一样的方式。


↙↙↙阅读原文可查看相关链接,并与作者交流