最近做了一个打架识别的项目,有感于当时开发资料的匮乏,特做一个小结,供大家参考。闲话少叙,看看效果先。
1. 研究现状
目前打架检测,主要有3种主流的方法,分别是:
(1)基于Detection的打架检测。其主要思想是: 将打架作为一种类别,通过分类的方式,将打架行为检测出来。目前这方面的研究较少,且没有公开可用的数据集,想要沿着这条路走,需自备数据集,自行探索。
(2)基于骨骼点的打架检测。其主要思想是:通过OpenPose等框架,将人体的骨骼点回归出来,然后基于骨骼点写逻辑,进行判断。目前有一部分人是基于这个做的打架检测。但是打架过程中如果人员纠缠在一起的话,利用骨骼点准确判断就比较困难。
(3)基于视频理解的打架检测。其主要思想是: 基于时序进行判断。打架对时序有着较强的依赖,利用目标检测技术去识别打架容易出现误检测或者漏检情况。另外如果人员重叠遮挡严重的话,基于骨骼点的行为识别,就有很大的局限性。而基于视频理解的打架检测,则较好的解决了这些问题。但是这种实现起来难度也较大。
2.选取的方案
我这里选择方案1,即基于目标检测做打架识别。前文也提到了,目前数据集十分匮乏。笔者也是反复查找,终于拿到了国外的一份很好的数据集。考虑到不同于一般的目标检测任务,所以数据集也是笔者亲自标注的,没有让第三方人员介入,目的就是保证标注的合理与精准。
基本流程是:
Labelme标注 -> 标注数据整理与格式转换 -> 模型训练 -> 部署
2.1 标注
目前开发工作都是在win11上,采用的是开源的labelme工具。笔者也是头一次使用该工具。使用之后才发现其实还是不错的,功能十分齐全。另外我拿到的国外数据集,是视频的形式,因此需要先将视频转换成图片,然后再进行标注。具体可以参考这篇文章,写的不错。
Labelme标注视频https://www.pudn.com/news/623b0a3f49c1dc3c8980863b.html
Fig.1 利用Labelme进行数据标注
利用几天空闲时间,笔者标注了上千张图片,然后剔除了一些无效图像,最终标注的数据集的信息如下:
标注工具 | Labelme |
数据集名称 | 打架数据集 |
图片数量/格式 | 800张左右/jpg |
图像分辨率 | 1920*1080 |
标注文件格式 | json |
是否涉密 | 否 |
2.2 标注数据整理与格式转换
Labelme标注的数据,无法直接用在训练中,需要自己再转换下。因为准备采用Yolo算法,所以这里我们要将Labelme格式转换成Yolo格式。以下是转换脚本:
""" 2023.1.1 该代码实现了labelme导出的json文件,批量转换成yolo需要的txt文件,且包含了坐标归一化 原来labelme标注之后的是:1.jpg 1.json 经过该脚本处理后,得到的是1.jpg 1.json 1.txt """ import os import numpy as np import json from glob import glob import cv2 from sklearn.model_selection import train_test_split from os import getcwd classes = ["NOFight", "Fight", "Person"] # 1.标签路径 labelme_path = "Data20200108/" isUseTest = False # 是否创建test集 # 3.获取待处理文件 files = glob(labelme_path + "*.json") files = [i.replace("\\", "/").split("/")[-1].split(".json")[0] for i in files] print(files) if isUseTest: trainval_files, test_files = train_test_split(files, test_size=0.1, random_state=55) else: trainval_files = files # split train_files, val_files = train_test_split(trainval_files, test_size=0.1, random_state=55) def convert(size, box): dw = 1. / (size[0]) dh = 1. / (size[1]) x = (box[0] + box[1]) / 2.0 - 1 y = (box[2] + box[3]) / 2.0 - 1 w = box[1] - box[0] h = box[3] - box[2] x = x * dw w = w * dw y = y * dh h = h * dh return (x, y, w, h) wd = getcwd() print(wd) def ChangeToYolo5(files, txt_Name): if not os.path.exists('tmp/'): os.makedirs('tmp/') list_file = open('tmp/%s.txt' % (txt_Name), 'w') for json_file_ in files: json_filename = labelme_path + json_file_ + ".json" imagePath = labelme_path + json_file_ + ".jpg" list_file.write('%s/%s\n' % (wd, imagePath)) out_file = open('%s/%s.txt' % (labelme_path, json_file_), 'w') json_file = json.load(open(json_filename, "r", encoding="utf-8")) height, width, channels = cv2.imread(labelme_path + json_file_ + ".jpg").shape for multi in json_file["shapes"]: points = np.array(multi["points"]) xmin = min(points[:, 0]) if min(points[:, 0]) > 0 else 0 xmax = max(points[:, 0]) if max(points[:, 0]) > 0 else 0 ymin = min(points[:, 1]) if min(points[:, 1]) > 0 else 0 ymax = max(points[:, 1]) if max(points[:, 1]) > 0 else 0 label = multi["label"] if xmax