Blog
Objetivo del Tutorial 7º del Curso de Python Avanzado con Dlib & OpenCV
-Aquí veremos un ejemplo de como se pueden seguir objetos en Python
-Igualmente, te dejamos el código con un ejemplo y los requisitos para correrlo.
Seguimiento de Objetos en Python
Aquí puedes ver el ejemplo en un vídeo:
Requisitos para correr el algoritmo
- cv2 (librería openCV)
- dlib (Un juego de herramientas para hacer aplicaciones de learning machine y análisis de datos para el mundo real)
- numpy
- Un vídeo donde aparezca algun objeto que quieras hacer el seguimiento
Código de Seguimiento de Objetos en Python
Archivo: objeto-seguimiento.py
import dlib import cv2 import argparse as ap import get_points def run(source=0, dispLoc=False): # Crea la captura del video cam = cv2.VideoCapture(source) # Si la camra no se abre cierra el programa if not cam.isOpened(): print ("El video no puede ser abierto") exit() print ("Pulsa la tecla 'p' para pausar el video y empezar el seguimiento") while True: # Recupera una imagen y visualízala. retval, img = cam.read() if not retval: print ("No se puede capturar el dispositivo de marco") exit() if(cv2.waitKey(10)==ord('p')): break cv2.namedWindow("Image", cv2.WINDOW_NORMAL) cv2.imshow("Image", img) cv2.destroyWindow("Image") # Las coordenadas de los objetos a rastrear # se almacenarán en una lista llamada `puntos` points = get_points.run(img) if not points: print ("ERROR: No objeto para seguimiento.") exit() cv2.namedWindow("Image", cv2.WINDOW_NORMAL) cv2.imshow("Image", img) #Coordenadas iniciales del objeto a rastrear. # Crear el objeto de seguimiento tracker = dlib.correlation_tracker() # Proporcionar al rastreador la posición inicial del objeto. tracker.start_track(img, dlib.rectangle(*points[0])) while True: # Se lee la imagen desde el aparato o archivo retval, img = cam.read() if not retval: print ("Cannot capture frame device | CODE TERMINATING :(") exit() # Actualizacion del seguimiento tracker.update(img) # Se obtiene la posición del objeto, se dibujar un # cuadro de límite alrededor de él y lo muestra. rect = tracker.get_position() pt1 = (int(rect.left()), int(rect.top())) pt2 = (int(rect.right()), int(rect.bottom())) cv2.rectangle(img, pt1, pt2, (255, 255, 255), 3) print ("Object tracked at [{}, {}] \r".format(pt1, pt2),) if dispLoc: loc = (int(rect.left()), int(rect.top()-20)) txt = "Object tracked at [{}, {}]".format(pt1, pt2) cv2.putText(img, txt, loc , cv2.FONT_HERSHEY_SIMPLEX, .5, (255,255,255), 1) cv2.namedWindow("Image", cv2.WINDOW_NORMAL) cv2.imshow("Image", img) # Continua hasta que se pulsa Escape if cv2.waitKey(1) == 27: break # se lanza la video captura cam.release() if __name__ == "__main__": # Analizar argumentos de línea de comando parser = ap.ArgumentParser() group = parser.add_mutually_exclusive_group(required=True) group.add_argument('-d', "--deviceID", help="Device ID") group.add_argument('-v', "--videoFile", help="Path to Video File") parser.add_argument('-l', "--dispLoc", dest="dispLoc", action="store_true") args = vars(parser.parse_args()) # se Obtiene la fuente del video if args["videoFile"]: source = args["videoFile"] else: source = int(args["deviceID"]) run(source, args["dispLoc"])
Archivo: get-points.py
# Se importan los modulos requeridos import cv2 import argparse def run(im, multi=False): im_disp = im.copy() im_draw = im.copy() window_name = "Selecciona el objeto para hacerle seguimiento." cv2.namedWindow(window_name, cv2.WINDOW_NORMAL) cv2.imshow(window_name, im_draw) # Lista que contiene la parte superior izquierda y la parte inferior derecha para recortar la imagen. pts_1 = [] pts_2 = [] rects = [] run.mouse_down = False def callback(event, x, y, flags, param): if event == cv2.EVENT_LBUTTONDOWN: run.mouse_down = True pts_1.append((x, y)) elif event == cv2.EVENT_LBUTTONUP and run.mouse_down == True: run.mouse_down = False pts_2.append((x, y)) print ("Objecto seleccionado a[{}, {}]".format(pts_1[-1], pts_2[-1])) elif event == cv2.EVENT_MOUSEMOVE and run.mouse_down == True: im_draw = im.copy() cv2.rectangle(im_draw, pts_1[-1], (x, y), (255,255,255), 3) cv2.imshow(window_name, im_draw) print ("Presione y suelte el mouse alrededor del objeto a ser rastreado.") cv2.setMouseCallback(window_name, callback) print ("Presione la tecla 'p' para continuar con los puntos seleccionados ") print ("Presione la tecla 'd' para descartar el último objeto seleccionado. ") print ("Presione la tecla 'q' para salir del programa ") while True: # dibuja el rectangulo en la imagen window_name_2 = "Objects to be tracked." for pt1, pt2 in zip(pts_1, pts_2): rects.append([pt1[0],pt2[0], pt1[1], pt2[1]]) cv2.rectangle(im_disp, pt1, pt2, (255, 255, 255), 3) #muestra las imagenes cortadas cv2.namedWindow(window_name_2, cv2.WINDOW_NORMAL) cv2.imshow(window_name_2, im_disp) key = cv2.waitKey(30) if key == ord('p'): # Presiona 's' para volvel a seleccionar los puntos cv2.destroyAllWindows() point= [(tl + br) for tl, br in zip(pts_1, pts_2)] corrected_point=check_point(point) return corrected_point elif key == ord('q'): # Presiona 'q' para salir del programa print ("Eliminando sin guardar.") exit() elif key == ord('d'): # Presionna 'd' para borrar y cambiar el rectangulo de seguimiento if run.mouse_down == False and pts_1: print ("Objecto borrado en [{}, {}]".format(pts_1[-1], pts_2[-1])) pts_1.pop() pts_2.pop() im_disp = im.copy() else: print ("No objecto para borrar.") cv2.destroyAllWindows() point= [(tl + br) for tl, br in zip(pts_1, pts_2)] corrected_point=check_point(point) return corrected_point def check_point(points): out=[] for point in points: #para encontrar min y max de las coordenadas en x if point[0]<point[2]: minx=point[0] maxx=point[2] else: minx=point[2] maxx=point[0] #para encontrar min y max de las coordenadas en y if point[1]<point[3]: miny=point[1] maxy=point[3] else: miny=point[3] maxy=point[1] out.append((minx,miny,maxx,maxy)) return out if __name__ == "__main__": ap = argparse.ArgumentParser() ap.add_argument("-i", "--imagepath", required=True, help="Path to image") args = vars(ap.parse_args()) try: im = cv2.imread(args["imagepath"]) except: print ("no puede leer la imagen.") exit() points = run(im) print ("La region rectangular selecionada es -> ", points)
El código se compone de:
- El archivo seguimiento-objeto.py se compone de:
- Función run donde se crea la captura de vídeo y se hace un while para mostrar el seguimiento del objeto con opencv
- Después se llama a la función get_points donde se crea la lista de puntos de la ventana que vamos a recortar para decirle que objeto queremos seguir, también se manejan las opciones de salir del código o rehacer el cuadro de seguimiento.
- Una vez se tiene el cuadro del objeto vamos a usar la librería dlib crear el objeto de seguimiento o tracker (tracker = dlib.correlation_tracker()) y le proporcionamos al rastreador la posición inicial del objeto (tracker.start_track(img, dlib.rectangle(*points[0])))
- Por último hacemos otro while donde leemos de nuevo la imagen y ploteamos el cuadro de seguimiento.
- En la última parte del código se manejan diferentes opciones de lectura del vídeo:
- Vídeo desde un archivo, ejecutamos desde el cmd –>
- python objeto-seguimiento.py -v nombre-del-video
- Vídeo a tiempo real (para ello necesitas una cámara) ejecutamos desde el cmd –>
- python objeto-seguimiento.py -d id-de-la-camara
- Vídeo desde un archivo, ejecutamos desde el cmd –>
¿Como usar el código?
Una vez que el código comience, comenzará el archivo de video o la transmisión en vivo. Para seleccionar los objetos a rastrear, haga una pausa en el video presionando la tecla p. El siguiente paso es crear un cuadro delimitador alrededor de los objetos a los que se va a rastrear. Presione el mouse para seleccionar la ubicación de píxel superior izquierdo del objeto que se va a rastrear y luego suelte el mouse en la ubicación de abajo a la derecha del objeto que se va a rastrear. Una vez hecho esto, presione p para iniciar el seguimiento. Además, si desea descartar el objeto, presione la tecla d.
➡ Si has llegado hasta aquí enhorabuena. Continúa aprendiendo con nosotros en nuestro curso de Dlib y OpenCV
Autor:Rafael Fernandez
Empezé estudiando Física aunque mas tarde me decanté por la Ingeniería. Después de hacer un master de Hidráulica (esp. Aero-hidrodinámica de Vehículos) comenzé el PhD en Ingeniería. Hoy en día me encuentro trabajando para la empresa ITK Engineering AG como ingeniero de desarrollo. Entre mi pasiones está el desarrollo e implementación de todo tipo de códigos en Python y otros lenguages.
Puedes visitar mi perfil en <a href="https://www.linkedin.com/in/rafaelfernandezperfil/">Linkedin.<a>