[Seguimiento de peatones y detección y alarma de caídas (YOLO V3 Tiny, Deepsort, ST-GCN)]

prefacio

Utilice los métodos YOLO V3 Tiny, Deepsort, ST-GCN para el seguimiento de peatones y la detección de caídas. Entre ellos, YOLO V3 Tiny se usa para la detección de peatones, DeepSort se usa para el seguimiento y ST-GCN se usa para la detección de comportamiento.

Introducción al proyecto

Para el proyecto de detección de caídas, hay discriminación directa a través del marco de detección YOLO y reconocimiento a través de openpose, pero los
requisitos para la dirección de la cámara son muy altos, y el efecto de detección de ángulo del lado es ideal, pero la detección de ángulo de la cámara ubicada en un lugar alto o en la parte posterior El efecto es deficiente. El uso de ST-GCN en este proyecto tiene un mejor efecto en la detección de caídas en diferentes ángulos.

Use Tiny YOLO oneclass para detectar a cada persona en el cuadro y use AlphaPose para obtener la pose esquelética, luego use el modelo ST-GCN para predecir la acción en cada 30 cuadros rastreados por cada persona.

Este proyecto entrena un nuevo modelo de clase única TinyYOLO para detectar solo objetos humanos y reduce el tamaño del modelo. Entrenado utilizando el conjunto de datos de puntos clave de personas COCO aumentados por rotación para una detección de personas más sólida en diferentes poses de ángulo.

Para el reconocimiento de acciones, utilice los datos del conjunto de datos de detección de caídas de Le2i (sala de café, hogar) para extraer poses esqueléticas a través de AlphaPose y marque manualmente cada cuadro de acción para entrenar el modelo ST-GCN.

Ahora admite 7 acciones: pararse, caminar, sentarse, acostarse, ponerse de pie, sentarse, caer.

Introducción a ST-GCN

inserte la descripción de la imagen aquí
Dada la información de secuencia de esqueleto de un video de acción, primero construya una estructura de gráfico que represente la información de secuencia de esqueleto, la entrada de ST-GCN es el vector de coordenadas conjuntas en el nodo de gráfico; luego, una serie de operaciones de convolución de gráfico espaciotemporal para extraer el alto características de nivel; finalmente utilice el clasificador SofMax para obtener la clasificación de acción correspondiente. Todo el proceso se da cuenta de la formación de extremo a extremo.

GCN nos ayuda a aprender las características locales de las juntas adyacentes en el espacio. Sobre esta base, necesitamos aprender las características locales de los cambios conjuntos en el tiempo. Cómo superponer características de tiempo para Graph es uno de los problemas que enfrentan las redes convolucionales de gráficos. Hay dos ideas principales para la investigación en esta área: Time Convolution (TCN) y Sequence Model (LSTM).

ST-GCN usa TCN. Debido a la forma fija, la operación de convolución de tiempo se puede completar usando capas convolucionales tradicionales. Para facilitar la comprensión, se puede comparar la operación de convolución de una imagen. La forma de las últimas tres dimensiones del mapa de características de ST-GCN es (C, V, T), que corresponde a la forma (C, W, H) del mapa de características de la imagen.

El número de canal C de la imagen corresponde al número de característica C de la unión.
El ancho W de la imagen corresponde al número V de fotogramas clave.
La altura H de la imagen corresponde al número T de juntas.

En la convolución de imágenes, el tamaño del kernel de convolución es "w" × "1", y la convolución de w filas de píxeles y 1 columna de píxeles se completa cada vez. "zancada" es s, luego mueve s píxeles cada vez y luego realiza la convolución de la siguiente fila de píxeles después de completar una fila.

En la convolución temporal, el tamaño del kernel de convolución es "temporal_kernel_size" × "1", y la convolución de 1 nodo y fotogramas clave de temporal_kernel_size se completa cada vez. Si "zancada" es 1, se mueve 1 cuadro a la vez, completa 1 nodo y realiza la convolución del siguiente nodo. Aquí está el entrenamiento:

inserte la descripción de la imagen aquí

Los datos de entrada primero se normalizan por lotes, luego se pasan a través de 9 unidades ST-GCN, seguido de una agrupación global para obtener el vector de características de 256 dimensiones de cada secuencia y, finalmente, se clasifican con la función SoftMax para obtener la etiqueta final.

Cada ST-GCN adopta la estructura de Resnet. La salida de las primeras tres capas tiene 64 canales, las tres capas del medio tienen 128 canales y las últimas tres capas tienen 256 canales. Después de pasar por la estructura ST-CGN cada vez, con una probabilidad de 0.5 Establezca aleatoriamente la eliminación de características, los avances de las capas convolucionales temporales 4 y 7 en 2. Entrenado con SGD, la tasa de aprendizaje es 0,01 y la tasa de aprendizaje disminuye en 0,1 cada 10 épocas.
Enlace del artículo ST-GCN: https://arxiv.org/abs/1801.07455

cuerpo del código

import os
import cv2
import time
import torch
import argparse
import numpy as np

from Detection.Utils import ResizePadding
from CameraLoader import CamLoader, CamLoader_Q
from DetectorLoader import TinyYOLOv3_onecls

from PoseEstimateLoader import SPPE_FastPose
from fn import draw_single

from Track.Tracker import Detection, Tracker
from ActionsEstLoader import TSSTG

# source = '../Data/test_video/test7.mp4'
# source = '../Data/falldata/Home/Videos/video (2).avi'  # hard detect ./output/test5.mp4
source = './output/test4.mp4'


# source = 2


def preproc(image):
    """preprocess function for CameraLoader.
    """
    image = resize_fn(image)
    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    return image


def kpt2bbox(kpt, ex=20):
    """Get bbox that hold on all of the keypoints (x,y)获取保持所有关键点(x,y)的bbox
    kpt: array of shape `(N, 2)`,
    ex: (int) expand bounding box,
    """
    return np.array((kpt[:, 0].min() - ex, kpt[:, 1].min() - ex,
                     kpt[:, 0].max() + ex, kpt[:, 1].max() + ex))


if __name__ == '__main__':
    par = argparse.ArgumentParser(description='Human Fall Detection Demo.')
    par.add_argument('-C', '--camera', default=source,  # required=True,  # default=2,
                     help='Source of camera or video file path.')
    par.add_argument('--detection_input_size', type=int, default=384,
                     help='Size of input in detection model in square must be divisible by 32 (int).')
    par.add_argument('--pose_input_size', type=str, default='224x160',
                     help='Size of input in pose model must be divisible by 32 (h, w)')
    par.add_argument('--pose_backbone', type=str, default='resnet50', help='Backbone model for SPPE FastPose model.')
    par.add_argument('--show_detected', default=False, action='store_true', help='Show all bounding box from detection.')
    par.add_argument('--show_skeleton', default=True, action='store_true', help='Show skeleton pose.')
    par.add_argument('--save_out', type=str, default='./output/output7.mp4', help='Save display to video file.')
    par.add_argument('--device', type=str, default='cuda', help='Device to run model on cpu or cuda.')
    args = par.parse_args()

    device = args.device

    # DETECTION MODEL.检测模型
    inp_dets = args.detection_input_size
    detect_model = TinyYOLOv3_onecls(inp_dets, device=device)

    # POSE MODEL.姿势模型
    inp_pose = args.pose_input_size.split('x')
    inp_pose = (int(inp_pose[0]), int(inp_pose[1]))
    pose_model = SPPE_FastPose(args.pose_backbone, inp_pose[0], inp_pose[1], device=device)

    # Tracker.跟踪器
    max_age = 30
    tracker = Tracker(max_age=max_age, n_init=3)

    # Actions Estimate.
    action_model = TSSTG()

    resize_fn = ResizePadding(inp_dets, inp_dets)

    cam_source = args.camera
    if type(cam_source) is str and os.path.isfile(cam_source):
        # Use loader thread with Q for video file.
        cam = CamLoader_Q(cam_source, queue_size=1000, preprocess=preproc).start()
    else:
        # Use normal thread loader for webcam.
        cam = CamLoader(int(cam_source) if cam_source.isdigit() else cam_source,
                        preprocess=preproc).start()

    # frame_size = cam.frame_size
    # scf = torch.min(inp_size / torch.FloatTensor([frame_size]), 1)[0]

    outvid = False
    if args.save_out != '':
        outvid = True
        codec = cv2.VideoWriter_fourcc(*'mp4v')
        print((inp_dets * 2, inp_dets * 2))
        writer = cv2.VideoWriter(args.save_out, codec, 25, (inp_dets * 2, inp_dets * 2))

    fps_time = 0
    f = 0
    while cam.grabbed():
        f += 1
        frame = cam.getitem()
        image = frame.copy()

        # Detect humans bbox in the frame with detector model.使用检测器模型检测帧中的人类bbox
        detected = detect_model.detect(frame, need_resize=False, expand_bb=10)

        # Predict each tracks bbox of current frame from previous frames information with Kalman filter.从先前帧信息预测当前帧的每个轨迹bbox
        tracker.predict()
        # Merge two source of predicted bbox together.将两个预测bbox源合并在一起
        for track in tracker.tracks:
            det = torch.tensor([track.to_tlbr().tolist() + [0.5, 1.0, 0.0]], dtype=torch.float32)
            detected = torch.cat([detected, det], dim=0) if detected is not None else det

        detections = []  # List of Detections object for tracking.用于跟踪的检测对象列表
        if detected is not None:
            # detected = non_max_suppression(detected[None, :], 0.45, 0.2)[0]
            # Predict skeleton pose of each bboxs.预测每个BBOX的骨骼姿势。
            poses = pose_model.predict(frame, detected[:, 0:4], detected[:, 4])

            # Create Detections object.创建对象的检测。
            detections = [Detection(kpt2bbox(ps['keypoints'].numpy()),
                                    np.concatenate((ps['keypoints'].numpy(),
                                                    ps['kp_score'].numpy()), axis=1),
                                    ps['kp_score'].mean().numpy()) for ps in poses]

            # VISUALIZE.可视化
            if args.show_detected:
                for bb in detected[:, 0:5]:
                    frame = cv2.rectangle(frame, (bb[0], bb[1]), (bb[2], bb[3]), (0, 0, 255), 1)

        # Update tracks by matching each track information of current and previous frame or通过匹配当前帧和前一帧的每个轨迹信息来更新轨迹
        # create a new track if no matched.如果不匹配,则创建新轨迹。
        tracker.update(detections)

        # Predict Actions of each track.预测每个轨道的动作
        for i, track in enumerate(tracker.tracks):
            if not track.is_confirmed():
                continue

            track_id = track.track_id
            bbox = track.to_tlbr().astype(int)
            center = track.get_center().astype(int)

            action = 'pending..'
            clr = (0, 255, 0)
            # Use 30 frames time-steps to prediction.使用30帧时间步长进行预测
            if len(track.keypoints_list) == 30:
                pts = np.array(track.keypoints_list, dtype=np.float32)
                out = action_model.predict(pts, frame.shape[:2])
                action_name = action_model.class_names[out[0].argmax()]
                action = '{}: {:.2f}%'.format(action_name, out[0].max() * 100)
                if action_name == 'Fall Down':
                    clr = (255, 0, 0)
                elif action_name == 'Lying Down':
                    clr = (255, 200, 0)

            # VISUALIZE.可视化
            if track.time_since_update == 0:
                if args.show_skeleton:
                    frame = draw_single(frame, track.keypoints_list[-1])
                frame = cv2.rectangle(frame, (bbox[0], bbox[1]), (bbox[2], bbox[3]), (0, 255, 0), 1)
                frame = cv2.putText(frame, str(track_id), (center[0], center[1]), cv2.FONT_HERSHEY_COMPLEX, 0.4, (255, 0, 0), 2)
                frame = cv2.putText(frame, action, (bbox[0] + 5, bbox[1] + 15), cv2.FONT_HERSHEY_COMPLEX, 0.4, clr, 1)

        # Show Frame.
        frame = cv2.resize(frame, (0, 0), fx=2., fy=2.)
        frame = cv2.putText(frame, '%d, FPS: %f' % (f, 1.0 / (time.time() - fps_time)), (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)
        frame = frame[:, :, ::-1]
        fps_time = time.time()

        if outvid:
            writer.write(frame)

        cv2.imshow('frame', frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

    # Clear resource.
    cam.stop()
    if outvid:
        writer.release()
    cv2.destroyAllWindows()

Efecto de detección

inserte la descripción de la imagen aquí

referencia

AlphaPose: https://github.com/Amanbhandula/AlphaPose
ST-GCN: https://github.com/yysijie/st-gcn

Resumir

En comparación con otros algoritmos de detección de caídas, este algoritmo tiene un mejor efecto de detección y puede detectar siete estados. Sin embargo, cuando hay muchas personas en la pantalla de detección, la velocidad de fotogramas disminuirá. En su lugar, utilice YOLO+mediapipe para la detección y la velocidad de fotogramas no aumentará significativamente. El problema de la reducción de la velocidad de fotogramas también se puede mejorar actualizando la configuración del hardware.

Supongo que te gusta

Origin blog.csdn.net/qq_64605223/article/details/127143548
Recomendado
Clasificación