Estimación de pose humana + Modelo caffe MPI

Estimación de pose humana + Modelo caffe MPI

Estimación de postura humana:

La estimación de la postura o articulaciones del movimiento del hombre ha venido ganando forma en los últimos años, ya que su aplicabilidad se puede dar en muchos ámbitos del que hacer cotidiano. Su fundamento es similar a la detección de puntos faciales o puntos de referencia (landmarks point) en donde un modelo previamente entrenado que se basa en el aprendizaje profundo o deep learning permite encontrar los hitos faciales del rostro. En este caso el modelo permite detectar puntos de referencia de las articulaciones del cuerpo humano, llamados también como puntos clave, por ejemplo: hombros, codos, muñecas, rodillas, tobillos, entre otros; de tal suerte que al unificar dichos puntos nos mostrará una imagen parecido a un hombre de palo o stickman. Para dicho efecto, este modelo pre entrenado se puede ejecutar desde OpenCV (Visión artificial de código abierto).

Figura 1. Puntos de referencia de articulaciones usando modelo pre entrenado Caffe

El modelo al que hacemos atribución es el llamado  modelo Caffe, entrenado en el framework del mismo nombre. Sabemos que en lo que concierne al aprendizaje profundo existen varios modelos, sin embargo caffe apareció como una de las primeras herramientas para Deep Learning. Observamos en la Figura 1. que el modelo ha detectado 15 puntos de las articulaciones del cuerpo para los que fue pre entrenado, sin embargo podría no ser siempre así, tal vez por ciertos ciertos factores, como por ejemplo la calidad , dimensión y profundidad de la imagen. 

Resulta necesario atribuir la arquitectura del modelo que fue propuesto en un artículo de investigadores del laboratorio de Computación Perceptual de la Universidad de Carnegie Mellon – Australia, en donde se entrenan redes neuronales profundas, la arquitectura de esta red la mostramos en la Figura 2. Además resulta pertinente mencionar que el framework o herramienta de trabajo caffe fue desarrollado  originalmente en la Universidad de Berkeley con características Open Source, usada específicamente para entrenar modelos en Redes Neuronales Convolucionales (CNN), su código fuente esta desarrollado en C++, para interfaces de su mismo lenguaje, Python y Matlab. Los modelos que se crean en caffe generan un archivo con extensión prototxt (nombremodelo.prototxt) y los pesos (weight) del modelo entrenado originan la extensión caffemodel (numeroiteración.caffemodel). Con la técnica de caffe llamada transfer learning pueden tomar modelos ya entrenados para aminorar los tiempos de entrenamiento y mejorar su precision.

Figura 2. Arquitectura VGG-19 de la estructura de Red Neuronal Convolucional (CNN) - Extraído de https://learnopencv.com/

La arquitectura del modelo lo podemos ver como un sistema en donde la entrada es una imagen de dimensiones w x h y la salida es la misma imagen pero con los puntos establecidos en las articulaciones del cuerpo, tal como se aprecia en la Figura 1. Técnica mente se le conoce como puntos clave 2D por tratarse de dos dimensiones y que básicamente son coordenadas medidas en pixeles. Bien, ahora explicaremos muy escuetamente el proceso interno que consta de 3 etapas.

  1. Etapa 0: Las 10 primeras capas de la estructura de red VGG (Visual Geometry Group) conocido como VGG-19, son usadas para crear mapas de características de la imagen de entrada.
  2. Etapa 1 (Stage1) : Se utiliza una CNN multietapa de 2 ramas (Branch 1 y Branch 2), la primera rama predice un conjunto de mapas de confianza 2D (S) de las ubicaciones las partes del cuerpo, por ejemplo las rodillas, codos, muñecas. En la Figura 3. se visualiza el mapa de confianza de la zona del hombro izquierdo de las personas. La segunda rama predice un conjunto de campos vectoriales 2D (L) de afinidades que asocian partes contiguas del cuerpo, por ejemplo la parte del hombro izquierdo con el cuello, como se aprecia en la Figura 4. 
  3. Etapa 2: Los mapas de confianza y afinidad son analizados cuidadosamente con complejas fórmulas inferenciales.
Figura 3. Mapa de confianza para el hombro izquierdo - Extraído de https://learnopencv.com/
Figura 4. Mapa de afinidad del hombro izquierdo al cuello - Extraído de https://learnopencv.com/

Definiremos a continuación los procedimientos para obtener la unión de los puntos establecidos como articulaciones, de tal suerte que pueda mostrarse como un esqueleto articulado o stickman.

Procedimiento 1: Cargar los pesos del modelo (entrenados en Caffe Deep Learning Framework) que comprenden dos archivos: nombremodelo.prototxt y numeroiteracion.caffemodel. El primero señala la arquitectura de la red neuronal y el segundo almacena los pesos del modelo. Estos archivos cargarán la red en la memoria del procesador, cuyo valor se asigna en los argumentos del método readNetFromCaffe.

#Indicamos la ruta de los dos archivos
protoFile = "pose/mpi/pose_deploy_linevec_faster_4_stages.prototxt"
weightsFile = "pose/mpi/ pose_iter_160000.caffemodel"
net = cv2.dnn.readNetFromCaffe(protoFile, weightsFile)

Procedimiento 2: Leemos la imagen para convertirlo en una entrada tipo blob que alimentará a la red, para ello invocaremos al método (función) blobFromImage que básicamente convierte el formato de la imagen de entrada de OpenCV al formato  Caffe blob. El tipo de datos que usualmente usa caffe es lmdb o leveldb no es común los formatos jpg, jpeg, tif, png y otros.

#Leemos la imagen
frame = cv2.imread("mi_imagen.jpg")
inWidth = 368
inHeight = 368
inpBlob = cv2.dnn.blobFromImage(frame, 1.0 / 255,
  (inWidth, inHeight), (0, 0, 0),swapRB=False, crop=False)
net.setInput(inpBlob)

Procedimiento 3: Una vez que la imagen se pasa al modelo, se realiza las inferencias de los mapas (confianza y afinidad), por tanto, las predicciones de los puntos clave. Para este efecto se usa una sola línea de código. El método para la clase  DNN en OpenCV hace un pase de reenvío a través de la red neuronal.

output = net.forward()

La salida (output) genera cuatro valores (matriz 4D): Primero, el ID de la imagen ( en caso de procesarse más de una). Segundo,  el índice del punto clave; sabemos que el modelo produce mapas de confianza y mapas de afinidad, estos valores probabilísticos son muchos, por tanto el modelo los concatena. El modelo MPI genera 15 puntos claves de las diferentes partes del cuerpo a diferencia del modelo COCO que genera 18, nosotros estamos usando el primer modelo. Los dos últimos valores corresponden al alto y ancho de la imagen.

En lo que concierne al segundo valor de salida del modelo MPI podemos apreciar en el reporte obtenido  desde nuestra shell o comando prompt (CMD), que generan los (15) puntos clave que va desde el 0 al 14, el mapa de confianza y afinidad en forma de matriz, la probabilidad de acercamiento a dicho punto clave y la posición en la imagen. Por ejemplo en el punto clave 0, la probabilidad de acercamiento es óptima con un valor de  0.826616 y  la posición del punto (point) es (24,8). Esta posición se escala para que se muestre la posición del punto clave en la imagen original, con la siguiente fórmula:

 

Por lo tanto, el valor de nuestro punto clave (0) es (24,8) que se escala a la coordenada (307,136) y así sucesivamente hasta completar el punto clave (14). Las líneas de código siguientes hacen posible esto, cuya ejecución se visualiza en la Figura 5. 

H = out.shape[2]

W = out.shape[3]

points = []
for i in range(len()):
    probMap = output[0, i, :, :]
    minVal, prob, minLoc, point = cv2.minMaxLoc(probMap)
    x = (frameWidth * point[0]) / W
    y = (frameHeight * point[1]) / H
    if prob > threshold :
       cv2.circle(frame, (int(x), int(y)), 15, (0, 255, 255),
         thickness=-1, lineType=cv.FILLED)
       cv2.putText(frame, "{}".format(i), (int(x), int(y)),
         cv2.FONT_HERSHEY_SIMPLEX, 1.4, (0, 0, 255), 3, lineType=cv2.LINE_AA)
       points.append((int(x), int(y)))
    else :
        points.append(None)
cv2.imshow("Output-Keypoints",frame)
cv2.waitKey(0)
cv2.destroyAllWindows()

Figura 5. Numeración de los puntos clave del cuerpo

Para visualizar el hombre de palo o «stickman» hay que unir los puntos claves numerados del 0 al 14, usando la siguiente líneas de código. El resultado se aprecia en la Figura 6.

for pair in POSE_PAIRS:
    partA = pair[0]
    partB = pair[1]
    if points[partA] and points[partB]:
        cv2.line(frameCopy, points[partA], points[partB], (0, 255, 0), 3)

 

Figura 6. Unión de los puntos clave llamado también "Stickman"

Gran parte del contenido ha sido extraído de una publicación de la siguiente dirección electrónica https://learnopencv.com/. Asimismo, el código para Python y C++ lo pueden descargar en dicha página web. Sin embargo hemos añadido algunos detalles  considerado necesario para una mejor comprensión.

Esperando como siempre haya sido de su interés, no olviden dejar sus comentarios y compartirlo, de esta forma seguiremos contribuyendo en la capitalización del conocimiento. 

Deja una respuesta