Introducción al seguimiento de objetos mediante OpenCV

Contenidos

Este artículo fue publicado como parte del Blogatón de ciencia de datos

Introducción

OpenCV es una gran herramienta para jugar con imágenes y videos. O desea darle a sus fotos un aspecto en blanco y negro de los 90 o realizar operaciones matemáticas complejas, OpenCV siempre está listo para servir. Si le gusta la visión por computadora, es imprescindible tener conocimientos de OpenCV. La biblioteca incluye más de 2500 algoritmos optimizados que se pueden utilizar para realizar una amplia variedad de tareas. Es utilizado por muchos de los gigantes de la industria como Google, Microsoft, IBM y se usa ampliamente en grupos de investigación. La biblioteca admite varios idiomas, incluidos java, c ++ y python.

Este artículo le mostrará cómo realizar la compleja tarea del seguimiento de objetos utilizando algunas de las funciones básicas de OpenCV.

Puede considerar un ejemplo de un partido de fútbol. Tienes una transmisión en vivo del partido y tu tarea es rastrear la posición de la pelota en cada momento. La tarea parece simple para un humano promedio, pero es demasiado compleja incluso para la máquina más inteligente. Como sabrá, las computadoras solo entienden números. No comprende qué es una imagen, sino los valores de píxeles asociados con la imagen. Dos imágenes que parecen ser exactamente iguales para el ojo humano pueden no ser el mismo caso para su computadora, ya que incluso un pequeño cambio en un píxel resultará en una diferencia. Por eso, el seguimiento de objetos se considera una de las tareas más complejas de la visión por computadora. Aunque complejo, no es algo inalcanzable.

El seguimiento de objetos se puede realizar mediante el aprendizaje automático y también con enfoques basados ​​en el aprendizaje profundo. El enfoque de aprendizaje profundo por un lado proporciona mejores resultados en tareas complejas y es bastante generalizado, requiere muchos datos de entrenamiento. Mientras que los enfoques basados ​​en ML son bastante sencillos pero no generalizados. Para este artículo, estamos usando un enfoque basado en ML junto con varias técnicas de visión por computadora que discutiremos más adelante en este artículo.

La técnica se usa ampliamente en vigilancia, seguridad, monitoreo de tráfico, visión de robot, comunicación por video y mucho más. Además, el seguimiento de objetos tiene varios casos de uso, como conteo de multitudes, vehículos autónomos, detección de rostros, etc. ¿Puede pensar en algunos ejemplos más en los que pueda utilizar el seguimiento de objetos en su vida diaria?

Debido a tantas aplicaciones de la vida real, se está realizando una investigación constante en este campo para lograr una mayor precisión y hacer que el modelo sea más robusto.

Para este artículo, usaremos este video. Como verá, hay una bola de color rojo que se mueve a través de un laberinto y nuestra tarea es detectar la ubicación de la bola y encontrar su centroide. También podría ver un gran ruido (lo siento gente), de fondo, para hacer la tarea un poco más desafiante.

22521screenshot2025-6154785

1.

En primer lugar, importamos las bibliotecas necesarias que se utilizarán.

import numpy as np
import cv2

2.

Estaremos definiendo una función que redimensionará las imágenes para que quepan en nuestra pantalla en caso de que sean lo suficientemente grandes. Este paso es completamente opcional y puede omitirlo.

def resize(img):
        return cv2.resize(img,(512,512)) # arg1- input image, arg- output_width, output_height

3.

Como sabrá, los videos están hechos de marcos. Los fotogramas no son más que una de las muchas imágenes fijas que juntas forman la imagen en movimiento completa. El siguiente paso será leer esos cuadros usando la función VideoCapture () en OpenCV y usando el bucle while, podemos ver los cuadros moviéndose. Puede ajustar la velocidad del video usando cv2.waitKey (x) que pausa la pantalla durante x milisegundos.

cap=cv2.VideoCapture(vid_file_path)
ret,frame=cap.read()

while ret==True:
    ret,frame=cap.read()
    cv2.imshow("frame",resize(frame))
    key=cv2.waitKey(1)
    if key==ord('q'):
        break
cv2.waitKey(0)
cv2.destroyAllWindows()

4.

OpenCV lee imágenes en formato BGR, por lo que convertiremos el espacio de color de BGR a HSV. ¿Por qué HSV y no BGR o cualquier otro formato?

Estamos usando el formato de color HSV porque es más sensible a cambios menores en la iluminación externa. Por lo tanto, dará máscaras más precisas y, por lo tanto, mejores resultados.

Después de convertir el espacio de color, lo que tenemos que hacer es filtrar el canal rojo y crear un marco de máscara.

El canal rojo en formato hsv está presente en [0,230,170] para [255,255,220] distancia.

cap=cv2.VideoCapture(vid_file_path)


ret,frame=cap.read()
l_b=np.array([0,230,170])# lower hsv bound for red
u_b=np.array([255,255,220])# upper hsv bound to red

while ret==True:
    ret,frame=cap.read()

    hsv=cv2.cvtColor(frame,cv2.COLOR_BGR2HSV)
    mask=cv2.inRange(hsv,l_b,u_b)

    cv2.imshow("frame",resize(frame))

    cv2.imshow("mask",mask)


    key=cv2.waitKey(1)
    if key==ord('q'):
        break
cv2.waitKey(0)
cv2.destroyAllWindows()
68572masked-4189669

(Esta imagen ha sido redimensionada)

5.

Hasta ahora, hemos creado la imagen enmascarada del marco y hemos filtrado la mayor parte del ruido. Lo que sigue es conseguir los límites de la pelota. Para ello utilizaremos el concepto de detección de contornos. Los contornos no son más que límites que rodearán nuestra pelota. Afortunadamente, no tenemos que encontrar esos límites por nuestra cuenta, ya que OpenCV permite una función findContours () que podemos usar para nuestro propósito. Toma una imagen enmascarada y devuelve una matriz de contornos. Para obtener más información sobre los contornos, visite me. Idealmente, en nuestro caso, el valor de los contornos debería ser uno, ya que solo tenemos una bola, pero debido a que algunas personas usaban sombreros rojos, obtendremos más de una. ¿Puedes pensar en algo para reducir aún más este ruido?

Para manejar este problema usaremos otra función de OpenCV que es cv2.contourArea (). Sabemos en la imagen enmascarada, la pelota tiene el área más grande y también lo será su contorno. Por lo tanto, obtendremos el contorno con el área más grande.

Tenemos los contornos de la bola y podemos dibujar directamente estos contornos usando la función cv2.drawContours (). Pero para las tareas de detección, lo que generalmente hacemos es usar un rectángulo bien delimitado para mostrar que el objeto ha sido detectado. Para hacerlo, usaremos la función cv2.boundingRect (). Esta función devolverá las coordenadas del rectángulo y luego la función cv2.rectangle () dibujará el rectángulo para nosotros.

cap=cv2.VideoCapture(vid_file_path)


ret,frame=cap.read()
l_b=np.array([0,230,170])# lower hsv bound for red
u_b=np.array([255,255,220])# upper hsv bound to red

while ret==True:
    ret,frame=cap.read()

    hsv=cv2.cvtColor(frame,cv2.COLOR_BGR2HSV)
    mask=cv2.inRange(hsv,l_b,u_b)

    contours,_= cv2.findContours(mask,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

    max_contour = contours[0]
         for contour in contours:
                if cv2.contourArea(contour)>cv2.contourArea(max_contour):

                      max_contour=contour

         contour=max_contour
         approx=cv2.approxPolyDP(contour, 0.01*cv2.arcLength(contour,True),True)
         x,y,w,h=cv2.boundingRect(approx)
         cv2.rectangle(frame,(x,y),(x+w,y+h),(0,255,0),4)

    cv2.imshow("frame",resize(frame))

    cv2.imshow("mask",mask)
528745-3351114

(Esta imagen ha sido redimensionada)

6.

Además, lo que podemos hacer es detectar el centroide de la pelota simultáneamente. Para eso, usaremos cv2.moments. cv2.moments calcula la suma promedio ponderada de las intensidades de píxeles dentro del contorno y, por lo tanto, permite obtener información más útil del blob, como su radio, centroide, etc. Asegúrese de convertir la imagen a formato binario antes de usar la función. Puedes saber más sobre momentos aquí.

cap=cv2.VideoCapture(vid_file_path)


ret,frame=cap.read()
l_b=np.array([0,230,170])# lower hsv bound for red
u_b=np.array([255,255,220])# upper hsv bound to red

while ret==True:
    ret,frame=cap.read()

    hsv=cv2.cvtColor(frame,cv2.COLOR_BGR2HSV)
    mask=cv2.inRange(hsv,l_b,u_b)

    contours,_= cv2.findContours(mask,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

    max_contour = contours[0]
         for contour in contours:


                if cv2.contourArea(contour)>cv2.contourArea(max_contour):

                  max_contour = contour

         approx=cv2.approxPolyDP(contour, 0.01*cv2.arcLength(contour,True),True)
         x,y,w,h=cv2.boundingRect(approx)
         cv2.rectangle(frame,(x,y),(x+w,y+h),(0,255,0),4)

         M=cv2.moments(contour)

cx = int (M[‘m10’]//METRO[‘m00’])
cy = int (M[‘m01’]//METRO[‘m00’])
cv2.circle (marco, (cx, cy), 3, (255,0,0), – 1)


    cv2.imshow("frame",resize(frame))

    cv2.imshow("mask",mask)

    key=cv2.waitKey(1)
    if key==ord('q'):
        break
cv2.waitKey(0)
cv2.destroyAllWindows()
200486-8346694

(Esta imagen ha sido redimensionada)

A dónde ir desde aquí

En este artículo, hemos utilizado la detección de objetos en cada fotograma para la tarea de seguimiento de objetos. Aunque es útil, puede que no funcione bien en todos los casos. Mientras leía el artículo, es posible que varias preguntas hayan golpeado su cerebro. ¿Qué pasa si hay más de un objeto en el video? ¿Qué pasa si las imágenes de la máscara no ayudan a detectar el objeto? ¿Qué pasa si el objeto se mueve constantemente dentro y fuera del marco? ¿Qué pasa si no hay ningún objeto?

La única forma de encontrarlos es probándolos por su cuenta. Siempre puedes modificar las entradas y hacer que la tarea sea un poco más desafiante hasta que deje de divertirte.

Los medios que se muestran en este artículo no son propiedad de DataPeaker y se utilizan a discreción del autor.

Suscribite a nuestro Newsletter

No te enviaremos correo SPAM. Lo odiamos tanto como tú.