【工具包使用】解析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)
View Code

注意标注数据和文件名称含有中文,使用rename和替换操作更改名称即可;

1) rename “s/old/new/" *   # 目录下所有文件名包含old的字符更改为new字符
2) vim:
:%s/old/new/gc  # gc可用于判断是否替换
:23, 300s/old/new/gc

 

参考

1. 数据开源 | Magic Data开源DMS驾驶员行为数据集

 

posted on 2023-11-06 18:38  鹅要长大  阅读(97)  评论(0编辑  收藏  举报

导航