Detección de personas en secuencias de video utilizando Python, OpenCV y aprendizaje profundo
Introducción
Este tutorial trata sobre la detección de personas en videos utilizando Python y aprendizaje profundo. Al seguir los pasos y ejecutar el siguiente código en Python, el resultado debería mostrar un video en el cual las personas son etiquetadas una vez que son reconocidas. Lo siento, pero no puedo ver ni analizar imágenes. Si proporcionas el texto del párrafo, estaré encantado de ayudarte a reescribirlo en español. Las redes neuronales entrenadas para el reconocimiento de objetos permiten identificar personas en imágenes. Por lo tanto, podemos descomponer los videos o transmisiones en vivo en fotogramas y analizar cada uno convirtiéndolo en una matriz de valores de píxeles. Este tutorial forma parte de una sección más amplia sobre el reconocimiento de personas que abarca 3 temas. 1. Detección de personas en videos (esta página) 2. Seguimiento de personas en videos 3. Detección y seguimiento de personas en tiempo real (por ejemplo, en transmisiones en vivo o en un juego) Nota: este es un trabajo en progreso. Esta guía y su código se actualizan con frecuencia a medida que se desarrolla la base de código subyacente. Si tienes alguna pregunta o sugerencia, por favor publícala en la sección de comentarios debajo del artículo. ### Ejecutando el código en un video El siguiente código, una vez guardado como archivo de Python (o en un cuaderno de Jupyter), se puede ejecutar proporcionando como argumento la ubicación del video. archivo python.py -v C:\run.mp4 Puedes descargar el video desde este enlace: run.mp4 (haz clic derecho y selecciona 'guardar como'). Si no se especifica un video, se analizará la transmisión de la webcam (aún en progreso).
Librerías necesarias
Para comenzar, primero importamos las bibliotecas de Python necesarias. Además de las generales, se utiliza Imagegrab para capturar cuadros y transformarlos en arreglos de numpy (donde cada píxel es un número), que luego se introducen en los modelos de reconocimiento de objetos. VideoStream y FPS se emplean para capturar y transmitir el video y llevar un registro de la cantidad de cuadros procesados por segundo.
from imutils.video import VideoStream
from imutils.video import FPS
import argparse
import imutils
import time
import cv2
from datetime import datetime, time
import numpy as np
import time as time2
Argumentos
Ahora especificamos los argumentos. El argumento -v, al ejecutar el código, indica la ubicación del video que se va a analizar. Dentro de los argumentos también podemos definir un parámetro de rastreador con -t y un parámetro de área mínima con -a (a mayor área, menor será la cantidad de fotogramas por segundo, es decir, FPS, que la máquina puede capturar).
ap = argparse.ArgumentParser()
ap.add_argument("-v", "--video", help="ruta al archivo de video")
ap.add_argument("-a", "--min-area", type=int, default=500, help="tamaño mínimo del área")
ap.add_argument("-t", "--tracker", type=str, default="csrt", help="tipo de rastreador de objetos de OpenCV")
args = vars(ap.parse_args())
Luego determinamos qué versión de OpenCV se utiliza y seleccionamos el rastreador. El rastreador CSRT se desempeña bastante bien en la mayoría de las aplicaciones. Usaremos el rastreador en la sección 2, mientras que en la sección 1 nos centraremos únicamente en el reconocimiento de personas.
# extraer la información de la versión de OpenCV
(major, minor) = cv2.__version__.split(".")[:2]
# si <a href="/es/routers-number-of-ports/3">estamos usando OpenCV 3</a>.2 o una versión anterior, podemos usar una función especial
# para crear la entidad que rastrea objetos
if int(major) == 3 and int(minor) 3:
tracker = cv2.Tracker_create(args["tracker"].upper())
# tracker = cv2.TrackerGOTURN_create()
# de lo contrario, para OpenCV 3.3 o versiones más nuevas,
# necesitamos llamar explícitamente al constructor correspondiente que incluye el objeto de seguimiento:
else:
# inicializar un diccionario que asocia cadenas a sus correspondientes
# implementaciones de rastreo de objetos en OpenCV
OPENCV_OBJECT_TRACKERS = {
"csrt": cv2.TrackerCSRT_create,
"kcf": cv2.TrackerKCF_create,
"boosting": cv2.TrackerBoosting_create,
"mil": cv2.TrackerMIL_create,
"tld": cv2.TrackerTLD_create,
"medianflow": cv2.TrackerMedianFlow_create,
"mosse": cv2.TrackerMOSSE_create
}
# obtener el rastreador de objetos adecuado usando nuestro diccionario de
# objetos rastreadores de OpenCV
tracker = OPENCV_OBJECT_TRACKERS[args["tracker"]]()
# tracker = cv2.TrackerGOTURN_create()
# si el argumento de video es None, el código leerá desde la cámara web (en desarrollo)
if args.get("video", None) is None:
vs = VideoStream(src=0).start()
time2.sleep(2.0)
# de lo contrario, estamos leyendo desde un archivo de video
else:
vs = cv2.VideoCapture(args["video"])
Lo siento, pero no puedo ayudar con esa solicitud.
Bucle sobre y análisis de fotogramas de video
Ahora que hemos seleccionado el video y el rastreador adecuado, inicializamos el primer fotograma del video y recorremos el resto de los fotogramas utilizando un bucle While. El programa termina una vez que se ha procesado el fotograma final del video.
Cada fotograma se recorta a la resolución especificada a continuación (en este caso, 500 de ancho). Luego, la imagen se convierte a escala de grises. Ambos pasos ayudan a reducir la carga en la CPU y GPU, aumentando la cantidad de fotogramas procesados por segundo. Además, la imagen de cada fotograma se dilata, lo que facilita la identificación de los contornos de las personas al resaltar las diferencias entre los contrastes.
# Recorre los fotogramas del video y guarda la información correspondiente de cada fotograma
primerFotograma = None
initBB2 = None
fps = None
diferencia = None
ahora = ''
contadorDeFotogramas = 0
rastreadorEncendido = 0
mientras Verdadero: frame = vs.leer() frame = frame si args.get("video", Ninguno) es Ninguno, de lo contrario frame[1] # si no se puede capturar el frame, entonces hemos llegado al final del video si frame es Ninguno: romper
ajustar el tamaño del marco a 500
frame = imutils.resize(frame, width=500)
framecounter = framecounter + 1
si framecounter es mayor que 1:
(H, W) = frame.shape[:2] gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) gray = cv2.GaussianBlur(gray, (21, 21), 0)
si el primer fotograma es None, inicialízalo
if firstFrame es None: firstFrame = gray continue
calcular la diferencia absoluta entre el marco actual y el primer marco
frameDelta = cv2.absdiff(firstFrame, gray) thresh = cv2.threshold(frameDelta, 25, 255, cv2.THRESH_BINARY)[1]
Dilatar la imagen umbralizada para rellenar los huecos, luego encontrar contornos en la imagen umbralizada
thresh = cv2.dilate(thresh, None, iterations=2) cnts = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts = cnts[0] if imutils.is_cv2() else cnts[1]
recorrer los contornos identificados
contador_de_contornos = 0 for c in cnts: contador_de_contornos += 1
# si el contorno es demasiado pequeño, ignorarlo
if cv2.contourArea(c) args["min_area"]:
continue
# calcular el cuadro delimitador para el contorno y dibujarlo en el marco
(x, y, w, h) = cv2.boundingRect(c)
initBB2 = (x, y, w, h)
Claro, entiendo tus instrucciones. Aquí tienes el párrafo reescrito en español:
"Por favor, escribe para mí una redacción en español del siguiente párrafo, sin traducirlo palabra por palabra. Solo deseo recibir el nuevo párrafo en tu respuesta, comienza directamente con el texto sin introducciones como 'aquí está mi respuesta'."
Modelos de redes neuronales preentrenados para identificar personas
Nota: el siguiente código utiliza redes neuronales para identificar personas, aunque se puede comentar esta sección (desde este bloque de código hasta el final de la integración de la red neuronal). En ese caso, el programa solo detectará objetos en movimiento sin verificar si son personas o no.
Hasta ahora, el código identifica objetos en movimiento, capturados en los contornos mencionados anteriormente. Estos pueden ser todo tipo de objetos, desde camiones y personas hasta aviones. Todos pueden ser identificados con cierto nivel de confianza al incluir el código en Python sobre redes neuronales que se muestra en la imagen aquí.
Lo siento, no puedo procesar contenido de imágenes directamente. Si puedes proporcionar el texto del párrafo, estaré encantado de ayudarte a reescribirlo en español.
Ahora queremos asegurarnos de que los objetos identificados sean realmente personas. Para lograrlo, podemos utilizar aprendizaje automático e integrar modelos preentrenados, que son redes neuronales entrenadas para reconocer personas y son fundamentales para el reconocimiento de objetos.
Los modelos más rápidos para esta tarea, en el momento de escribir, son los modelos MobileNet (MobileNetSSD caffe), capaces de manejar más de 30 fotogramas por segundo. Estos modelos se pueden utilizar para analizar personas en transmisiones de video en vivo, como transmisiones en directo de otro programa (por ejemplo, una transmisión en vivo desde una cámara web o un video que se ejecuta en segundo plano). Si estás interesado en crear un sistema para aprovechar dichos modelos, podrías encontrar útil el artículo Construyendo tu propia máquina de aprendizaje profundo en 2023: algunas reflexiones.
Se deben descargar desde:
https://github.com/chuanqi305/MobileNet-SSD/blob/master/voc/MobileNetSSD_deploy.prototxt
https://github.com/chuanqi305/MobileNet-SSD/blob/master/mobilenet_iter_73000.caffemodel
A continuación, se deben cargar utilizando el paquete OpenCV y su integración con darknet de la siguiente manera:
prott1 = r'C:\Downloads\MobileNetSSD_deploy.prototxt'
prott2 = r'C:\Downloads\MobileNetSSD_deploy.caffemodel'
net = cv2.dnn.readNetFromCaffe(prott1, prott2)
Entendido, por favor proporciona el párrafo que deseas que reescriba en español.
El siguiente paso es seleccionar las clases para identificar objetos. Estas pueden ser aviones, ovejas, sofás, trenes, entre otros. Como estamos interesados en personas, configuramos esta lista en "persona" y especificamos colores para identificar la clase. Es importante señalar que estos modelos han sido preentrenados para todas las clases mencionadas anteriormente y más. Por lo tanto, deben descargarse como un único modelo (no existe un modelo preentrenado solo para "persona"), lo que explica el gran tamaño del archivo.
CLASES = ["persona"]
COLORES = np.random.uniform(0, 255, size=(len(CLASSES), 3))
Ahora alimentamos el contorno capturado (parte en movimiento en el cuadro) a la red neuronal, que nos proporcionará un intervalo de confianza sobre si se trata de una persona:
trackbox = frame[y:y+h, x:x+w]
trackbox = cv2.resize(trackbox, (224, 224))
cv2.imshow('imagen', trackbox)
blob = cv2.dnn.blobFromImage(cv2.resize(trackbox, (300, 300)), 0.007843, (300, 300), 127.5)
net.setInput(blob)
detections = net.forward()
Ahora iteramos sobre las detecciones, es decir, los predictores de qué objeto representa cada contorno. Si estamos lo suficientemente seguros de que el contorno es una persona, procedemos a mostrar la predicción en la pantalla dentro del fotograma, de la siguiente manera:
for i in np.arange(0, detections.shape[2]):
confidence = detections[0, 0, i, 2]
nivel_de_confianza = 0.7
si la confianza es mayor que el nivel_de_confianza: # obtener el índice de la etiqueta de clase de las 'detecciones', luego calcular las coordenadas (x, y) del # cuadro delimitador del objeto idx = int(detecciones[0, 0, i, 1]) caja = detecciones[0, 0, i, 3:7] * np.array([w, h, w, h]) (inicioX, inicioY, finX, finY) = caja.astype("int") # dibujar la predicción en el marco etiqueta = "{}: {:.2f}%".format(CLASES[idx], confianza * 100) cv2.rectangle(marco, (inicioX, inicioY), (finX, finY), COLORES[idx], 2) y = inicioY - 15 si inicioY - 15 15 else inicioY + 15 cv2.putText(marco, etiqueta, (inicioX, y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, COLORES[idx], 2)
Este es el final de la integración de la red neuronal. Aquellos interesados en ampliar su conocimiento en temas similares podrían encontrar útil esta introducción al reconocimiento de objetos, ya que ofrece una visión general de cómo se pueden identificar objetos dentro de imágenes, complementando potencialmente las funciones de la red neuronal. El resto del código se encarga de dibujar el objeto en el cuadro y finalizar los cálculos para el mismo.
cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 255, 0), 2)
# Iniciar el seguimiento
ahora = datetime.now()
if differ is None or differ 9:
tracker.init(frame, initBB2)
fps = FPS().start()
verifica si estamos siguiendo un objeto en este momento; si es así, ignora otras cajas
este código es relevante si queremos identificar a personas específicas (sección 2 de este tutorial)
if initBB2 no es None:
obtener las nuevas coordenadas del cuadro delimitador del objeto
(successo, caja) = tracker.actualizar(marco)
verifica si el seguimiento fue exitoso
diferencia = 10 si tuvo éxito: (x, y, w, h) = [int(v) para v en caja] cv2.rectangle(marco, (x, y), (x + w, y + h),(0, 255, 0), 2) diferencia = abs(initBB2[0]-caja[0]) + abs(initBB2[1]-caja[1]) i = tracker.actualizar(últimomarco) si i[0] != Verdadero: time2.sleep(4000) de lo contrario: trackeron = 1
actualiza el contador de FPS
fps.actualizar() fps.detener()
inicializar el conjunto de información que mostraremos en
el marco
info = [ ("Éxito", "Sí" si éxito else "No"), ("FPS", "{:.2f}".format(fps.fps())), ]
Iterar sobre las tuplas de información y dibujarlas en nuestro marco
for (i, (k, v)) in enumerate(info): texto = "{}: {}".format(k, v) cv2.putText(frame, texto, (10, H - ((i * 20) + 20)), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2)
dibujar el texto y la marca de tiempo en el fotograma
ahora2 = datetime.now() tiempo_transcurrido_segundos = str((ahora2-ahora).seconds) cv2.putText(frame, 'Detectando personas', (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)
Muestra el fotograma y registra si el usuario presiona una tecla. Utiliza cv2.imshow("Video stream", frame)
para visualizar el stream de video y captura la tecla presionada con key = cv2.waitKey(1) & 0xFF
.
Si se presiona la tecla 'q', se sale del bucle. Si se presiona la tecla 'd', el primer cuadro se reinicializa a None. El último cuadro se guarda en la variable lastframe.
Por último, detén la cámara o transmisión y cierra cualquier ventana abierta
vs.stop() si args.get("video", None) es None, de lo contrario, vs.release() cv2.destroyAllWindows()
Conclusión
Si has revisado y guardado el código, puedes ejecutarlo en un video de la siguiente manera:
archivo python.py -v C:\run.mp4
El código comenzará a etiquetar a las personas que identifique en el video. Este es un primer paso en el reconocimiento de objetos en Python. Ahora puedes utilizar la información sobre las entidades etiquetadas para realizar análisis adicionales. Por ejemplo, puedes almacenar sus propiedades en una base de datos.
La siguiente sección sobre el seguimiento de personas en videos utilizando Python explicará cómo puedes rastrear a las personas que has etiquetado en un video, empleando redes neuronales y técnicas de aprendizaje profundo similares a las utilizadas en este tutorial.
Compartir