Potente cálculo de mapas de calor con CAS

Potente cálculo de mapas de calor con CAS


Esta publicación describe cómo generar mapas de calor en CAS utilizando la acción del paso DATOS para calcular histogramas 2D y el conjunto de acciones Imagen para el procesamiento posterior. El algoritmo de este ejemplo es una aplicación práctica de uno de los casos de uso presentados en una publicación anterior. En esta publicación, sugerimos usar mapas de calor como una forma de anonimizar a las personas que están siendo observadas por una cámara de vigilancia.

Además de la protección de datos, este ejemplo no solo utiliza mapas de calor como herramienta de anonimización, sino que también saca conclusiones sobre el uso de un entorno. En particular, identificamos zonas de alto tráfico. El código fuente completo está disponible en GitHub.

Descripción general de la canalización de procesamiento de imágenes

Para esta aplicación, los datos de seguimiento de movimiento se recopilaron por separado de los cálculos del mapa de calor. Los mapas de calor recopilaron datos de seguimiento durante una ventana de tiempo especificada por el usuario, como cinco minutos, y con una resolución especificada por el usuario. La tubería de procesamiento para los cálculos del mapa de calor fue:

  1. Cargue los datos de seguimiento de movimiento y la imagen base
  2. Preprocesamiento:
    • Convierta las coordenadas del cuadro delimitador de los objetos seguidos en una coordenada centroide
    • Filtrar los centroides que quedan fuera del límite de la imagen
    • Agrupe las coordenadas del objeto rastreado por ventana de tiempo
  3. Cálculo de histogramas 2D con resolución NxN
  4. Postprocesamiento:
    • Transforme los datos del histograma en una imagen dimensional NxNx1
    • Normalice y escale los valores bin del histograma a enteros de 8 bits
    • Cambie el tamaño de la imagen NxNx1 al alto y ancho de la imagen base
  5. Superponer el mapa de calor en la imagen base

La canalización se puede visualizar a continuación:

Figura 1: Pipeline de generación de mapas de calor

Los detalles de los datos están cargados

Los datos de seguimiento de movimiento para este algoritmo se almacenaron en un archivo CSV. El archivo tiene columnas para el número de imagen (incrustado en un nombre de archivo de imagen) y las coordenadas de las esquinas superior izquierda e inferior derecha del cuadro delimitador de los objetos rastreados. La acción loadTable se encarga de cargar el archivo CSV por nosotros.

También querremos cargar la imagen base en este punto. Las dimensiones de la imagen base se utilizan en el procesamiento posterior para filtrar los objetos rastreados que salen del límite de la imagen. Para hacer esto, podemos usar la acción loadImages.

Consulte la sección «Cargar datos de seguimiento e imagen base» de Jupyter Notebook en GitHub para ver cómo se usaron estas dos acciones.

Detalles de preprocesamiento

El procesamiento previo se realizó con una llamada al conjunto de acciones DATA Step. El procesamiento previo se necesita principalmente para asignar una ID de intervalo de tiempo. Esto está determinado por un intervalo especificado por el usuario. También asigna la velocidad de fotogramas a la que se capturaron las imágenes. En esta primera pasada de los datos se realizan algunos otros cálculos simples de preprocesamiento. Convertir las coordenadas del cuadro delimitador de cada objeto en una coordenada de centroide y luego filtrar todos los centroides que salen del límite de la imagen.

   preprocessed_data = s.CASTable('preprocessed_data', replace=True)
   response = s.datastep.runcode(
       code=f'''data preprocessed_data;
                set tracking_data;
 
                /* Calculate centroids from the top-left and bottom-right bounding box coordinates. */
                cx = BRx/2 + TLx/2;
                cy = BRy/2 + TLy/2;
 
                /* Filter out any centroids that leave the image boundary. */
                if cx >= 0 and cx < {width} and cy >= 0 and cy < {height} then do;
 
                    /* Parse the frame number from the filename and then calculate the time window ID based on
                       the frame number, framerate, and window length (in minutes). */
                    time_window_id = floor((int(scan(filename,-2,'_./'))-1) / {heatmap_window_minutes*60*framerate});
 
                    output; 
                end;
             run;
   ''')

Detalles sobre cómo se calcula el histograma 2D

El conjunto de acciones DATA Step se usa nuevamente, pero esta vez para calcular histogramas 2D. Al calcular el histograma, vale la pena recordar algunos matices importantes:

  1. Usamos la declaración ID BY de intervalo de tiempo para garantizar que cada histograma corresponda a un intervalo de tiempo específico
  2. Los objetos rastreados se califican en el histograma 2D, con grados de histograma que van de 0 a N-1
  3. El tipo de matriz 2D utilizado en el paso DATA se reduce automáticamente a una tabla ancha

El binning del histograma 2D se puede visualizar en la Figura 2. En este ejemplo, una imagen de 300×300 píxeles se convierte en un histograma 2D de 3×3. El histograma 2D de 3×3 eventualmente se aplana en una sola fila con nueve columnas. En el ejemplo, un objeto rastreado se detecta en la ubicación del píxel (205, 95) y se coloca en la fila 1, columna 3 del histograma 2D (mostrado en azul claro). Después de aplanar, la fila 1, la columna 3 del histograma 2D se convierte en la columna 3 en la tabla de salida que se muestra a la derecha.

Figura 2: Paso de DATOS del histograma 2D visualizado

El cálculo del histograma 2D que se muestra en la Figura 2 se implementó mediante el paso de DATOS que se muestra a continuación.

   total_num_bins = heatmap_resolution*heatmap_resolution
   pixels_per_bin = width/heatmap_resolution
 
   histograms = s.CASTable('histograms', replace=True)
   response = s.datastep.runcode(
       code=f'''data histograms (keep=c01-c{total_num_bins} time_window_id);
                 set preprocessed_data;
 
                 /* Process by time_window_id to get one histogram per time interval.*/
                 by time_window_id;
 
                 /* Create histogram bins and instruct DATA step to retain values between rows.*/
                 array histogram_bins{{{heatmap_resolution},{heatmap_resolution}}} c01-c{total_num_bins};
                 retain histogram_bins;
 
                 /* 'Bin' the centroid coordinates.*/
                 x = floor(cx/{pixels_per_bin})+1;
                 y = floor(cy/{pixels_per_bin})+1;
 
                 /* Increment the histogram bin values based on the binned coordinates.*/
                 if histogram_bins{{y,x}}=. then histogram_bins{{y,x}}=1;
                 else histogram_bins{{y,x}}=histogram_bins{{y,x}}+1;
 
                 /* When all observations in a time window are processed, write the result to the output table.*/
                 if last.time_window_id then output;
             run;
   ''')

Detalles de posprocesamiento

Una ventaja clave de usar el paso DATA para el histograma 2D fue que el histograma se convirtió en una tabla ancha sin costo alguno durante los cálculos. Esto es importante porque el conjunto de acciones Imagen tiene una acción, condensar imágenes, que convierte una tabla ancha en una sola columna de imágenes. Esto se puede usar dentro del conjunto de acciones de imagen.

En el procesamiento posterior que se muestra en la Figura 3, usamos la acción condenseImages para convertir una tabla ancha en una imagen. Luego, la acción procesarImages se usa para preparar los valores bin del histograma para usarlos como una imagen, antes de finalmente cambiar el tamaño del histograma para que se ajuste a nuestra imagen base. Para visualizar el uso del café, queremos un mapa de calor espacial con una magnitud que varíe continuamente. Para lograr esto, el paso de cambio de tamaño utiliza interpolación bilineal al transformar la imagen NxNx1 al tamaño de imagen base.

La canalización se muestra a continuación. El código fuente de esta sección se encuentra en la sección Posprocesamiento del cuaderno Jupyter mencionado anteriormente.

Figura 3: posprocesamiento de histogramas 2D

Detalles de superposición de mapas de calor

En esta etapa de la canalización, tenemos una tabla de mapas de calor que corresponden a cada intervalo de tiempo especificado por el usuario. La acción annotateImages del conjunto de acciones de imagen se puede usar para superponer estos mapas de calor sobre la imagen base. Sin embargo, primero se debe conectar la tabla de mapas de calor a la imagen base. Usamos el conjunto de acciones de fedSQL para realizar la combinación de tablas. Consulte la sección «Superposición del mapa de calor en la imagen base» en GitHub para ver el código de este paso. El diagrama de la Figura 4 ilustra la secuencia de superposición.

Superposiciones de mapas de calor en la imagen base

Figura 4: Mapas de calor superpuestos en la imagen base

rendimiento

Se realizaron comparaciones entre una implementación de Python (usando OpenCV y NumPy para procesamiento de imágenes y cálculos de histogramas 2D) y la versión CAS descrita aquí. Todas las pruebas se repitieron cinco veces y se informaron los tiempos de ejecución promedio.

Para la primera prueba, se realizaron comparaciones manteniendo constante la resolución del histograma 2D (en N=13) y variando el tamaño de la ventana de tiempo del mapa de calor. La figura 5 muestra una comparación de la implementación básica de Python y la versión CAS que se ejecuta tanto en modo de máquina única (SMP) como en modo distribuido (MPP). La figura 6 solo amplía la versión CAS.

Tiempos de ejecución frente a minutos por mapa de calor

Figura 5: Prueba 1, tiempos de ejecución frente a la duración de la ventana (minutos)

Tiempos de ejecución frente a minutos por mapa de calor

Figura 6: Prueba 1, tiempos de ejecución frente a la duración de la ventana (minutos), solo CAS

Mirando la Figura 5, el algoritmo se ejecuta unas 5 veces más rápido en SMP-CAS y unas 10 veces más rápido en MPP-CAS que en la implementación básica de Python. La versión de Python tiene un tiempo de ejecución constante al variar la duración de la ventana de tiempo del mapa de calor porque puede asumir que todas las observaciones están bien y pueden procesarse secuencialmente. Los tiempos de ejecución de la implementación de CAS varían ligeramente debido a los matices en el procesamiento del grupo BY. Es decir, si se reduce la longitud de la ventana del mapa de calor, se deben procesar más ventanas y se agrega una sobrecarga adicional.

Para una segunda prueba, la ventana de tiempo del mapa de calor se mantuvo constante (a cinco minutos por mapa de calor) y se barrió la resolución del histograma 2D.

Figura 7: Prueba 2, tiempos de ejecución versus resolución de histograma 2D

Figura 8: Prueba 2, tiempos de ejecución versus resolución de histograma 2D, solo CAS

Una vez más, la implementación de SMP-CAS es entre 4 y 5 veces más rápida y entre 8 y 10 veces más rápida en el modo MPP. Al igual que en la primera prueba, vemos que la versión de Python es casi constante en el tiempo a medida que variamos la resolución del histograma. Esta vez, el tiempo de ejecución constante se debe al cálculo del histograma 2D utilizando estructuras de datos de matriz eficientes con tiempos de acceso O(1). Por el contrario, la implementación de CAS se escala ligeramente con la resolución, ya que los datos del histograma 2D se almacenan en una tabla ancha donde los accesos son O(n).

Conclusión

Los mapas de calor son una herramienta valiosa cuyos usos van desde la simplificación de datos, como en el caso de los análisis de preservación de la privacidad discutidos en una publicación anterior, hasta el ejemplo de visualización de datos destacado aquí en la aplicación de uso de café. Si bien los mapas de calor espaciales fueron más útiles para el ejemplo de la cafetería, muchas otras aplicaciones se benefician de diferentes tipos de mapas de calor, como:

Esta canalización de generación de mapas de calor demuestra cómo se puede usar el conjunto de acciones DATA Step para ampliar la funcionalidad del conjunto de acciones Imagen. En esta publicación solo se usó la acción condenseImages del conjunto de acciones de imagen. Sin embargo, las acciones flattenImages y condenseImages se pueden usar juntas para acoplar imágenes dentro y fuera de los formatos de imagen. Esto abre la puerta a cualquier acción CAS que se pueda aplicar a los datos de imagen.

Related post

A la vanguardia de la construcción con biología

A la vanguardia de la construcción con biología

Ritu Raman, profesor asistente de desarrollo profesional de ingeniería mecánica de d’Arbeloff, se centra en la construcción con biología utilizando células…
El programa interactivo de los científicos informáticos ayuda a planificar el movimiento para entornos con obstáculos – ScienceDaily

El programa interactivo de los científicos informáticos ayuda a…

Al igual que nosotros, los robots no pueden ver a través de las paredes. A veces necesitan un poco de ayuda…
Toma lecciones en realidad virtual con Immerse, una aplicación de voz para Quest 2

Toma lecciones en realidad virtual con Immerse, una aplicación…

En el metaverso, imagínese llegando tarde a la escuela. Bucear es una plataforma educativa de metaverso desarrollada en colaboración con los…

Leave a Reply

Tu dirección de correo electrónico no será publicada.