SUSTRACCIÓN DE FONDO | Python – OpenCV

Por Administrador

¿Recuerdas el video de la detección de movimiento (? DETECCIÓN DE MOVIMIENTO (Con sustracción de imágenes) – OpenCV y Python.) que realizamos hace algún tiempo ya? En ese video aplicamos sustracción de imágenes para detectar el movimiento, pero fue un tanto diferente a lo que veremos hoy. Recordemos un poco: 

Ubicamos la cámara en un lugar estático, entonces para realizar la sustracción del fondo y determinar donde existe movimiento, usamos una imagen de referencia, que correspondía al fondo de la escena y luego con ayuda de cv2.absdiff obtuvimos la diferencia entre la imagen del fondo y los siguientes fotogramas. Aplicábamos a este resultado umbralización simble en donde a su vez obteníamos una imagen binaria, en donde la región blanca representaba el primer plano o el movimiento en estos caso, mientras que en negro el fondo de la escena. 

¿Pero qué sucedería si la imagen con el fondo de la escena no fuera tan fácil de conseguir? Imaginemos que nuestro objetivo es contar autos en una autopista. Si para desarrollar un programa tomamos lo que hicimos en el tutorial anterior que te pedí que recordaras, sería muy difícil obtener una imagen del fondo. Tendríamos que buscar el momento exacto en que no existiese ningún auto para usar esa imagen y restarla de los fotogramas siguientes.  

Pero aun si la consiguiéramos, tendríamos problemas con la iluminación, ya que al pasar de la mañana a tarde a noche, esta cambiaría y no obtendríamos buenos resultados al tratar de extraer el primer plano, o a los autos en este caso. 

Es por ello que en el tutorial de hoy, veremos otros algoritmos que posee OpenCV para la sustracción de fondo, que si bien tienen sus limitaciones, mejoran muchísimo con respecto al método que usé en tutoriales anteriores. (Y además, no vamos a tener que preocuparnos por obtener una imagen del fondo). 

CONTENIDO

  • Background Subtractor
    • Background sustractor MOG
    • Background sustractor MOG2
    • Background sustractor GMG
    • Aspectos importantes a considerar al aplicar la sustracción de fondo

Background Subtractor

La sustracción de fondo o background sustractor es una técnica que nos permite detectar objetos en movimiento (foreground o primer plano), mientras que descarta el resto de la escena (background o fondo), ya que permanecerá sin movimiento. Claro, esto se da al emplearse una cámara estática que estará captando toda la escena.

Figura 1: Izq. Video de entrada. Der. Imagen binaria obtenida al aplicar sustracción de imágenes.

En este tutorial veremos como aplicar 3 algoritmos que posee OpenCV para la sustracción de fondo: BackgroundSubtractorMOG, BackgroundSubtractorMOG2 y BackgroundSubtractorGMG. 

NOTA: El video con el que estaré realizando este tutorial es vtest.avi de OpenCV, puedes encontrarlo aquí.

BackgroundSubtractorMOG

Según OpenCV: «Es un algoritmo de segmentación de fondo / primer plano basado en una mezcla gaussiana». (Fuente)

import cv2

cap = cv2.VideoCapture('vtest.avi')
fgbg = cv2.bgsegm.createBackgroundSubtractorMOG()

while True:

    ret, frame = cap.read()
    if ret == False: break

    fgmask = fgbg.apply(frame)
    
    cv2.imshow('fgmask',fgmask)
    cv2.imshow('frame',frame)
    
    k = cv2.waitKey(30) & 0xFF
    if k == 27:
        break
cap.release()
cv2.destroyAllWindows()

Línea 1: Importamos OpenCV.

Línea 3: Leemos el video de entrada.

Línea 4: Llamamos al algoritmo que vamos a estar usando, en este caso BackgroundSubtractorMOG. Vamos a dejar sus parámetros por defecto, pero si deseas puedes tener más información sobre ellos en la documentación de OpenCV.

Línea 8 y 9: Leemos los fotogramas y si ret == False, rompemos el ciclo.

Línea 11: Necesitamos usar el nombre que asignamos en la línea 4, seguido de apply() para obtener la máscara del primer plano, en donde la sección en blanco representará el primer plano u objetos en movimiento, y en negro el fondo de la imagen.

Línea 13 a 20: Visualizamos fgmaskframe. Luego si ‘ESC’ es presionado, se romperá el ciclo y se cerrarán las ventanas creadas.

Figura 2: Visualización del video de entrada y al aplicar BackgroundSubtractorMOG.

BackgroundSubtractorMOG2

Al igual que en el anterior algoritmo, OpenCV señala que: «Es un algoritmo de segmentación de fondo / primer plano basado en una mezcla gaussiana». Pero además, «Proporciona una mejor adaptabilidad a diferentes escenas debido a cambios de iluminación, etc». (Fuente)

import cv2

cap = cv2.VideoCapture('vtest.avi')
fgbg = cv2.createBackgroundSubtractorMOG2()

while True:

    ret, frame = cap.read()
    if ret == False: break

    fgmask = fgbg.apply(frame)
    
    cv2.imshow('fgmask',fgmask)
    cv2.imshow('frame',frame)

    k = cv2.waitKey(30) & 0xFF
    if k == 27:
        break
cap.release()
cv2.destroyAllWindows()

Como puedes apreciar, el código es bastante parecido al anterior, por lo que solo explicaré las líneas concernientes a este algoritmo.

Línea 4: Para emplear este algoritmo debemos llamarlo con cv2.createBackgroundSubtractorMOG2(). Vamos a dejar sus parámetros por defecto, pero si deseas puedes tener más información sobre ellos en la documentación de OpenCV.

NOTA: cv2.createBackgroundSubtractorMOG2() posee un parámetro llamado detectShadows, que permitirá detectar las sombras generadas por los objetos en movimiento, marcándolas en grises. Este proceso hará que disminuya la velocidad, por lo que si no es necesario, se puede especificar el parámetro como False.

Línea 11: Al igual que en algoritmo anterior, usamos apply() para obtener la máscara del primer plano, en donde la sección en blanco representará el primer plano u objetos en movimiento, y en negro el fondo de la imagen. En esta ocasión dejaremos los parámetros por defecto, pero si necesitas más información puedes darle clic aquí.

Figura 3: Visualización del video de entrada y al aplicar BackgroundSubtractorMOG2.

BackgroundSubtractorGMG

Según OpenCV: «Este algoritmo combina la estimación estadística de la imagen de fondo y la segmentación bayesiana por píxel». (Fuente) Algo que hay que tener en cuenta y nos lo dice la documentación, es que este algoritmo utiliza los primeros fotogramas (120 por defecto) para el modelado de fondo, entonces se obtendrá una ventana negra en los primeros fotogramas.

import cv2

cap = cv2.VideoCapture('vtest.avi')
fgbg = cv2.bgsegm.createBackgroundSubtractorGMG()

while True:

    ret, frame = cap.read()
    if ret == False: break

    fgmask = fgbg.apply(frame)
    
    cv2.imshow('fgmask',fgmask)
    cv2.imshow('frame',frame)

    k = cv2.waitKey(30) & 0xFF
    if k == 27:
        break
cap.release()
cv2.destroyAllWindows()

Línea 4: Llamamos al algoritmo que vamos a estar usando, en este caso BackgroundSubtractorGMG. Vamos a dejar sus parámetros por defecto, pero si deseas puedes tener más información sobre ellos en la documentación de OpenCV.

Línea 11: Necesitamos usar el nombre que asignamos en la línea 4, seguido de apply() para obtener la máscara del primer plano, en donde la sección en blanco representará el primer plano u objetos en movimiento, y en negro el fondo de la imagen.

Figura 4: Visualización del video de entrada y al aplicar BackgroundSubtractorMOG2.

Aspectos importantes a considerar al aplicar la sustracción de fondo

Cabe destacar que si usamos estos algoritmos para el conteo de personas por ejemplo, debemos tomar en cuenta que si varias personas están juntas, se tomaría como si fuera un gran objeto en movimiento. 

Figura 5: Personas próximas.

Si el color del objeto es similar al del fondo, pueden presentarse errores al momento de detectar el primer plano. 

Figura 6: Persona en movimiento con color similar al del fondo.

Si un objeto que estuvo en movimiento se queda quieto por algún tiempo, los algoritmos lo tomarán como parte del fondo. 

Figura 7: Yo, Gaby. Tratando de no moverme para visualizar como se comportan los algoritmos ante un objeto que luego de estar en movimiento, se queda quieto :).

REFERENCIAS