<jupyter_start><jupyter_text>EJERCICIO: ACTIVIDAD Construye un detector de movimiento en una región de interés de la imagen marcada manualmente. Guarda 2 ó 3 segundos de la secuencia detectada en un archivo de vídeoPara la resolución del ejercicio se ha considerado la siguiente aproximación: si la **diferencia media** entre una imagen original y otra modificada, ambas captadas por una **webcam**, supera un cierto umbral **THRES**, se iniciará el proceso de grabación de un vídeo de duración **TIME** segundos. Por defecto, se considerará un umbral **THRES = 10** y una longitud de vídeo de **TIME = 3 segundos**. Ambos parámetros son configurables desde la línea de comandos (el script ACTIVIDAD.py maneja un parser de argumentos con ```argparse```).Para que el programa sea capa de localizar una anomalía, el usuario deberá especificar una región rectangular de la imagen presionando el click izquierdo del ratón. Esto dará lugar lo que se conoce como un **ROI** (*Region Of Interest*). Esta subimagen será la que el programa considere a la hora de localizar las anomalías. Para que el programa comience el proceso de vigilancia, se deberá especificar un ROI y capturarlo con la tecla 'c'. A partir de este momento, cualquier anomalía (es decir, cualquier diferencia notable entre el momento de la captura del ROI y la imagen en directo) que supere el umbral será detectada y grabada en vídeo.A continuación se lista las condiciones (individuales) para que un vídeo deje de grabar:1. La diferencia media entre 2 imágenes ha dejado de superar el umbral THRES.2. La longitud de vídeo ha alcanzado los TIME segundos.3. Se ha detenido el proceso de captura (tecla 'x'). Esta acción borra también el ROI de la imagen.4. Se ha modificado el ROI.5. Se ha detenido la ejecución del programa (tecla 'ESC').Cabe recalcar que, si la anomalía transcurre en la imagen durante un tiempo mayor que TIME, se producirá como resultado distintos vídeos de duración TIME. De esta forma, en un frame se detendrá el vídeo y en el siguiente, si se sigue superando el umbral, se iniciará un nuevo proceso de grabación.Comenzamos con la importación de las librerías requeridas para la resolución del ejercicio y la inicialización de la ventana de visualización.<jupyter_code>#import argparse
import cv2          as cv
import numpy        as np
from   umucv.stream import autoStream
from   umucv.util   import Video, ROI, putText
from   time         import time

'''
parser = argparse.ArgumentParser(description='Graba y guarda archivos de vídeo de 3 segundos con la webcam en caso de que se detecte en la imagen una anomalía que sobrepase un cierto umbral en el ROI seleccionado')
parser.add_argument('-thres', metavar='--threshold', type=float, default = 10,
                    help='La diferencia media umbral de imagen entre entre 2 ROIs que se debe superar para considerar una anomalía en la imagen (por defecto, 10)')
parser.add_argument('-time', metavar='--videoLength', type=float, default = 3,
                    help='La longitud del vídeo en segundos (por defecto, 3)')
'''

cv.namedWindow("input")
cv.moveWindow('input', 0, 0)

#ELIMINAR LAS SIGUIENTES LINEAS SI SE CONSIDERA EL PARSER
THRES = 10
TIME = 3<jupyter_output><empty_output><jupyter_text>A continuación se definen las variables que necesarias para la correcta ejecución del programa:- ```region```: objeto que nos permitirá determinar las dimensiones del ROI- ```captured```: flag booleana que permitirá distinguir al programa cuándo un ROI está siendo capturado en el programa y cuándo no.- ```prevDim```: las dimensiones del ROI en el frame anterior. Será necesario para la condición 4 de detención de vídeo, ya que la única forma que se tiene de comparar 2 ROIs es comparando sus dimensiones.- ```start```: timestamp del inicio de la grabación (medido en segundos).- ```video```: objeto que referencia al vídeo. También actúa como flag para distinguir si se está grabando un vídeo o no (```video = 0```)<jupyter_code>region = ROI("input")
captured = False
prevDim = []
start = video = 0<jupyter_output><empty_output><jupyter_text>Se han definido además las siguiente funciones auxiliares para comenzar y detener un vídeo.<jupyter_code>def startVideo():
    '''Inicia el proceso de grabacion y devuelve el objeto video y la marca de tiempo de inicio'''
    print("\nAnomaly detected with "+str(round(diff,2))+" mean difference")
    video = Video(fps=30, codec="MJPG",ext="avi")
    video.ON = True
    return video, time()

def stopVideo(video,t = 0, info = 0):
    '''Detiene un video y devuelve valores nulos para este y la marca de inicio de grabacion.
    Puede recibir como argumento adicional el tiempo de grabacion de video'''
    global start
    print(str(round(t if t else time()-start, 2)) + " seconds of anomaly recorded")
    if (info):
        print(info)
    video.release()
    return 0,0<jupyter_output><empty_output><jupyter_text>El procesamiento de los frames se realiza en un bucle que continuará ejecutándose hasta que salgamos del programa (tecla 'ESC'). En una iteración del bucle, se tiene un ```frame``` y la tecla ```key``` que se ha pulsado (o no) en un instante de tiempo.La primera comprobación que realizamos es la comparación entre el ROI anterior, cuyas dimensiones estarían almacenadas en ```prevDim```, y el actual. Esto se trata de la condición 4 de detención de grabación. Con un nuevo ROI, el proceso de captura termina y, en caso de estar grabándose un vídeo, se detiene. Seguidamente, almacenamos en ```liveROI``` la porción de imagen seleccionada (dado que solo la utilizaríamos para el cálculo de la diferencia, no es una asignación muy necesaria pero aumenta la legibilidad de código). Almacenamos también las dimensiones del ROI```pythonfor key, frame in autoStream():    [x1,y1,x2,y2] = region.roi    Si estamos creando un nuevo ROI distinto del anterior ya capturado...    if (prevDim and [x1,y1,x2,y2] != prevDim and captured):        captured = False        Si estamos grabando un video con un ROI antiguo...        Condicion 4        if (video):            video, start = stopVideo(video,info = "A new ROI is beeing created")    ROI en directo (se actualiza en cada frame)    liveROI = frame[y1:y2+1, x1:x2+1]    prevDim = [x1,y1,x2,y2]        ...```La siguiente tarea a realizar en la iteración es la comprobación de las teclas pulsadas. Con la tecla 'c' se comenzaría el proceso de captura y asignaríamos a ```staticROI``` la porción de imagen seleccionada. En esta iteración, ```liveROI``` y ```staticROI``` harían referencia a la misma subimagen, pero la diferencia clave es que ```liveROI``` se actualiza con cada frame (en cada iteración), mientras que ```staticROI``` solo cambia de valor si se vuelve a capturar.Con la tecla 'x' detenemos la captura, por lo que borramos el ROI estableciendo sus dimensiones a valores vacíos y detenemos cualquier vídeo que pueda estar grabándose en el momento.```python    ...        if key == ord('c') or key == ord('C'):        Si se captura, guardamos el estado del ROI en ese instante en staticROI y activamos el flag        captured = True        ROI estatico (solo guarda la imagen del ROI en el instante de la captura)        staticROI = frame[y1:y2+1, x1:x2+1]            if key == ord('x') or key == ord('X'):        Si eliminamos el ROI, desactivamos el flag        region.roi = []        captured = False        Si estabamos grabando, detenemos el video        Condicion 3        if (video):            video, start = stopVideo(video, info = "'X' key pressed, stopping capture")    Dibujamos el ROI en la imagen y sus dimensiones    cv.rectangle(frame, (x1,y1), (x2,y2), color=(0,255,255), thickness=2)    putText(frame, f'{x2-x1+1}x{y2-y1+1}', orig=(x1,y1-8))        ...```El siguiente paso sería el cálculo de la diferencia entre ```liveROI``` y ```staticROI```, en caso de que el proceso de captura esté iniciado. El valor calculado ```diff``` no es más que la media de la diferencia absoluta entre cada par de pixels de ambos ROIs. Este valor es el que se comparará con el umbral ```THRES``````python    ...        if(captured):        Calculo de la diferencia media        putText(frame, "Watching...", orig=(x1,y2+15))        imgDiff = cv.absdiff(liveROI,staticROI)        diff = np.mean(imgDiff)        MD = Mean Difference        putText(frame, "MD =" + str(round(diff,2)), orig=(x1,y2+30))                ...```Si el valor calculado es igual o superior al umbral, se considerará una anomalía. El siguiente código se hace las comprobaciones debidas para determinar cuándo iniciar y detener una grabación. En este caso dependerá de si el tiempo que llevemos grabado supera el máximo establecido ```TIME```. En el caso de que no se supere el umbral, se considerará que la anomalía ha desaparecido y se detendrá el vídeo si procede.````python        ...            if (diff >= THRES):            putText(frame, "ANOMALY DETECTED", orig=(x1,y2+45))            Si ya se estaba grabando un video (video != 0) y han pasado 3 segundos...            Condicion 2            if (video and time() - start >= TIME):                video, start = stopVideo(video,TIME)            Si no se esta grabando (start == 0)            else:                if (video == 0):                    video, start = startVideo()                else:                    video.write(frame)                    Si no hay anomalias Y hay un video en marcha...        Condicion 1        elif (video):            video, start = stopVideo(video, info = "Anomaly gone")                         ...```` A continuación queda el código completo para su ejecución:<jupyter_code>'''

SI SE CONSIDERA EL PARSER, HACER LAS SIGUIENTES SUSTITUCIONES
THRES -> args.thres
TIME -> args.time

'''

for key, frame in autoStream():
    #Si en el frame hay especificado un ROI...
    if region.roi:
        #Recogemos datos del ROI (puntos del rectangulo)
        [x1,y1,x2,y2] = region.roi
        
        #Si estamos creando un nuevo ROI distinto del anterior ya capturado...
        if (prevDim and [x1,y1,x2,y2] != prevDim and captured):
            captured = False
            #Si estamos grabando un video con un ROI antiguo...
            #Condicion 4
            if (video):
                video, start = stopVideo(video,info = "A new ROI is beeing created")

        #ROI en directo (se actualiza en cada frame)
        liveROI = frame[y1:y2+1, x1:x2+1]

        if key == ord('c') or key == ord('C'):
            #Si se captura, guardamos el estado del ROI en ese instante en staticROI y activamos el flag
            captured = True
            #ROI estatico (solo guarda la imagen del ROI en el instante de la captura)
            staticROI = frame[y1:y2+1, x1:x2+1]
        
        if key == ord('x') or key == ord('X'):
            #Si eliminamos el ROI, desactivamos el flag
            region.roi = []
            captured = False
            #Si estabamos grabando, detenemos el video
            #Condicion 3
            if (video):
                video, start = stopVideo(video, info = "'X' key pressed, stopping capture")

        #Dibujamos el ROI en la imagen y sus dimensiones
        cv.rectangle(frame, (x1,y1), (x2,y2), color=(0,255,255), thickness=2)
        putText(frame, f'{x2-x1+1}x{y2-y1+1}', orig=(x1,y1-8))
        
        
        # Graba siempre un maximo de TIME segundos de anomalia
        # Si la anomalia dura mas, para la grabacion y comienza otra
        if(captured):
            #Calculo de la diferencia media
            putText(frame, "Watching...", orig=(x1,y2+15))
            imgDiff = cv.absdiff(liveROI,staticROI)
            diff = np.mean(imgDiff)
            #MD = Mean Difference
            putText(frame, "MD =" + str(round(diff,2)), orig=(x1,y2+30))

            #Si hay una anomalia...
            if (diff >= THRES):
                putText(frame, "ANOMALY DETECTED", orig=(x1,y2+45))
                #Si ya se estaba grabando un video (video != 0) y han pasado 3 segundos...
                #Condicion 2
                if (video and time() - start >= TIME):
                    video, start = stopVideo(video,TIME)
                #Si no se esta grabando (start == 0)
                else:
                    if (video == 0):
                        video, start = startVideo()
                    else:
                        video.write(frame)
            
            #Si no hay anomalias Y hay un video en marcha...
            #Condicion 1
            elif (video):
                video, start = stopVideo(video, info = "Anomaly gone")
                
        #Guardamos las dimensiones de este ROI para compararlas en el siguiente frame
        prevDim = [x1,y1,x2,y2]

    h,w,_ = frame.shape
    putText(frame, f'{w}x{h}')
    cv.imshow('input',frame)

cv.destroyAllWindows()
#Condicion 5
if (video):
    stopVideo(video, info = "Exiting program")<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.08866267775273914, 'fraction_numerical': 0.013287745745590178, 'mean_word_length': 2.938188494492044, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '631592', 'license': 'BSD-3-Clause', 'n_tokens_mistral': 4072, 'n_tokens_neox': 3946, 'n_words': 1620, 'path': 'MIS NOTEBOOKS/ACTIVIDAD.ipynb', 'repo_name': 'ctm1098/umucv', 'size': '12869'}