ANIMACIONES CON OPENCV – Python | Especial por los 5K suscriptores ❤️

Por Administrador

Hace poquito el canal OMES ha superado los 5000 suscriptores, por lo cual estoy muy contenta. Ha pasado más de un año desde que cree el canal y no pensé que podría alcanzar tantos grandiosos suscriptores. Estoy muy agradecida, ya que no solo apoyan al canal con las vistas o likes, sino que también la comunidad deja sus consejos, sugerencias y buena vibra. ¡Son lo máximo!.

Es por eso que para celebrar a los 5K, he querido realizar un videotutorial y post un poquito diferente. Hoy vamos a realizar tres animaciones y almacenaremos estas en un video, todo esto con ayuda de OpenCV y Python. Así que si te parece interesante, ¡vamos con el código!.

CONTENIDO

  • Leyendo las imágenes de entrada
  • ANIMACIONES USANDO OPENCV Y PYTHON
    • Desplazamiento de los dígitos hacia abajo
      • ¡Vamos con el 5!
      • ¡Vamos con los ceros!
    • La imagen aparece poco a poco
    • Un corazón latiendo

Leyendo las imágenes de entrada

Vamos a crear un script llamado animacion.py y empezaremos con las siguientes líneas:

import cv2
import numpy as np

salida = cv2.VideoWriter('videoSalida.avi',cv2.VideoWriter_fourcc(*"MJPG"),30,(1280,720))

imagen = 255*np.ones(shape=(720,1280,3),dtype=np.uint8)

Línea 1 y 2: Importamos OpenCV y numpy.

Línea 4: Ya que vamos a almacenar un video, debemos emplear cv2.VideoWriter, y en el especificamos el nombre del video de salida, el codec, fps y su dimensión. Para más información puedes visitar Capturar, guardar y leer un video en OpenCV y Python

Línea 6: Creamos nuestro lienzo en blanco, es decir mediante np.ones creamos una matriz de unos, de 720 filas, 1280 columnas y 3 canales. Dado que esta imagen está multiplicada por 255, la imagen se visualizará en blanco.

Procedemos a leer las imágenes que vamos a utilizar:

cinco = cv2.imread('cinco.png')
filas_cinco = cinco.shape[0]
col_cinco = cinco.shape[1]

Línea 8 a 10: Leemos la imagen cinco.png y en las siguientes líneas obtenemos el número de filas y columnas de dicha imagen.

Figura 1: Imagen de entrada llamada cinco.png

cero = cv2.imread('cero.png')
filas_cero = cero.shape[0]
col_cero = cero.shape[1]

Línea 12 a 14: Leemos la imagen cero.png y en las siguientes líneas obtenemos el número de filas y columnas de dicha imagen.

Figura 2: Imagen de entrada llamada cero.png

suscriptores = cv2.imread('suscriptores.png')
filas_suscriptores = suscriptores.shape[0]
col_suscriptores = suscriptores.shape[1]

Línea 16 a 18: Leemos la imagen suscriptores.png y en las siguientes líneas obtenemos el número de filas y columnas de dicha imagen.

Figura 3: Imagen de entrada llamada suscriptores.png

corazon = cv2.imread('corazon.png')
filas_corazon = corazon.shape[0]
col_corazon = corazon.shape[1]

Línea 20 a 22: Leemos la imagen corazon.png y en las siguientes líneas obtenemos el número de filas y columnas de dicha imagen.

Figura 4: Imagen de entrada llamada corazon.png

ANIMACIONES USANDO OPENCV Y PYTHON

Desplazamiento de los dígitos hacía abajo

Ahora vamos con la primera animación, haremos que cada dígito de 5000 aparezca de la parte superior y baje hasta el centro.

¡Vamos con el 5!

En un principio aparecerá el número 5 y se desplazará hacia abajo, por lo que usaremos las siguientes líneas:

#----- Visualiza 5000 (bajan desde la parte superior) -----
for i in np.arange(0,150,4):
    n_imagen1 = imagen.copy()
    n_imagen1[i:i+filas_cinco,320:320+col_cinco] = cinco
    salida.write(n_imagen1)
    cv2.imshow('Imagen',n_imagen1)
    cv2.waitKey(10)

Línea 25: Usamos un for para que i obtenga valores de entre 0 y 150 en intervalos de 4.

Línea 26: Hacemos una copia de imagen, la cual almacenaremos en n_imagen1. Esto nos servirá para crear el desplazamiento hacía abajo sin que se sobreescriban las imágenes.

Línea 27: Tomamos una porción de n_imagen1. En las filas de dicha porción irá de i, hasta i más el número de filas de la imagen correspondiente al cinco, mientras que en columnas lo ubicamos en la posición 320 a 320 más el número de columnas de la imagen del cinco. Esto lo igualamos a la imagen almacenada en cinco.

Línea 28: Añadimos la imagen n_imagen1 al video de salida.

Línea 29 y 30: Visualizamos n_imagen1 y en cv2.waitKey añadimos 10 o más, para que la visualización no se vea muy acelerada.

Figura 5: Visualización del movimiento del número 5.

¡Vamos con los ceros!

El proceso para visualizar los ceros es similar al del número cinco, veamos:

for i in np.arange(0,140,4):
    n_imagen2 = n_imagen1.copy()
    n_imagen2[i:i+filas_cero,480:480+col_cero] = cero
    salida.write(n_imagen2)
    cv2.imshow('Imagen',n_imagen2)
    cv2.waitKey(10)

for i in np.arange(0,140,4):
    n_imagen3 = n_imagen2.copy()
    n_imagen3[i:i+filas_cero,635:635+col_cero] = cero
    salida.write(n_imagen3)
    cv2.imshow('Imagen',n_imagen3)
    cv2.waitKey(10)

for i in np.arange(0,140,4):
    n_imagen4 = n_imagen3.copy()
    n_imagen4[i:i+filas_cero,790:790+col_cero] = cero
    salida.write(n_imagen4)
    cv2.imshow('Imagen',n_imagen4)
    cv2.waitKey(10)

Línea 32: Usamos un for para que i obtenga valores de entre 0 y 140 en intervalos de 4.

Línea 33: Hacemos una copia de n_imagen1, la cual almacenaremos en n_imagen2. Esto nos servirá para crear el desplazamiento hacía abajo sin que se sobreescriban las imágenes, y además usamos n_imagen1, que es la imagen resultante del proceso anterior.

Línea 34: Tomamos una porción de n_imagen2. En las filas de dicha porción irá de i, hasta i más el número de filas de la imagen correspondiente al cero, mientras que en columnas lo ubicamos en la posición 480 más el número de columnas de la imagen del cero. Esto lo igualamos a la imagen almacenada en cero.

Línea 35: Añadimos la imagen n_imagen2 al video de salida.

Línea 36 y 37: Visualizamos n_imagen2 y en cv2.waitKey añadimos 10 o más, para que la visualización no se vea muy acelerada.

Líneas 39 a 51: Realizamos el mismo procedimiento para los demás ceros, la única diferencia radica en la ubicación que tomarán estos dos últimos en cuanto a las columnas que serían 635 y 790 respectivamente.

Como vemos, en este proceso lo que se hace es reemplazar cierta área de una imagen principal por las imágenes con los dígitos cinco o cero. Además estas se actualizan en cada momento para dar el efecto de movimiento.

Figura 6: Visualización del movimiento de los ceros.

La imagen aparece poco a poco

Ahora vamos con la imagen correspondiente a la figura 3. En esta animación haremos que la imagen se muestre poco a poco, hasta que pueda verse perfectamente. Para ello vamos a usar la función cv2.addWeighted, que ya lo hemos visto en el tutorial: ADICIÓN y SUSTRACCIÓN de imágenes con OpenCV y Python

#----- Visualiza ¡Suscriptores! (Aparece poco a poco) -----
for i in np.arange(0.3,1,0.03):
    crop_n_imagen4 = n_imagen4[428:428 + filas_suscriptores, 260:260 + col_suscriptores]
    n_imagen4[428:428 + filas_suscriptores, 260:260 + col_suscriptores] = cv2.addWeighted(suscriptores,i,crop_n_imagen4,0.9,0)
    salida.write(n_imagen4)
    cv2.imshow("Imagen",n_imagen4)
    cv2.waitKey(10)

Línea 54: Usamos un for para que i obtenga valores de entre 0.3 y 1 en intervalos de 0.03.

Línea 55: Tomamos una porción de la n_imagen4 (que era el resultado de la animación anterior). Esta porción debe tener el mismo ancho y alto de la imagen de la figura 3.

Línea 56: Vamos a usar cv2.addWeighted para mezclar la imagen de suscriptores con la imagen fondo crop_n_imagen4. El valor de alfa se asigna a i para que conforme este incremente, se visualice mejor la imagen contenida en suscriptores.  Luego empleamos un beta de 0.9 ya que si especificamos 1, pues no obtendremos mezcla porque se visualizará siempre en blanco. 

Línea 57: Añadimos la imagen n_imagen4 al video de salida.

Línea 58 y 59: Visualizamos n_imagen2 y en cv2.waitKey añadimos 10 o más, para que la visualización no se vea muy acelerada.

Veamos como se vería el proceso de aparición:

Figura 7: Visualización de ¡suscriptores!.

Un corazón latiendo

Si bien el corazón se dilata y se contrae, se podría plantear la animación para que tenga un tamaño, que disminuya y vuelva a ganar tamaño. Por ahora no haremos esa animación, sino que haremos que se visualice el corazón y desaparezca en un mismo número de fotogramas, veamos:

#----- Visualiza el corazón (Latidos en encendido y apagado) -----
j = 0
for i in range(200):
    n_imagen5 = n_imagen4.copy()
    if j <= 10:
        n_imagen5[440:440+filas_corazon,865:865+col_corazon] = corazon
    if j > 20:
        j = 0
    j = j + 1

    salida.write(n_imagen5)
    cv2.imshow('Imagen',n_imagen5)
    cv2.waitKey(10)

salida.release()
cv2.waitKey(0)
cv2.destroyAllWindows()

Línea 62: Declaramos j e igualamos a 0, esta nos servirá como contador más adelante.

Línea 63: Usamos un for para que i tome valores con un rango de hasta 200.

Línea 64: Hacemos una copia de n_imagen4, la cual almacenaremos en n_imagen5. Esto nos servirá para crear el efecto de latido del corazón (tipo encendido y apagado) sin que se sobreescriban las imágenes, y además usamos n_imagen4, para usar la imagen resultante del proceso anterior.

Línea 65 y 66: Cuando j sea menor igual a 10, entonces tomaremos una porción de n_imagen5 que estará ubicada casi al final de la sección donde se encuentra la imagen de la figura 3.

Línea 67 y 68: Cuando j sea mayor a 20, se iguala j=0.

Línea 69: j se incrementa en 1.

Línea 71: Añadimos la imagen n_imagen5 al video de salida.

Línea 72 y 73: Visualizamos n_imagen5 y en cv2.waitKey añadimos 10 o más, para que la visualización no se vea muy acelerada.

Este proceso con ayuda del contador j nos servirá para que en 10 fotogramas seguidos se visualice el corazón y en otros días no se visualice, y así dar el efecto de latidos.

Líneas 75 a 77: Finalizamos la grabación del video, añadimos cv2.waitKey(0) para que el proceso termine cuando se presione alguna tecla y se cierren las ventanas de visualización.

Figura 8: Visualización de la animación correspondiente al corazón.

Y hemos llegado al final del tutorial. Nuevamente quiero agradecer el apoyo que le están dado al canal, al blog y en general al contenido que realizo, son una comunidad magnífica. ¡Un abrazo grande y nos vemos en el siguiente tutorial!