Este post corresponde a la segunda parte de dos posts. Puedes leer la primera parte en PARTE-1, ésta ha repasado la descomposición de matrices usando Singular Vector Decomposition (SVD), randomized Singular Vector Decomposition (rSVD) y Nonnegative Matrix Factorization (NMF) principalmente para la compresión de imagenes.

Esta segunda parte, analizará cómo realizar la eliminación del fondo de vídeos mediante randomized SVD y robust PCA.

En este post por tanto, trataremos de reproducir la metodología y el proceso aprendido con python en el Capítulo 3: Background Removal with Robust PCA, del curso online gratuito: “Computational Linear Algebra for Coders” ofrecido gratuitamente por Fast.ai. Puedes obtener más información sobre el curso aquí. Todo el material original del curso Fast.ai está escrito en python y se puede descargar aquí. En este post intentaremos reproducir los mismos resultados utilizando el código R.

Utilizaré ejemplos claros sobre cómo utilizar SVD (Singular Value Decomposition), randomized SVD y robust PCA (Principal Component Analysis) aplicado a vídeo para eliminar el fondo de los vídeos cómo lo pueden ser los de videovigilancia.

Las partes principales del post incluyen la eliminación del fondo de:

  • Vídeo en blanco y negro utilizando SVD y robust SVD
  • Vídeo en blanco y negro utilizando Randomized robust PCA
  • Vídeo en color utilizando Randomized robust PCA

También puedes obtener ideas básicas sobre la SVD en mi post anterior.

 

Transformando el archivo de vídeo

En primer lugar, para trabajar con vídeo en R necesitamos instalar el paquete Rvision de Github, puedes ejecutar el código de abajo o seguir las instrucciones de Rvision_Github. Este paquete nos permitirá trabajar con archivos de vídeo.

Para este post, usaremos un archivo de video a color de 350 fotogramas video_example.mp4 que debe estar ubicado en el directorio de trabajo.

Las dimensiones del vídeo y el espacio de color se pueden obtener utilizando las siguientes funciones.

Cada fotograma de vídeo tiene una dimensión de 240 x 320 píxels, además hay 3 imágenes de 240 x 320 píxels para cada fotograma ya que el vídeo es en color y por lo tanto contiene 3 canales (RGB), uno para el canal Rojo, otro para el canal Verde, y el último para el canal Azul. Así, en total disponemos de 350 fotogramas x 3 canales (RGB) x 240 x 320 píxels = 80640000 valores numéricos.

Abajo puedes ver el vídeo con el qual trabajaremos.

A continuación, convertiremos cada fotograma en una escala de grises para simplificar el ejemplo (puedes encontrar el código para trabajar con vídeo a color al final de este post).

Después de eso, transformaremos cada fotograma de 240 x 320 píxels (escala de grises) en un vector largo de 240 x 320 = 76800 valores.

Lo haremos para todos los 350 fotogramas, así que tendremos un vector para cada fotograma.

Al final, combinaremos los vectores-fotogramas para obtener una matriz M de dimensiones: 76800 x 350, donde cada columna representa cada fotograma del vídeo.

La matriz en memoria ocupa:

En la secuencia For_Loop anterior, hemos convertido un vídeo en escala de grises (es decir, una matriz multidimensional de alto x ancho x fotogramas) en una matriz 2D. Veamos cómo se ve si pintamos esta matriz:

plot of chunk matrix_decomposition_part_2-10

En la imagen de arriba, el eje ‘y’ (alto x ancho) es enorme con respecto al eje ‘x’ (fotogramas). Así que no es posible visualizar correctamente la matriz 2D. Necesitamos usar la función rasterImage() para expandir el eje ‘x’ a lo largo de la pantalla.

Así, expandiendo esa matriz a lo largo del eje ‘x’, se observa más fácilmente la idea de movimiento del vídeo. En la imagen siguiente el eje `x’ representa el tiempo (cada fotograma), y el eje `y’ es la forma vectorizada de cada fotograma. Ahora puedes ver claramente el movimiento de la gente en el vídeo (las líneas parabólicas), y cómo el fondo que parece estar formado por líneas horizontales.

plot of chunk matrix_decomposition_part_2-11

Podemos comprobar la transformación invirtiendo el proceso para un fotograma específico, y así tratar de recuperar el fotograma número 250 transformando la columna 250 de la matriz M de vector a matriz. A continuación se muestra el ejemplo.

plot of chunk matrix_decomposition_part_2-12

Randomized SVD (video B/N)

Una vez que hemos aprendido a transformar un archivo de vídeo en una matriz 2D, ahora podemos aplicar métodos de descomposición de matrices (ver PARTE-1) para la eliminación del fondo de los vídeo.

Comenzaremos aplicando Randomized SVD en la matriz M, para este ejemplo usaremos el paquete rsvd con un valor de descomposición de bajo rango (low-rank decomposition) de k=2 sobre la matriz M.

The dimensions of the SVD decomposed matrices are:

Ahora, reconstruiremos el vídeo usando las matrices descompuestas U, D y V. Para ello aplicaremos la fórmula:

M_recovery = U · d · VT (ver PARTE-1 para más detalles)

Debido a que usamos un valor de bajo rango (k=2) no se espera que la matriz 2D reconstruida (M_recovery) coincida exactamente con la matriz 2D original (M). En lugar de eso, obtendremos una matriz que generaliza cada fotograma del vídeo y se centrará en los píxels estáticos de la matriz, en pocas palabras, ‘M_recovery’ se centrará en el fondo del vídeo, y evitará los objetos en movimiento.

Si dibujamos la reconstrucción de las matrices descompuestas vemos, en la siguiente imagen, que el resultado es que no hay movimiento:

plot of chunk matrix_decomposition_part_2-16

Como podemos ver, las dimensiones de la matriz 2D reconstruida rSVD_k2_re coinciden con la matriz M original:

Si mostramos un fotograma (por ejemplo el fotograma 250) de la matriz reconstruida, obtendremos una imagen con el fondo pero sin objetos o personas en movimiento (abajo a la izquierda de la imagen). También podemos restar la matriz reconstruida a la matriz original, para obtener así una imagen con sólo los objetos en movimiento o personas y sin el fondo (abajo a la derecha de la imagen).

plot of chunk matrix_decomposition_part_2-18

A continuación podemos realizar un pequeño análisis de lo que ocurre con los diferentes valores de k. Como se puede ver en las imágenes de abajo, el mejor valor para la eliminación del fondo de vídeo es k = 2, esto es porque no queremos obtener la matriz reconstruida igual a la matriz original, de hecho, queremos el efecto contrario, que se elimine el movimiento del fondo, puede ir a la PARTE-1 para más detalles sobre el valor k.

plot of chunk matrix_decomposition_part_2-19

Randomized robust PCA (video B/N)

Ahora vamos a realizar el mismo procedimiento pero en lugar de usar rSVD vamos a usar randomized robust principal component analysis. Ten en cuenta que existe una relación matemática entre el SVD y el Principal Component Analysis (PCA), pero no es el alcance de este post profundizar en esa relación, si estas interesado hay contenido muy bueno en Internet.

El Robust PCA descompone una matriz en dos matrices L y S, la suma de ellas da como resultado la matriz original:

M = L + S

  • M es la matriz original
  • L es la de bajo rango
  • S es la “sparse

El término low-rank significa que la matriz tiene mucha información redundante, así que en nuestro ejemplo ese es el fondo del vídeo, mientras que sparse se refiere a la matriz con la mayoría de las entradas cero, así que en nuestro ejemplo corresponde a el primer plano o la gente en movimiento (en el caso de datos de vídeo corruptos la matriz sparse captura los datos corruptos).

A continuación a la matriz de vídeo 2D  original M aplicaremos la función rrpca() del paquete rsvd.

A continuación, recuperaremos el mismo fotograma núm. 250 de la matriz reconstruida. En el lado izquierdo de la imagen de abajo, se puede observar la matriz de bajo rango L (fondo). En el lado derecho, está la matriz sparse S (movimiento).

plot of chunk matrix_decomposition_part_2-21

También podemos crear un archivo de vídeo si guardamos en un archivo la imagen de cada fotograma, esto se puede hacer fácilmente con una secuencia For-Loop. Luego sólo nos quedará juntar o empaquetar todos los archivos de imagenes en un único archivo de vídeo.mp4. Para ello se debe instalar ffmpeg, en MAC OSX es tan fácil como escribir en el Terminal:

Para Windows intenta buscar aquí.

Ejecutando el código de abajo crearemos las imágenes de los fotogramas y posteriormente el vídeo en blanco y negro:

A continuación encontrarás el vídeo descompuesto:

Randomized robust PCA (vídeo a color)

En código previamente mostrado, simplifica el problema ya que trabaja con vídeo en blanco y negro, intentemos añadir un nivel más de complejidad añadiendo el color a los vídeos!!!.

En este caso, tendremos una matriz 2D más alta, esto significa que la dimensión de la matriz será 350 x 230400, en lugar de 350 x 76800 del ejemplo B/N. Ten en cuenta que 230400 viene de 240 x 320 x 3 canales de color (RGB).

Podemos ver abajo el movimiento de las personas en la nueva matriz 2D de color, esta vez incluyendo el color!!.

plot of chunk matrix_decomposition_part_2-25

También podemos reconstruir cualquier fotograma de la matriz de vídeo 2D para comprobar que el proceso de transformación sea correcto.

plot of chunk matrix_decomposition_part_2-26

Finalmente, utilizaremos la función rrpca() para la versión a todo color de nuestra matriz. Esto creará el objeto rPCA_k2 que contendrá la matriz  low-rank y la matriz sparse.

A continuación, comprobamos como ha sido la eliminación de fondo y la separación de los objetos en primer plano para el mismo fotograma 250.

plot of chunk matrix_decomposition_part_2-28

Y finalmente, crearemos para la versión en color, un vídeo que incluya todos los fotogramas del vídeo original.

A continuación, puedes encontrar el vídeo final: video_decomposed_color.mp4.

Y hasta aquí hemos llegado al final de la PARTE-2.

Espero que haya sido interesante. Deja algunos comentarios u opiniones si quieres!

 


Session Info:

Appendix, all the code:

Share it!:

Leave a Reply

Your email address will not be published. Required fields are marked *