前言
决定使用Yolov8-pose来做这一个跌倒检测,主要是看重他的关键点识别
标注
这个项目采用labelme标注工具,不用labelimg的原因其一就在于labelimg不能标注关键点
安装labelme很简单,像你安装别的第三方包一样,在终端中键入
pip install labelme
然后在终端中直接输入labelme便可打开
打开后选择你的数据集进行标注
第一步将人物用矩形框框起来,命名为person,并且将group id设置为0
接下来依次标注人体关键点,要严格按照一个自定义的顺序来标注,要不然未来转换文件格式的时候会很麻烦
笔者这里采用了 头-右肩-左肩-身体-右手-左手-右腿-左腿-右脚-左脚 的顺序进行标注,并且将group id设置为1
值得注意的是,标注的过程中也许会遇到没有关键部位的情况,这种情况分为两种,第一种是被遮挡但仍然在画面内,这种情况下我们选择估算他的大概位置,然后进行标注,同时将group id设为2
另一种就是压根不在画面内,就像例图中的腿部与脚部,这种我们直接跳过标注即可,但是切记要按照顺序来标注。
YOLOv8训练需要txt格式的文件,而labelme标注得到的是json格式,因此我们要对其进行格式转换
import json
import os
json_path = r'' # json文件路径
txt_path = r'' # txt文本文件路径
# 关键点数组
pointsArr = ['head', 'rightshoulder', 'leftshoulder', 'body', 'righthand', 'lefthand', 'rightleg', 'leftleg',
'rightfoot', 'leftfoot']
# 坐标归一化,返回中心点坐标和宽高
def coordinates2yolo(xmin, ymin, xmax, ymax, img_w, img_h):
x = abs(xmin + xmax) / (2.0 * img_w)
y = abs(ymin + ymax) / (2.0 * img_h)
w = abs(xmax - xmin) / (1.0 * img_w)
h = abs(ymax - ymin) / (1.0 * img_h)
return x, y, w, h
def writeJson(rootpath, rootpath1, filename):
path = os.path.join(rootpath, filename + '.json')
count = 0 # 记录一张图片中人数的多少
index = 0 # data索引,用于区分json文件中的label值
with open(path) as f:
# 读取json格式文件并获取相应信息
data = json.load(f)
imageHeight = data['imageHeight']
imageWidth = data['imageWidth']
data = data['shapes']
length = len(data)
print('length', length)
# 遍历json文件,用变量count记录 data[i]['label']=’类别名‘ 的次数,以此说明图片中有几个人
for i in range(0, length):
# 类别名换成自己的类别,当有多个类别时,用关键字or进行连接
# if data[i]['label'] == '类别名1' or data[i]['label'] == '类别名2'
if data[i]['label'] == 'person':
count += 1
# 将json文件信息写入txt文本文件中
file = open(os.path.join(rootpath1, filename + '.txt'), mode='w')
for j in range(0, count):
# 在txt文本文件中写入类别id、目标框中心坐标以及图片宽高
file.write(str(data[index]['group_id']))
file.write(" ")
points = data[index]['points']
print(points)
xmin = points[0][0]
print(xmin)
ymin = points[0][1]
print(ymin)
xmax = points[1][0]
print(xmax)
ymax = points[1][1]
print(ymax)
x, y, w, h = coordinates2yolo(xmin, ymin, xmax, ymax, imageWidth, imageHeight)
file.write(str(round(x, 6)))
file.write(" ")
file.write(str(round(y, 6)))
file.write(" ")
file.write(str(round(w, 6)))
file.write(" ")
file.write(str(round(h, 6)))
file.write(" ")
index += 1
# 在txt文本文件中写入关键点坐标与对应id值
for point in pointsArr:
# print(index)
# print(data)
if index < length:
if data[index]['label'] == point:
point = data[index]['points'] # 获取关键点的坐标值
file.write(str(round(point[0][0] / imageWidth, 6)))
file.write(" ")
file.write(str(round(point[0][1] / imageHeight, 6)))
file.write(" ")
# data[index]['group_id'] == 2,表名为被遮挡的关键点,在txt文档中写入1
if data[index]['group_id'] == 2:
file.write('1.000000')
file.write(" ")
# data[index]['group_id'] != 2,表名为正常标记的关键点,在txt文档中写入2
else:
file.write('2.000000')
file.write(" ")
index += 1
# 若data[index]['label'] != point,则写入(0, 0, 0),前两个代表坐标,最后一个‘0’代表此关键点未被标记
else:
file.write('0.000000')
file.write(" ")
file.write('0.000000')
file.write(" ")
file.write('0.000000')
file.write(" ")
else:
file.write('0.000000')
file.write(" ")
file.write('0.000000')
file.write(" ")
file.write('0.000000')
file.write(" ")
file.write('\n')
# 读取path路径中的文件
filenames = os.listdir(json_path)
for item in filenames:
# 以'.'为标志分割获取文件名
filename = item.split('.')[0]
print(filename)
writeJson(json_path, txt_path, filename)
训练采用yolov8n-pose.pt模型
yolo pose train data=pose.yaml model=yolov8n-pose.pt project= name= epochs=50 batch=16 device=cpu
pose.yaml内部格式
# 数据集的根目录路径。
path:
# 训练集的相对路径
train: train
# 验证集的相对路径
val: val
test: val
# 关键点的形状,表示有10个关键点,每个关键点有3个维度(通常是x坐标、y坐标和一个表示可见性的标记)。
kpt_shape: [10, 3]
# 类别名称。
names:
0: person
Comments NOTHING