Como subir imágenes y videos a MongoDB con Python y GridFS.
Subir archivos multimedia a una base de datos, ¿Es posible? pues en este articulo veremos cómo lograrlo, así que comencemos...
Lo primero que debemos hacer es tener descargados, instalados y ejecutándose de forma correcta tanto Python, en nuestro caso es la versión 3.7.9, como Mongo DB, que es una base de datos no. Lo que haremos en código, es tomar la imagen de cualquier formato, ya sea un JPG, un PNG o cualquier otro, lo convertiremos en un bytes array y subiremos esa información a Mongo con ayuda de la librería GridFS, en este punto tendremos bytes alojados en Mongo, posteriormente consultaremos esa información en un equivalente a un SELECT de SQL, y reconstruiremos la imagen, solamente leyendo los bytes y también con ayuda de librerías para el procesamiento de imágenes como lo son CV2 y PILLOW.
Carga y consulta
Para empezar, debemos importar todos los módulos que necesitemos, estos se pueden instalar con el comando “pip install <nombre>”, estas librerías o módulos no son nada fuera de lo normal, así que es probable que ya las tengas instaladas.
# importaciones import base64 from pymongo import MongoClient import gridfs from io import BytesIO import numpy as np import matplotlib.pyplot as plt import cv2 from PIL import Image
Comencemos por importar base64, para la codificación y decodificación de las imágenes, luego pymongo para conectarnos a MongoDB, también importamos GridFS, que sirve para controlar la carga de multimedia, de io importamos BytesIO, que es para leer bytes, e importamos numpy, que siempre es necesario para el manejo de conjuntos de números y hacemos la referencia a matplotlib para graficar resultados. Como extras, importamos cv2 y también Image proveniente de PIL, que son para el manejo de imágenes.
Hechas las importaciones, procedemos a declarar algunas variables, el cliente de mongo, la referencia a la base de datos, la ruta de la imagen y una variable de texto que usaremos para hacer validaciones.
# Conexion client = MongoClient('localhost', 27017) database = client.image img = r'D:\Imágenes\Saved Pictures\AnyWall\Microsoft_WindowsInsider.PNG' fid = ""
Después, abrimos el archivo leyendo los bytes, y con ayuda de la librería base64, codificamos esa información, de tal forma que sea compatible con MongoDB, a esta referencia, le pasamos la variable con la ruta de la imagen. Hasta este punto, la imagen ya fue leída y codificada por base64. En este punto haremos la carga, por lo que declaramos una referencia con GridFS y le pasamos como parámetro la base de datos que usaremos, posteriormente subimos la información con la función put de GridFS, por último, conectamos esta carga con un insert y así saber que id le pertenece a que imagen.
# Lectura with open(img, "rb") as image_file: encoded_string = base64.b64encode(image_file.read()) # Carga de la imagen filename = "test" fs = gridfs.GridFS(database) fileid = fs.put(encoded_string, filename=filename) database.image.insert_one({"filename":filename,"fileid":fileid})
Hasta este punto los bytes ya estarán alojados en la base de datos. A continuación, comprobamos en Robo 3T un nuevo archivo en la base de datos "image" con nombre "test".
Ahora lo que tenemos que hacer es consultar esta información, para eso haremos el equivalente de un SELECT en MongoDB, con este resultado haremos la comprobación de que no este vacío y con ayuda de GridFS extraeremos la información (los bytes).
# Consulta for item in database.image.find({"filename":filename}): print(item) fid = item["fileid"] if fid != "": output = fs.get(fid).read() print(output)
Excelente, hasta este punto ya habremos completado todo el proceso de carga y consulta. Esto lo podemos comprobar ejecutando el archivo Python de distintas formas (por la línea de comandos o IDE).
Uso de librerías auxiliares
Para implementar las 2 librerías de apoyo que están hechas para el procesamiento y trato de imágenes, declararemos otro tipo de query, este es propio de GridFS, y no como el anterior que era propio de pymongo, en todo caso, el funcionamiento interno es prácticamente el mismo.
# Construccion de la imagen file = fs.find_one({"filename":filename}) bytedata = file.read()
Usando Pillow, habrá que decodificar los bytes de la consulta, para eso volvemos a usar base64, además debemos hacer una conversión de formatos, de ahí la necesidad de usar BytesIO, posteriormente, usando la función open de la clase Image, leeremos el contenido decodificado y solo resta mostrarlo con la función show.
# Pillow ima_IO = BytesIO(base64.b64decode(bytedata)) img_PIL = Image.open(ima_IO) img_PIL.show()
Como podemos observar, hemos logrado cargar la imagen directamente de los bytes de Mongo.
Para el caso de cv2, primero que nada, pasaremos los bytes a un formato de numpy, con el fin de normalizar la información de la consulta, luego habrá que usar la función imdecode de cv2 para convertir los bytes a una imagen, como preventivo usaremos la función cvtColor con el fin de que los colores sean los mismo que la imagen cuando la cargamos a MongoDB. Por último, haremos uso de matplotlib para mostrar dicha imagen, ya que cv2 no cuenta con una función show para mostrar contenido.
# CV2 data = np.frombuffer(base64.b64decode(bytedata), np.uint8) img_CV2 = cv2.imdecode(data, 3) img_CV2 = cv2.cvtColor(img_CV2, cv2.COLOR_BGR2RGB) plt.imshow(img_CV2) plt.show()
Ahora es el turno de los resultados con CV2.
Ya para finalizar, solo queda cerrar la referencia a la base de datos como buena práctica y esencial en ambientes de producción.
client.close()
Como pudimos observar a lo largo de este artículo, la carga de imágenes y en general de archivos a mongo resulta una practica no tan compleja, que con un solo archivo Python se puede resolver, esto resulta de gran utilidad para evitar el uso de un servidor FTP que almacene esa información, si no que directamente se puede hacer a través de Mongo y Python.
A continuación dejo un video explicando mas a detalle este proceso y además un repositorio en GitHub con el código.
Por su atención, muchas gracias.
Ingeniero en Sistemas Computacionales. en Instituto Tecnologico
4 años¡¡¡Excelente presentación!!!. Te felicito por el tema y el contenido.