SUSTRACCIÓN DE FONDO | Python – OpenCV
¿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.
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 fgmask
y frame
. Luego si ‘ESC’ es presionado, se romperá el ciclo y se cerrarán las ventanas creadas.
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í.
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.
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.
Si el color del objeto es similar al del fondo, pueden presentarse errores al momento de detectar el primer plano.
Si un objeto que estuvo en movimiento se queda quieto por algún tiempo, los algoritmos lo tomarán como parte del fondo.
REFERENCIAS
- https://github.com/opencv/opencv/tree/master/samples/data
- https://docs.opencv.org/master/d8/d38/tutorial_bgsegm_bg_subtraction.html
- https://docs.opencv.org/master/d1/dc5/tutorial_background_subtraction.html
- https://docs.opencv.org/3.4/de/df4/tutorial_js_bg_subtraction.html
- https://docs.opencv.org/3.4/d7/d7b/classcv_1_1BackgroundSubtractorMOG2.html#a682adde901148d85450435e6cc0de4a1
- https://docs.opencv.org/master/de/de1/group__video__motion.html#ga2beb2dee7a073809ccec60f145b6b29c
- https://programarfacil.com/blog/vision-artificial/deteccion-de-movimiento-con-opencv-python/
Para una imagen estática, cuál seria el procedimiento? ya que las imágenes que estoy usando tienden a confundirse y no crea un contorno adecuado debido a la iluminación, se puede solucionar con opencv? Gracias de antemano y muchas felicitaciones, muy buenos tus videos
Hola Jesus, para imágenes estáticas podrías aplicar la sustracción de imágenes. http://omes-va.com/adicion-sustraccion-de-imagenes/
Me encantan tus videos y explicaciones, gracias por compartir lo que has aprendidom ensenas muy bien, soy tu fan.
Muchas gracias Luis, eres muy amable. Gracias de verdad por compartirme que te gustan los tutoriales. Un abracito!
Hola Gaby.
Disculpa, al momento de ejecutar el programa me sale esto: «AttributeError: module ‘cv2.cv2’ has no attribute ‘bgsegm'».
He intentado buscar la solución en internet, pero no he logrado dar con la reapuesta, pordría ayudarme, por favor?.
Hola Axel, asegúrate de haber instalado OpenCV contrib. Como en este video: https://youtu.be/6R_VU958jPY
Consulta, si en vez de usar videos quiero usar imagenes. Conoces documentacion sobre eso?
Ncesito sacarle el fondo a una imagen para eliminar la interferencia y el ruido al momento de contar objetos
Hola Federico, y si usas la sustracción de fondo, con estos métodos: http://omes-va.com/adicion-sustraccion-de-imagenes/
Hola Gabriela, muchas gracias por compartir, una consulta ¿Se puede utilizar mp4 en lugar de avi? ¿Solamente hay que cambiar la extension?
Si Abel, exactamente. 🙂
hola gabi.. mi consulta es.. si esto se puede hacer con una camara en tiempo real?.. gracias
Hola Catherin, claro que sí. Puedes usar cv2.VideoCapture(0).
Es posible que en donde se ven los contornos de las personas en blanco, se vean las figuras y el fondo negro? es decir, solo se vean las prsonas sin fondo
Buenos días bendiciones Gabriela.
Excelente tus vídeos.
Hola, primero felicidades por tus aportes y enseñanzas.
Pregunta: ¿Es posible que en OpenCV 4.7 (versión actual), el algoritmo/método BackgroundSubtractorMOG() ya no exista? (solo consta en las librerías el MOG2), y si uso cualquier línea especificando MOG o bgsegm.*, me da un error de «no existe». ¿Es posible que hayan anulado el MOG por el MOG2?
Gracias.
Hola de nuevo.
Tengo el mismo problema con el algoritmo GMG, el cual tampoco consta en OpenCV 4.7.
En su lugar me aparece el KNN, que trabaja por proximidad de pixeles.
Tanto el MOG2, como el KNN, mejoran mucho los resultados si se especifican parámetros concretos en lugar de los que se aplican por defecto.