【工具包使用】解析Multi-Modal Driver Behaviors Dataset for DMS数据集
前言
博主查阅驾驶员异常行为检测数据集时搜索到Multi-Modal Driver Behaviors Dataset for DMS - MagicHub,之后下载解析,整理数据集用于训练;
一、MULTI-MODAL DRIVER BEHAVIORS DATASET FOR DMS简介
数据集中30,892 images for Driver Monitoring System (DMS) (Male: 12,704 images; Female: 18,188 images),下载共15.1G大小,使用IR camera获取的图像,图像尺寸1280*720*3,图像格式png,标注文件格式txt,标注文件包含多条标注数据,一行表示一张图像的标注数据;
一张图像对应的标注数据如下:
[{"info":{"createdTime":"2022-12-07 11:48:55","edition":1,"aStep":[2271],"aBy":["4547"],"vStep":[2272,2273],"vBy":["4548",""],"comments":"comments","package_id":3117549},"cause":"","image":{"area":921600,"depth":3,"width":1280,"height":720,"file_url":"http://magicdatacloud.oss-accelerate.aliyuncs.com/prod/magicdatacloud/dataSet/CV2D/20221127/IRCamera_ID00011_20222017_女_21_DZ05_hat_000000448.png","file_name":"IRCamera_ID00011_20222017_女_21_DZ05_hat_000000448.png"},"valid":true,"rotation":0,"categories":[],"dataItemId":3807808,"annotations":[{"id":"101","ocr":[],"points":[{"x":0.704358,"y":0.231201},{"x":0.956219,"y":0.231201},{"x":0.956219,"y":0.745359},{"x":0.704358,"y":0.745359}],"coordinate":[{"x":901.577904,"y":166.465037},{"x":1223.960514,"y":166.465044},{"x":1223.960478,"y":536.658201},{"x":901.577904,"y":536.658201}],"visibility":true,"isInside":true,"strokeWidth":"2","type":"rectangle","labels":[{"id":"c919c617c8cf45a78a1a815cdcb5b644","type":"cascader","color":"#FE6A92","label":[[{"label":"人头","display":true,"labelName":"人头"}]],"title":"类别"}]},{"id":"102","ocr":[],"points":[{"x":0.770525,"y":0.379188},{"x":0.949816,"y":0.379188},{"x":0.949816,"y":0.731129},{"x":0.770525,"y":0.731129}],"coordinate":[{"x":986.271707,"y":273.015137},{"x":1215.764353,"y":273.015146},{"x":1215.764317,"y":526.413083},{"x":986.271707,"y":526.413083}],"visibility":true,"isInside":true,"strokeWidth":"2","type":"rectangle","labels":[{"id":"c919c617c8cf45a78a1a815cdcb5b644","type":"cascader","color":"#0CC2D9","label":[[{"label":"人脸","display":true,"labelName":"人脸"}]],"title":"类别"}]},{"id":"103","ocr":[],"points":[{"x":0.903671,"y":0.578706},{"x":0.999086,"y":0.578706},{"x":0.999086,"y":0.788246},{"x":0.903671,"y":0.788246}],"coordinate":[{"x":1156.699082,"y":416.668595},{"x":1278.830711,"y":416.668595},{"x":1278.830711,"y":567.537077},{"x":1156.699082,"y":567.537077}],"visibility":true,"isInside":true,"strokeWidth":"2","type":"rectangle","labels":[{"id":"c919c617c8cf45a78a1a815cdcb5b644","type":"cascader","color":"#A057FF","label":[[{"label":"交互物品","display":true,"labelName":"交互物品"},{"label":"手机","display":true,"labelName":"手机"}]],"title":"类别"}]},{"id":"104","ocr":[],"points":[{"x":0.822329,"y":0.838963},{"x":0.755184,"y":1},{"x":0.814927,"y":1},{"x":0.855888,"y":0.858493},{"x":0.835892,"y":0.806619},{"x":0.822329,"y":0.838963}],"coordinate":[{"x":1052.581201,"y":604.05349},{"x":966.635536,"y":720.000246},{"x":1043.106925,"y":720.000246},{"x":1095.536172,"y":618.114877},{"x":1069.941163,"y":580.765756},{"x":1052.581201,"y":604.05349}],"visibility":true,"isInside":true,"strokeWidth":"2","type":"polygon","labels":[{"id":"c919c617c8cf45a78a1a815cdcb5b644","type":"cascader","color":"#910082","label":[[{"label":"安全带","display":true,"labelName":"安全带"}]],"title":"类别"}]}],"invalid_reason":""}]
目前解析数据看到的类别有人脸、人头、安全带、交互物品、食物(吃喝)、手机、烟、打火机、其他,标注目标区域的方式包括polygon、rectangle,其中食物、手机、烟、打火机的标注类别是rectangle,另外需要注意的是不同标注数据坐标点的顺序不一样且没有规则(只能通过所有数据点求解bbox的min/max),共筛选出来5537张图像用于训练;
二、标注数据解析过程
code
import os def parse_onedata(data): print('data: ', data) info = data['info'] image = data['image'] valid = data['valid'] rotation = data['rotation'] categories = data['categories'] annotations = data['annotations'] print('image filename: ', image['file_name']) print('annotations len: ', len(annotations)) def parse_txtfile(path): imagedir = 'ID00011_female' filename = 'DCV20221108451508P0320221207114849.txt' filepath = os.path.join(path, imagedir, filename) print('imagedir: ', imagedir) txtfile = open(filepath) txtdata = txtfile.readlines() print('txtdata len: ', len(txtdata)) for onedata in txtdata: print(type(onedata)) onedata = onedata.replace('true', 'True') data = eval(onedata) print(type(eval(onedata)[0])) parse_onedata(data[0]) break if __name__ == "__main__": path = os.path.dirname(os.path.realpath(__file__)) parse_txtfile(path)
注意,二维字典列表转换为数组或者列表;注意数据类型;
标注数据解析:
import os import numpy as np import cv2 as cv import shutil def parse_onedata(data, imgdir, path): # print('data: ', data) info = data['info'] image = data['image'] valid = data['valid'] rotation = data['rotation'] categories = data['categories'] annotations = data['annotations'] # print('image filename: ', image['file_name']) # print('annotations len: ', len(annotations)) imgw = image['width'] imgh = image['height'] imgname = image['file_name'] imgdir1 = 'images_18188' img = cv.imread(os.path.join(path, imgdir, imgdir1, imgname)) # print('path: ', path) # print('path: ', imgdir) # print('path: ', imgname) for anno in annotations: points = anno['points'] coords = anno['coordinate'] pts = [] for coord in coords: pts.append([int(coord[key]) for key in coord]) annotype = anno['type'] labels = anno['labels'][0] # dict. label = labels['label'][0][-1]['label'] # print('label: ', type(label)) # print('label: ', label) if label == '人脸': enlabel = 'face' elif label == '人头': enlabel = 'head' elif label == '安全带': enlabel = 'belt' elif label == '手机': enlabel = 'phone' elif label == '烟': enlabel = 'smoke' elif label == '食物': enlabel = 'food' elif label == '打火机': enlabel = 'zippo' elif label == '交互物品': enlabel = 'items' else: enlabel = label print('new label to add: ', label) if annotype == 'rectangle': xmin = int(min(pts[0][0], pts[1][0], pts[2][0], pts[3][0]) - 1) ymin = int(min(pts[0][1], pts[1][1], pts[2][1], pts[3][1]) - 1) xmax = int(max(pts[0][0], pts[1][0], pts[2][0], pts[3][0]) - 1) ymax = int(max(pts[0][1], pts[1][1], pts[2][1], pts[3][1]) - 1) cv.rectangle(img, (xmin,ymin), (xmax, ymax), (0, 255, 213), 3) else: npts = np.array(pts, dtype=np.int32) npts = npts.reshape(-1, 1, 2) cv.polylines(img, [npts], True, (0, 255, 66), thickness=2) cv.putText(img, enlabel, pts[0], cv.FONT_HERSHEY_SIMPLEX, 2, (225, 18, 255), 1, cv.LINE_AA) cv.imshow('dms', img) if cv.waitKey(100) == 27: print('27') cv.destroyWindow('dms') def parse_txtfile(path): imagedir = 'ID00011_female' filename = 'DCV20221108451508P0320221207114849.txt' filepath = os.path.join(path, imagedir, filename) # print('imagedir: ', imagedir) txtfile = open(filepath) txtdata = txtfile.readlines() # print('txtdata len: ', len(txtdata)) k = 0 for onedata in txtdata: # print(type(onedata)) onedata = onedata.replace('true', 'True') onedata = onedata.replace('false', 'False') data = eval(onedata) # print(type(eval(onedata)[0])) parse_onedata(data[0], imagedir, path) # k = k + 1 # if k > 10: # break def get_bbox(size, box): # Convert xyxy box to YOLOv5 xywh box dw = 1. / size[0] dh = 1. / size[1] xc = (box[0] + box[2])*0.5*dw yc = (box[1] + box[3])*0.5*dh w = (box[2]-box[0])*dw h = (box[3]-box[1])*dh return xc, yc, w, h def filter_onedata(data, imgdir, imgdir1, path): image = data['image'] annotations = data['annotations'] imgw = image['width'] imgh = image['height'] imgname = image['file_name'] # imgdir1 = 'images_18188' old_image_name = os.path.join(path, imgdir, imgdir1, imgname) # img = cv.imread(os.path.join(path, imgdir, imgdir1, imgname)) labelpath = os.path.join(path, 'badbehavior', 'label') imagepath = os.path.join(path, 'badbehavior', 'image') flag = False info = f"" for anno in annotations: points = anno['points'] coords = anno['coordinate'] pts = [] for coord in coords: pts.append([int(coord[key]) for key in coord]) annotype = anno['type'] labels = anno['labels'][0] # dict. label = labels['label'][0][-1]['label'] # rectangle not polygon if annotype == 'polygon': continue xmin = int(min(pts[0][0], pts[1][0], pts[2][0], pts[3][0]) - 1) ymin = int(min(pts[0][1], pts[1][1], pts[2][1], pts[3][1]) - 1) xmax = int(max(pts[0][0], pts[1][0], pts[2][0], pts[3][0]) - 1) ymax = int(max(pts[0][1], pts[1][1], pts[2][1], pts[3][1]) - 1) xywh = get_bbox((imgw,imgh), [xmin, ymin, xmax, ymax]) if label == '手机': # enlabel = 'phone' classid = 0 flag = True info += f"{classid} {' '.join(f'{x:.6f}' for x in xywh)}\n" elif label == '烟': # enlabel = 'smoke' classid = 1 flag = True info += f"{classid} {' '.join(f'{x:.6f}' for x in xywh)}\n" elif label == '食物': # enlabel = 'food' classid = 2 flag = True info += f"{classid} {' '.join(f'{x:.6f}' for x in xywh)}\n" else: continue if flag: # copy image new_image_name = os.path.join(imagepath, imgname) shutil.copyfile(old_image_name, new_image_name) # save label file labelname = os.path.join(labelpath, imgname.replace('png', 'txt')) labelfile = open(labelname, 'w+') labelfile.write(info) labelfile.close() def filter_badbehavior_female(path): # ├── ID00011_female # ├── DCV20221108451508P0320221207114849.txt # └── images_18188 # names: ['phone', 'smoke', 'food'] imagedir = 'ID00011_female' imgdir1 = 'images_18188' filename = 'DCV20221108451508P0320221207114849.txt' filepath = os.path.join(path, imagedir, filename) txtfile = open(filepath) txtdata = txtfile.readlines() k = 0 for onedata in txtdata: onedata = onedata.replace('true', 'True') onedata = onedata.replace('false', 'False') data = eval(onedata) filter_onedata(data[0], imagedir, imgdir1, path) def filter_badbehavior_male(path): # ├── ID00013_male # ├── DCV20221108451508P0120221207122717.txt # └── images_12704 # names: ['phone', 'smoke', 'food'] imagedir = 'ID00013_male' imgdir1 = 'images_12704' filename = 'DCV20221108451508P0120221207122717.txt' filepath = os.path.join(path, imagedir, filename) txtfile = open(filepath) txtdata = txtfile.readlines() k = 0 for onedata in txtdata: onedata = onedata.replace('true', 'True') onedata = onedata.replace('false', 'False') data = eval(onedata) filter_onedata(data[0], imagedir, imgdir1, path) if __name__ == "__main__": path = os.path.dirname(os.path.realpath(__file__)) # parse_txtfile(path) filter_badbehavior_male(path) print("---------------------Start Female----------------------------------------------------------------------------------") filter_badbehavior_female(path)
注意标注数据和文件名称含有中文,使用rename和替换操作更改名称即可;
1) rename “s/old/new/" * # 目录下所有文件名包含old的字符更改为new字符 2) vim: :%s/old/new/gc # gc可用于判断是否替换
:23, 300s/old/new/gc
参考
1. 数据开源 | Magic Data开源DMS驾驶员行为数据集;
完
各美其美,美美与共,不和他人作比较,不对他人有期待,不批判他人,不钻牛角尖。
心正意诚,做自己该做的事情,做自己喜欢做的事情,安静做一枚有思想的技术媛。
版权声明,转载请注明出处:https://www.cnblogs.com/happyamyhope/
心正意诚,做自己该做的事情,做自己喜欢做的事情,安静做一枚有思想的技术媛。
版权声明,转载请注明出处:https://www.cnblogs.com/happyamyhope/