Seguimiento de OpenCV

Salman Mehmood 15 febrero 2024
Seguimiento de OpenCV

Esta demostración tiene como objetivo aprender a crear un sistema de detección y seguimiento de movimiento muy básico y simple utilizando Python y OpenCV. Logramos rastrear a cada persona con un cuadro delimitador rectangular al final de este artículo.

Cree un sistema de seguimiento y detección de movimiento usando Python y OpenCV

Primero, necesitamos leer dos cuadros de la instancia CAP.

ret, F1 = CAP.read()

Del mismo modo, vamos a leer el segundo cuadro.

ret, F2 = CAP.read()

Ahora declararemos una variable llamada DF y usaremos la función absdiff(). El absdiff() ayuda a encontrar la diferencia absoluta entre fotogramas, el primero F1 y el segundo F2.

while CAP.isOpened():
    if ret == False:
        print(ret)
        break
    DF = cv2.absdiff(F1, F2)

Convierta esta diferencia en un modo de escala de grises utilizando el método cvtColor(). El primer parámetro será DF.

El segundo argumento será COLOR_BGR2GRAY, que ayudará a convertir el color del marco BGR al modo de escala de grises; ¿Por qué estamos descubriendo el modo de escala de grises?

Debido a que encontraremos el contorno en las etapas posteriores, es más fácil encontrar los contornos en el modo de escala de grises que en el modo de color.

Gray_Scale = cv2.cvtColor(DF, cv2.COLOR_BGR2GRAY)

Una vez que tengamos el modo de escala de grises, debemos desenfocar nuestro marco de escala de grises usando el método GaussianBlur(). Toma algunos parámetros; el primero es Gray_Scale, el segundo parámetro será el tamaño del kernel 5x5, y el tercer parámetro será el valor Sigma X.

BL = cv2.GaussianBlur(Gray_Scale, (5, 5), 0)

Necesitamos determinar el umbral usando el método threshold(). Devuelve dos objetos; definimos _ porque no necesitamos la primera variable y luego la segunda variable será thresh.

En el primer parámetro, pasaremos nuestra imagen borrosa como fuente, y luego el segundo parámetro será el valor de umbral de 20. El valor de umbral máximo será 255; el tipo será THRESH_BINARY.

_, thresh = cv2.threshold(BL, 20, 255, cv2.THRESH_BINARY)

Necesitamos dilatar la imagen con umbral para llenar todos los agujeros; esto nos ayudará a encontrar mejores contornos. El método dilate() toma algunos parámetros; el primer parámetro será el umbral definido, y el segundo parámetro será el tamaño del núcleo, pero lo estamos pasando None.

El tercer argumento es el número de iteraciones como 3. Si no funciona, puede aumentar o disminuir el número de iteraciones.

DL = cv2.dilate(thresh, None, iterations=3)

En el siguiente paso, encontraremos el contorno, y el método findContours() nos da dos resultados; uno son los contornos y el otro es la jerarquía, pero no vamos a usar el segundo resultado. Vamos a buscar los contornos sobre la imagen dilatada.

Así que estamos pasando imagen dilatada en el primer parámetro, y el siguiente será el modo RETR_TREE que es el más utilizado. El siguiente parámetro será el método CHAIN_APPROX_SIMPLE.

CTS, _ = cv2.findContours(DL, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

En el siguiente paso, queremos dibujar los rectángulos, por lo que iteraremos sobre todos los contornos usando el bucle for. El CTS es una lista, y estamos iterando sobre esta lista, por lo que el primer paso será guardar todas las coordenadas de los contornos usando el método boundingRect().

En el próximo paso, encontraremos el área del contorno, y si esta área es menor que cierto valor, no dibujaremos un rectángulo. Dentro del bucle for, definiremos que si el área del contorno es menor de 700, continuaremos la iteración; de lo contrario, dibuje el rectángulo.

Para dibujar el rectángulo, necesitamos usar el método cv2.rectangle(), y el primer argumento aquí será la fuente que será F1; el segundo parámetro será el punto 1 (x,y). El tercer parámetro será el punto 2, el siguiente parámetro será una tupla como valor de color y el siguiente parámetro será el grosor.

for CT in CTS:
    (x, y, w, h) = cv2.boundingRect(CT)

    if cv2.contourArea(CT) < 900:
        continue
    cv2.rectangle(F1, (x, y), (x + w, y + h), (0, 255, 0), 2)

Colocaremos algún texto en la imagen si se observa algún movimiento. Usaremos el método cv2.putText(); este método tomará F1, el segundo será el texto, y el siguiente parámetro del argumento será el origen donde queremos poner este texto.

El siguiente parámetro es el tipo de letra FONT_HERSHEY_SIMPLEX; el siguiente parámetro será la escala de fuente. El siguiente será el color de la fuente; luego, el último parámetro será el grosor del texto.

cv2.putText(
    F1,
    "Status: {}".format("Movement"),
    (10, 20),
    cv2.FONT_HERSHEY_SIMPLEX,
    1,
    (0, 0, 255),
    3,
)

Ahora escribiremos algo de código fuera del bucle. Primero, escribiremos imágenes de salida para guardar la salida y luego mostraremos F1, el resultado después de aplicar el contorno.

En la siguiente línea, estamos leyendo el nuevo cuadro en la variable F2, y antes de leer el nuevo cuadro, asignamos el valor de F2 a la F1. De esta manera, estamos leyendo y encontrando la diferencia entre los dos fotogramas.

OP.write(IMG)
cv2.imshow("feed", F1)
F1 = F2
ret, F2 = CAP.read()

Código fuente completo:

import cv2
import numpy as np

CAP = cv2.VideoCapture("input.avi")
FR_W = int(CAP.get(cv2.CAP_PROP_FRAME_WIDTH))

FR_H = int(CAP.get(cv2.CAP_PROP_FRAME_HEIGHT))

FRC = cv2.VideoWriter_fourcc("X", "V", "I", "D")

OP = cv2.VideoWriter("output.avi", FRC, 5.0, (1280, 720))

ret, F1 = CAP.read()
ret, F2 = CAP.read()
print(F1.shape)
while CAP.isOpened():
    if ret == False:
        print(ret)
        break
    DF = cv2.absdiff(F1, F2)
    Gray_Scale = cv2.cvtColor(DF, cv2.COLOR_BGR2GRAY)
    BL = cv2.GaussianBlur(Gray_Scale, (5, 5), 0)
    _, thresh = cv2.threshold(BL, 20, 255, cv2.THRESH_BINARY)
    DL = cv2.dilate(thresh, None, iterations=3)
    CTS, _ = cv2.findContours(DL, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

    for CT in CTS:
        (x, y, w, h) = cv2.boundingRect(CT)

        if cv2.contourArea(CT) < 900:
            continue
        cv2.rectangle(F1, (x, y), (x + w, y + h), (0, 255, 0), 2)
        cv2.putText(
            F1,
            "Status: {}".format("Movement"),
            (10, 20),
            cv2.FONT_HERSHEY_SIMPLEX,
            1,
            (0, 0, 255),
            3,
        )

    IMG = cv2.resize(F1, (1280, 720))
    OP.write(IMG)
    cv2.imshow("feed", F1)
    F1 = F2
    ret, F2 = CAP.read()

    if cv2.waitKey(40) == 27:
        break

cv2.destroyAllWindows()
CAP.release()
OP.release()

Podemos ver que el estado muestra movimiento porque todas las personas se están moviendo. También podemos mirar los rectángulos que se dibujan alrededor de la persona que se mueve.

Seguimiento de OpenCV

Salman Mehmood avatar Salman Mehmood avatar

Hello! I am Salman Bin Mehmood(Baum), a software developer and I help organizations, address complex problems. My expertise lies within back-end, data science and machine learning. I am a lifelong learner, currently working on metaverse, and enrolled in a course building an AI application with python. I love solving problems and developing bug-free software for people. I write content related to python and hot Technologies.

LinkedIn

Artículo relacionado - Python OpenCV