行人实时动作识别

  • 详细资料和代码请加微信:17324069443

一、项目介绍

基于PyTorchVideo的实时动作识别框架:
我们选择了yolov5作为目标检测器,而不是Faster R-CNN,它速度更快、更方便。
我们使用一个跟踪器(deepsort)来为不同帧中所有具有相同ID的对象分配动作标签。
行为识别使用 slowfast算法,根据前后帧的图片,分析这个序列,来判断是做了什么动作
我们在单个RTX 2080Ti GPU上以30个推理批处理大小达到了24.2 FPS的处理速度。
在这里插入图片描述

二、算法介绍

2.1 yolov5目标检测

YOLOv5是一种基于深度学习的目标检测算法,它在目标检测和图像识别领域具有很高的性能。YOLOv5建立在先前版本(如YOLOv3和YOLOv4)的基础上,通过引入一系列改进来提高检测准确性和速度。
YOLOv5的核心架构是基于单阶段目标检测器(one-stage detector)。与传统的两阶段方法不同,YOLOv5通过单个神经网络模型直接从图像中预测目标的类别和边界框位置。这使得YOLOv5在速度和准确性之间取得了良好的平衡,适用于许多实时应用场景。
YOLOv5的主要特点和优势包括:

  • 轻量化设计
  • 多尺度检测
  • 自动数据增强
  • 简单易用

YOLOv5在许多基准数据集上取得了优秀的检测性能,并且被广泛应用于实际场景中,包括智能监控、自动驾驶、工业检测等领域。其高性能和灵活性使得YOLOv5成为目标检测领域的热门选择之一。

2.2 DeepSort目标跟踪

DeepSort是一种基于深度学习的目标跟踪算法,旨在解决多目标跟踪问题。它结合了目标检测和目标跟踪两个关键任务,能够在视频序列中准确地追踪多个目标并分配唯一的ID。
DeepSort算法的核心思想是将卷积神经网络(CNN)用于目标检测,以便识别视频帧中的目标,并结合深度学习技术来进行目标特征提取和关联。具体来说,DeepSort首先使用一个预训练的目标检测器(如YOLO或Faster R-CNN)来检测视频帧中的目标,并提取目标的特征表示。
接着,DeepSort利用深度学习模型(通常是基于Siamese网络或类似的架构)来计算不同目标之间的相似度,并根据目标之间的特征相似性来进行目标关联。通过在时间序列中跟踪目标的位置,并根据目标的外观和运动特征来更新目标的状态,DeepSort能够有效地处理目标在视频中的出现、消失和遮挡等情况,实现稳健的多目标跟踪。
DeepSort算法在目标跟踪领域取得了显著的成果,特别是在具有复杂背景和目标重叠的场景下表现突出。它在许多跟踪竞赛和实际应用中都取得了优异的性能,成为目标跟踪领域的重要算法之一。深度学习方法的引入使得DeepSort在目标跟踪任务中更加准确、高效,并且具有良好的通用性和可扩展性。

2.3 slowfast动作识别

SlowFast是一种用于视频动作识别的深度学习算法。它是在Facebook AI研究团队提出的基础上发展而来的,旨在解决传统的单帧或连续帧方法在动作识别任务中存在的困难。
SlowFast算法的核心思想是引入两个不同速度的流来处理视频数据:慢速流(Slow)和快速流(Fast)。慢速流用于捕捉视频中的空间细节,它对每个帧进行较高的时间采样,以更好地理解运动的细节。快速流则用于捕捉动作的快速变化,它对每个帧进行较低的时间采样,以更好地捕捉动作的整体动态。
具体实现上,SlowFast网络由两个并行的卷积神经网络流组成:慢速流和快速流。慢速流通常包含较多的卷积层和较大的时间步长,以便对空间细节进行更深入的分析。而快速流则包含较少的卷积层和较小的时间步长,以便对动作的快速变化进行快速响应。
在训练过程中,SlowFast网络通过使用慢速流和快速流来学习视频的空间和时间特征,以及它们之间的关系。通过在大规模视频数据集上进行训练,SlowFast网络能够学习到通用的动作表示,从而在动作识别任务中取得良好的性能。
SlowFast算法在视频动作识别领域表现出色,其能够有效地捕捉视频中的空间和时间信息,并且在处理速度和准确率之间取得了良好的平衡。它在许多视频动作识别的挑战中取得了领先的结果,并被广泛应用于视频分析、智能监控等领域。

三、代码实现

  1. 读取视频或者摄像头中的图片
  2. 通过 yolo 检测出画面的目标
  3. 通过 deep_sort 对目标进行跟踪
  4. 通过 slowfast 识别出目标的动作
  5. 可以根据识别的动作进行业务处理等
def tensor_to_numpy(tensor):
    img = tensor.cpu().numpy().transpose((1, 2, 0))
    return img

def ava_inference_transform(clip, boxes,
    num_frames = 32, #if using slowfast_r50_detection, change this to 32, 4 for slow 
    crop_size = 640, 
    data_mean = [0.45, 0.45, 0.45], 
    data_std = [0.225, 0.225, 0.225],
    slow_fast_alpha = 4, #if using slowfast_r50_detection, change this to 4, None for slow
):
    boxes = np.array(boxes)
    roi_boxes = boxes.copy()
    clip = uniform_temporal_subsample(clip, num_frames)
    clip = clip.float()
    clip = clip / 255.0
    height, width = clip.shape[2], clip.shape[3]
    boxes = clip_boxes_to_image(boxes, height, width)
    clip, boxes = short_side_scale_with_boxes(clip,size=crop_size,boxes=boxes,)
    clip = normalize(clip,
        np.array(data_mean, dtype=np.float32),
        np.array(data_std, dtype=np.float32),) 
    boxes = clip_boxes_to_image(boxes, clip.shape[2],  clip.shape[3])
    if slow_fast_alpha is not None:
        fast_pathway = clip
        slow_pathway = torch.index_select(clip,1,
            torch.linspace(0, clip.shape[1] - 1, clip.shape[1] // slow_fast_alpha).long())
        clip = [slow_pathway, fast_pathway]
    
    return clip, torch.from_numpy(boxes), roi_boxes

def plot_one_box(x, img, color=[100,100,100], text_info="None",
                 velocity=None,thickness=1,fontsize=0.5,fontthickness=1):
    # Plots one bounding box on image img
    c1, c2 = (int(x[0]), int(x[1])), (int(x[2]), int(x[3]))
    cv2.rectangle(img, c1, c2, color, thickness, lineType=cv2.LINE_AA)
    t_size = cv2.getTextSize(text_info, cv2.FONT_HERSHEY_TRIPLEX, fontsize , fontthickness+2)[0]
    cv2.rectangle(img, c1, (c1[0] + int(t_size[0]), c1[1] + int(t_size[1]*1.45)), color, -1)
    cv2.putText(img, text_info, (c1[0], c1[1]+t_size[1]+2), 
                cv2.FONT_HERSHEY_TRIPLEX, fontsize, [255,255,255], fontthickness)
    return img

def deepsort_update(Tracker,pred,xywh,np_img):
    outputs = Tracker.update(xywh, pred[:,4:5],pred[:,5].tolist(),cv2.cvtColor(np_img,cv2.COLOR_BGR2RGB))
    return outputs

def save_yolopreds_tovideo(yolo_preds,id_to_ava_labels,color_map,output_video):
    for i, (im, pred) in enumerate(zip(yolo_preds.ims, yolo_preds.pred)):
        im=cv2.cvtColor(im,cv2.COLOR_BGR2RGB)
        if pred.shape[0]:
            for j, (*box, cls, trackid, vx, vy) in enumerate(pred):
                if int(cls) != 0:
                    ava_label = ''
                elif trackid in id_to_ava_labels.keys():
                    ava_label = id_to_ava_labels[trackid].split(' ')[0]
                else:
                    ava_label = 'Unknow'
                text = '{} {} {}'.format(int(trackid),yolo_preds.names[int(cls)],ava_label)
                color = color_map[int(cls)]
                im = plot_one_box(box,im,color,text)
        output_video.write(im.astype(np.uint8))

def main(config):
    model = torch.hub.load('ultralytics/yolov5', 'yolov5l6')
    model.conf = config.conf
    model.iou = config.iou
    model.max_det = 200
    if config.classes:
        model.classes = config.classes
    device = config.device
    imsize = config.imsize
    video_model = slowfast_r50_detection(True).eval().to(device)
    deepsort_tracker = DeepSort("data/models/ckpt.t7")
    ava_labelnames,_ = AvaLabeledVideoFramePaths.read_label_map("selfutils/temp.pbtxt")
    coco_color_map = [[random.randint(0, 255) for _ in range(3)] for _ in range(80)]

    vide_save_path = config.output
    video=cv2.VideoCapture(config.input)
    width,height = int(video.get(3)),int(video.get(4))
    video.release()
    outputvideo = cv2.VideoWriter(vide_save_path,cv2.VideoWriter_fourcc(*'mp4v'), 25, (width,height))
    print("processing...")
    
    video = pytorchvideo.data.encoded_video.EncodedVideo.from_path(config.input)
    a=time.time()
    for i in range(0,math.ceil(video.duration),1):
        video_clips=video.get_clip(i, i+1-0.04)
        video_clips=video_clips['video']
        if video_clips is None:
            continue
        img_num=video_clips.shape[1]
        imgs=[]
        for j in range(img_num):
            imgs.append(tensor_to_numpy(video_clips[:,j,:,:]))
        yolo_preds=model(imgs, size=imsize)
        yolo_preds.files=[f"img_{i*25+k}.jpg" for k in range(img_num)]

        print(i,video_clips.shape,img_num)
        deepsort_outputs=[]
        for j in range(len(yolo_preds.pred)):
            temp=deepsort_update(deepsort_tracker,yolo_preds.pred[j].cpu(),yolo_preds.xywh[j][:,0:4].cpu(),yolo_preds.ims[j])
            if len(temp)==0:
                temp=np.ones((0,8))
            deepsort_outputs.append(temp.astype(np.float32))
        yolo_preds.pred=deepsort_outputs
        id_to_ava_labels={}
        if yolo_preds.pred[img_num//2].shape[0]:
            inputs,inp_boxes,_=ava_inference_transform(video_clips,yolo_preds.pred[img_num//2][:,0:4],crop_size=imsize)
            inp_boxes = torch.cat([torch.zeros(inp_boxes.shape[0],1), inp_boxes], dim=1)
            if isinstance(inputs, list):
                inputs = [inp.unsqueeze(0).to(device) for inp in inputs]
            else:
                inputs = inputs.unsqueeze(0).to(device)
            with torch.no_grad():
                slowfaster_preds = video_model(inputs, inp_boxes.to(device))
                slowfaster_preds = slowfaster_preds.cpu()
            for tid,avalabel in zip(yolo_preds.pred[img_num//2][:,5].tolist(),np.argmax(slowfaster_preds,axis=1).tolist()):
                id_to_ava_labels[tid]=ava_labelnames[avalabel+1]
        save_yolopreds_tovideo(yolo_preds,id_to_ava_labels,coco_color_map,outputvideo)
    print("total cost: {:.3f}s, video clips length: {}s".format(time.time()-a,video.duration))
    outputvideo.release()
    print('saved video to:', vide_save_path)
    
    
if __name__=="__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('--input', type=str, default="data/1.mov", help='test imgs folder or video or camera')
    parser.add_argument('--output', type=str, default="data/output.mp4", help='folder to save result imgs, can not use input folder')
    # object detect config
    parser.add_argument('--imsize', type=int, default=640, help='inference size (pixels)')
    parser.add_argument('--conf', type=float, default=0.4, help='object confidence threshold')
    parser.add_argument('--iou', type=float, default=0.4, help='IOU threshold for NMS')
    parser.add_argument('--device', default='cpu', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
    parser.add_argument('--classes', nargs='+', type=int, help='filter by class: --class 0, or --class 0 2 3')
    config = parser.parse_args()
    print(config)
    main(config)
  • 22
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值