? DETECCIÓN DE MOVIMIENTO en CIERTA ÁREA | Python – OpenCV
Supongamos que nos han encomendado una tarea, el detectar movimiento en cierta área mediante visión artificial. Entonces tenemos un video de entrada, en donde vamos a detectar dicho movimiento, sin embargo el área donde debemos trabajar no es toda la imagen, sino parte de ella. En este tutorial veremos como realizar la detección de movimiento en cierta porción de una imagen con ayuda de la sustracción de fondo que vimos en el post anterior.
Detección de movimiento en cierta área o lugar de la imagen con OpenCV y Python
Ya habíamos visto en acción a la detección de movimiento en un tutorial pasado: ? DETECCIÓN DE MOVIMIENTO (Con sustracción de imágenes) – OpenCV y Python. En aquel tutorial empleamos la sustracción de imágenes, y tratamos de detectar el movimiento. En esta ocasión usaremos Background Subtractor MOG (sustracción de fondo) que es uno de los algoritmos que habíamos visto en el anterior tutorial y este lo aplicaremos solo en cierta área de la imagen. ¡Empecemos!.
Como te decía, supongamos que nos han pedido detectar movimiento en cierto lugar de un edificio. Entonces nos muestran los videos que capta una cámara, en la cual podemos ver el área que necesitamos analizar, pero además otras áreas que no necesitamos, es entonces que debemos planificar que hacer. Además para nuestro ejemplo, el mover la cámara de lugar para que capture solo el área que deseamos no es una posibilidad. Por lo que te planteo una solución a este problema a continuación:
import cv2 import numpy as np cap = cv2.VideoCapture('aeropuerto.mp4') fgbg = cv2.bgsegm.createBackgroundSubtractorMOG() kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(3,3))
Línea 1 y 2: Importamos OpenCV y numpy.
Línea 4: Especificamos el video de entrada. Por cierto, puedes encontrar el video completo que usé para este tutorial aquí.
Línea 6: Especificamos el algoritmo de sustracción de fondo que estaremos usando, BackgroundSubtractorMOG.
Línea 7: Usaremos este más adelante para mejorar la imagen binaria luego de aplicar la sustracción de fondo.
while True: ret, frame = cap.read() if ret == False: break gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # Dibujamos un rectángulo en frame, para señalar el estado # del área en análisis (movimiento detectado o no detectado) cv2.rectangle(frame,(0,0),(frame.shape[1],40),(0,0,0),-1) color = (0, 255, 0) texto_estado = "Estado: No se ha detectado movimiento" # Especificamos los puntos extremos del área a analizar area_pts = np.array([[240,320], [480,320], [620,frame.shape[0]], [50,frame.shape[0]]]) # Con ayuda de una imagen auxiliar, determinamos el área # sobre la cual actuará el detector de movimiento imAux = np.zeros(shape=(frame.shape[:2]), dtype=np.uint8) imAux = cv2.drawContours(imAux, [area_pts], -1, (255), -1) image_area = cv2.bitwise_and(gray, gray, mask=imAux)
Línea 11 y 12: Se realiza la lectura de los fotogramas.
Línea 14: Transformamos frame
de BGR a escala de grises.
Línea 18 a 20: Estas líneas nos servirán para visualizar la información de la detección o no de movimiento en el área.
Línea 23: Especificamos los puntos extremos del área que deseamos analizar. Estos han sido ordenados de forma horaria.
Línea 27 y 28: Creamos una matriz auxiliar de ceros, del mismo ancho y alto que frame
. Luego en esta dibujamos el contorno formando por los puntos dados en area_pts
.
Línea 29: Con ayuda de cv2.bitwise_and
, obtenemos una imagen en donde el área blanca de la línea 28 se mostrará gray
. Creo que esta parte se explica mejor visualizando uno de los fotogramas obtenidos, veamos:
# Obtendremos la imagen binaria donde la región en blanco representa # la existencia de movimiento fgmask = fgbg.apply(image_area) fgmask = cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, kernel) fgmask = cv2.dilate(fgmask, None, iterations=2)
Línea 33: Aplicamos la sustracción de fondo sobre image_area
.
Línea 34 y 35: Aplicamos transformaciones morfológicas (opening y dilate) para mejorar la imagen binaria obtenida en la línea 33.
# Encontramos los contornos presentes en fgmask, para luego basándonos # en su área poder determina si existe movimiento cnts = cv2.findContours(fgmask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0] for cnt in cnts: if cv2.contourArea(cnt) > 500: x, y, w, h = cv2.boundingRect(cnt) cv2.rectangle(frame, (x,y), (x+w, y+h),(0,255,0), 2) texto_estado = "Estado: Alerta Movimiento Detectado!" color = (0, 0, 255)
Línea 39: Usamos cv2.findContours
, para encontrar los contornos presentes en fgmask
.
Línea 40 a 45: Analizamos cada contorno encontrado. Cuando un contorno tenga un área mayor a 500, se dibujará un recuadro delimitador que rodeará al área blanca en movimiento. Además, ya que se ha detectado movimiento sobre esa área se visualizará "Estado: Alerta Movimiento Detectado!"
en la parte superior de la imagen. Por último se asignará el color rojo a la variable color
.
# Visuzalizamos el alrededor del área que vamos a analizar # y el estado de la detección de movimiento cv2.drawContours(frame, [area_pts], -1, color, 2) cv2.putText(frame, texto_estado , (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, color,2) cv2.imshow('fgmask', fgmask) cv2.imshow("frame", frame) k = cv2.waitKey(70) & 0xFF if k == 27: break cap.release() cv2.destroyAllWindows()
Línea 49 y 50: Visualizamos en frame
, el alrededor del área que estamos analizando, además del texto que aparecerá en la sección superior de la imagen, indicando si se ha detectado o no movimiento en el área seleccionada.
Línea 53 a 61: Visualizamos fgmask
y frame
. El proceso finalizará hasta que se presione ESC o hasta que se acabe el video de entrada. Finalmente se cierran las ventanas de visualización.
Veamos los resultados:
Como veremos a continuación, hay una persona que no fue detectada. Bien esto es entendible, ya que como lo vimos en el tutorial anterior para la sustracción de fondo, si el objeto o la persona en este caso posee un color similar al del fondo, entonces se puede tener problemas al momento de aplicar sustracción de fondo.
Y hemos llegado al final de este tutorial, que por cierto espero que te haya gustado. ¡Nos vemos en el siguiente!.
Hola!,
Tengo Opencv 4.4 y me pasa que al ejecutar el codigo me devuelve el prompt en windows.. sin haber ejecutado ninguna ventana.. alguna idea?
* Revisado el codigo
* Video original que indicaste e incluso otro que tengo de test
* Tengo funcionando opencv con otros ejemplos tuyos
Gracias!
Manu
Hola Manu, has visualizado la ventana con cv2.imshow? y luego para que se visualice hasta que el usuario presione una tecla, usaste cv2.waitKey(0)?
hola tengo el opencv 4.6 y tengo el mismo problema no me ejecuta ninguna ventana
Hola Cesar, obtienes algún error?
Hola! Que tal ! A mi me da este error:
AttributeError: module ‘cv2’ has no attribute ‘cv_FONT_HERSEY_SIMPLEX’
y si instalé opencv con pip install opencv-contrib-python.
Llevo rato tratando de resolver el error pero aun no puedo jejeje.
Cabe aclarar que para probar que si estuviera funcionando probré con otro codigo, es el siguiente:
import cv2
cap = cv2.VideoCapture(0)
fps = cap.get(cv2.CAP_PROP_FPS)
while True:
ret, img = cap.read()
cv2.putText(img,str(fps) + » fps», (5, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, 255,2)
cv2.imshow(‘Window’,img)
k = cv2.waitKey(80) & 0xFF
if k == 27:
break
cap.release()
cv2.destroyAllwindows()
Quiero imaginar que esta parte de codigo «cv2.putText(img,str(fps) + » fps», (5, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, 255,2)
cv2.imshow(‘Window’,img)» es la que tendria que implementar al codigo actual.
Tu que opinas?
Sin nada mas que agregar, quedo al pendiente
Saludos
Hola Pablo, según veo el error lo obtienes porque falta la H en HERSHEY, por ello obtienes el error: AttributeError: module ‘cv2’ has no attribute ‘cv_FONT_HERSEY_SIMPLEX’.
Cuando ejecuto y me sale el video, me sale enorme que no me cabe ni en pantalla, porque pasa esto ?
Hola Luifer, es por el tamaño del video de entrada. Puedes redimensionarlo con cv2.resize o con imutils. https://youtu.be/iI35ZTe5b3g
Buenas, al ejecutarlo me da un error:
File «detectar_zona.py», line 4, in
fgbg = cv2.bgsegm.createBackgroundSubtractorMOG()
AttributeError: module ‘cv2’ has no attribute ‘bgsegm’
¿Alguna idea?
Muchas gracias!
Hola Marc, asegúrate de haber instalado OpenCV con contrib. Puede que sea ese el problema.
Usa
fgbg = cv2.createBackgroundSubtractorMOG2()
para que te deje correrlo
createBackgroundSubtractorMOG2() cambielo por este.
Cuando ejecuto el código se cierra el video instantáneamente
Hola José, verifica que la función cv2.waitKey. Pueda que esta función te esté dando problemas en el tiempo de visualización.
Hola,
Te cuento que al momento de ejecutar mi video sale demasiado lento, he movido los valores k = cv2.waitKey(30) & 0xFF
desde 30 a 90 y nada siempre es muy lento.
Tu ayuda, por favor?
Hola,
Te cuento que al momento de ejecutar mi video sale demasiado lento, he movido los valores k = cv2.waitKey(30) & 0xFF
desde 30 a 90 y nada siempre es muy lento.
Tu ayuda, por favor?
NOTA: Estoy probando con otro video, mi video está en formato MP4 pesa !12,9MB y su duración es de 1 minuto 47 segundos.
Hola Jyron, intenta cambiar por valores más bajos, por ejemplo 1 por el 30.
error: (-215:Assertion failed) size.width>0 && size.height>0 in function ‘cv::imshow’ HELPP?
Hola XMAN, comprueba que esté correcta la lectura del video o imagen, puede que no se haya encontrado dicha imagen/video.
Buen día quiero redimensionar el video con imutils pero no me deja
Traceback (most recent call last):
File «C:/Users/Román Hdz/AppData/Local/Programs/Python/Python39/Vision/vision.py», line 7, in
cap1= imutils.resize(cap , width=300)
File «C:\Users\Román Hdz\AppData\Local\Programs\Python\Python39\lib\site-packages\imutils\convenience.py», line 69, in resize
(h, w) = image.shape[:2]
AttributeError: ‘cv2.VideoCapture’ object has no attribute ‘shape’
>>>
Hola Román, se me hace que estás usando cap = cv2.VideoCapture, y de cap quieres redimensionar la imagen. Pero en este caso tendrías que redimensionar la imagen contenida en cap.read().
Me marca este error en imutils
Traceback (most recent call last):
File «C:/Users/Román Hdz/AppData/Local/Programs/Python/Python39/Vision/vision.py», line 7, in
cap1= imutils.resize(cap , width=300)
File «C:\Users\Román Hdz\AppData\Local\Programs\Python\Python39\lib\site-packages\imutils\convenience.py», line 69, in resize
(h, w) = image.shape[:2]
AttributeError: ‘cv2.VideoCapture’ object has no attribute ‘shape’
Buen día me sale este error al querer re dimensionar el video porque sale muy grande.
Traceback (most recent call last):
File «C:/Users/Román Hdz/AppData/Local/Programs/Python/Python39/Vision/vision.py», line 7, in
cap1= imutils.resize(cap , width=300)
File «C:\Users\Román Hdz\AppData\Local\Programs\Python\Python39\lib\site-packages\imutils\convenience.py», line 69, in resize
(h, w) = image.shape[:2]
AttributeError: ‘cv2.VideoCapture’ object has no attribute ‘shape’
Con que función puedo encontrar el centro de los objetos, si ya tengo los objetos con su respectivo contorno ?
Hola Armando, puedes encontrar un ejemplo de como realizarlo aquí: http://omes-va.com/contando-por-colores-en-python-opencv/ En la sección: Enumerar cada uno de los círculos de acuerdo al color.
Buen día , para todos los que les parezca una ventana gigante al momento de poner el video a funcionar les dejo la función que cree y los pasos para que se vea como la chica guapa por cierto del tutorial
1. agregan esta funcion antes del while
def rescale_frame(frame, percent=75):
width = int(frame.shape[1] * percent/ 100)
height = int(frame.shape[0] * percent/ 100)
dim = (width, height)
return cv2.resize(frame, dim, interpolation =cv2.INTER_AREA)
2. justo en el while donde dice ret, frame = cap.read(), deben poner lo siguiente:
frame = rescale_frame(frame,35) «yo deje 35 por que es lo que se acomodo a mi pantalla pero ustedes prueben diferentes escalas»
3. Listo , si pegaron la funcion sus 3 lineas primeras del while deberian quedar asi:
while True:
ret, frame = cap.read()
frame = rescale_frame(frame,35)
if ret == False: break
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
Creditos: JamesRC1142
Da este error mi pana
File «C:\Users\Robert\Desktop\detectar_mov_area.py», line 10
width = int(frame.shape[1] * percent/ 100)
^
IndentationError: expected an indented block
[Finished in 0.3s]
Hola Alex, es un error de identación. Puedes revisar los espacios de esa línea para que puedas solucionarlo.
Disculpa, podrías darme tu correo. Quisiera conversar contigo sobre temas laborales.
Saludos.
Hola Rodrigo, claro te dejo mi correo: [email protected]
Saludos para ti también.
Buen dia …donde puedo encontrar el video original del aeropuerto para probar no lo encuentro
Hola Isra RR, puedes encontrarlo en la cajita de descripción del videotutorial.
Una pregunta como puedo solucionar cuando a la hora de hacer correr el programa el video insertado se reproduzca?
porque solo me sale como imagen y se queda quieto gracias
Hola Alex, mira que en cv2.waitKey tengas un 1, en vez de un 0.
Hola, al ejecutar solo me compila pero no me abre la ventana, ya he cambiado varios valores y sigue sin funcionarme..
¿Qué puedo hacer?
Hola Simon. ¿Usaste cv2.imshow?. ¿Obtienes algún error?
Hola, no me muestra ningun error unicamente compila
NO ME funciona me lo deja como imagen si pongo 1 o 0
solo habre y cierra el video
Hola Carlos, por favor déjame el código para poder analizarlo. 🙂
Se podria hacer con un área de la pantalla? No un vídeo, sino más bien enmarcar la parte del monitor que quiero que detecte
¿Cómo funciona el comando .apply en el código sin la librería pandas? He estado investigando por internet y encontré información acerca del uso de este comando, y se utiliza con pandas.
El programa que estoy haciendo es detectar objetos en un área, como lo explicaste en el video. Sin embargo, no estoy utilizando la sustracción de fondo, porque solamente detecta el movimiento. Al pasar un tiempo, el objeto no es detectado. Esto es lo que no quiero que suceda en mi aplicación.
De esta, manera decidí utilizar la técnica disponible en OpenCV llamada «cv2.threshold(…)». El error que tengo en mi programa es que en la parte de utilizar fgmask = fgbg.apply(image_area) me da error. fgbg es la variable que retorna el resultado de la sustracción de fondo. En ves de esto, estoy utilizando fgmask1 = thFrame.apply(image_analysis_area1), donde: ret, thFrame = cv.threshold(greyFrame, 120, 255, cv.THRESH_BINARY_INV).
El mensaje que me aparece al ejecutar el programa es:
fgmask1 = thFrame.apply(image_analysis_area1)
AttributeError: ‘numpy.ndarray’ object has no attribute ‘apply’
[ WARN:[email protected]] global ..\modules\videoio\src\cap_msmf.cpp (539) `anonymous-namespace’::SourceReaderCB::~SourceReaderCB terminating async callback
Holaaaa, gracias por compartir tus proyectos!!!
Tengo un error me dice que image_area no esta definida, el error me aparece en esta línea
fgmask = fgbg.apply(image_area)
antes de eso tengo
image_area = cv2.bitwise_and(gray, gray, mask=imAux)
Como lo podría resolver?
Muchas gracias!!
Hola buenas tardes.
Tengo todas las lineas pero solo me presenta el vídeo original
saludos
Hola! no me está dejando visualizar el video, a pesar de que estoy usando el mismo video de referencia que tu y también el mismo code, a qué se debe esto ?
Hola Juan, obtienes algún error? o solo no se visualiza? Sería chévere poder revisar tu código en un comentario, a ver que está pasando. 🙂
Muchas gracias por tu tutoriales. Muy útiles para un senior muy senior y muy novato en Python.
El código funciona muy bien, pero si en el area de detección no hay nadie, el video se bloquea hasta nueva detección. Probado con video de carretera y con WebCam.
¿Hay solución? Gracias otra vez por tu esfuerzo.
Hola, muchas gracias por compartir tu conocimiento y ganas de enseñar esto es en realidad lo que se dice como persona desprendida y aparte empoderas muy bien a la mujer, un muy claro ejm de que si quieren se pueden meter en las ciencias, con tus explicaciones he podido avanzar mucho en python pero llegue a este ejm donde copio y pego tu codigo, descargo el video aeropuerto.mp4 y le doy a run pero no hace absolutamente nada, no da ningun erro ni abre ninguna ventana de visualizacion, veo en comentarios que a mas de uno le pasa pero no han podido solucionarlo, en mi caso es innecesario enviar el codigo ya que es el mismo expuesto en esta pagina, e tomado cada troso de codigo y lo he pegado en el idle de python, pero nada debe ser un error tonto que a un novato como yo le cuesta ver jeje, te agradeceria que me ayudaras en orientarme que debo hacer ?, gracias y que Dios te siga dando la bendicion del conocimiento y de compartirlo.
Buen día, Gaby.
Muy buena idea esta de ir publicando, en texto, los videotutoriales de youtube de una manera más explicada. Acabo de seguir los pasos de esta entrada y si me compila, pero no me muestra nada por pantalla. Tengo el comando imshow tal cual lo tienes en el código de muestra, el waitKey y demás. Igual, no me devuelve nada. Hice algo más que fue ir mostrando los valores de ciertas variables, como cnts y fgmask que son variables de entrada para las secciones del código donde se muestra el video y los resultados que obtengo son todo en 0. Uso la versión 4.7.0 de opencv.
Quedo al tanto de tus comentarios
Saludos desde Cuba