Aprende a implementar tu propio motor de búsqueda de imágenes autohospedado con Python 3 en Ubuntu 18.04 usando Tensorflow y Keras.


Los motores de búsqueda de imágenes analizan una imagen y hacen algunas preguntas básicas sobre ella, por ejemplo, ¿hay una cara en la imagen o más de 1? ¿Qué color aparece en la imagen y con qué frecuencia? Cual es la resolucion? Los buscadores pueden luego limitar su búsqueda en función de esta información. Seguramente este es un tema muy extenso que no explicaremos en profundidad, pero te explicaremos cómo implementar tu propio motor de búsqueda de imágenes con algunas herramientas que ya están listas para funcionar exactamente como lo necesitas, y si no es así. , por supuesto, puede modificarlo y adaptarlo a sus propias necesidades.

En este artículo, le explicaremos brevemente cómo puede implementar rápidamente su propio motor de búsqueda de imágenes usando Keras y Tensorflow con Python en Ubuntu 18.04.

Requisitos

Necesitarás tener Python 3 instalado en su sistema y Pip 3 también, puede instalarlos respectivamente en su sistema Ubuntu con:

sudo apt-get install python3

Y Pip con:

sudo apt-get install python3-pip

Habiendo dicho eso, ¡comencemos!

1. Clonar el proyecto SIS e instalar dependencias

Para implementar su propio motor de búsqueda de imágenes local utilizando las tecnologías mencionadas, confiaremos en un proyecto de código abierto llamado SIS. El motor de búsqueda de imágenes simple es un motor de búsqueda de imágenes escrito desde cero por @ matsui528 , es profesor asistente en el Instituto de Ciencias Industriales de la Universidad de Tokio, Japón.

Para comenzar, clona el código fuente del proyecto con Git usando el siguiente comando en tu terminal (si no tienes git, instálalo previamente con sudo apt-get install git):

git clone https://github.com/matsui528/sis.git

El proyecto es muy ligero inicialmente, ya que contiene solo 62 líneas (python) + 24 líneas (html). Después de clonar el código fuente, cambie al directorio sis con:

cd sis

Y proceda con la instalación de las dependencias del proyecto usando Pip. Puede instalarlos desde la lista proporcionada por el proyecto con:

pip3 install -r requirements.txt

Esto instalará 5 dependencias:

  • Pillow : Pillow es el simpático tenedor PIL de Alex Clark and Contributors. PIL es la biblioteca de imágenes de Python de Fredrik Lundh y colaboradores.
  • h5py : El paquete h5py es una interfaz Pythonic para el formato de datos binarios HDF5. Le permite almacenar grandes cantidades de datos numéricos y manipular fácilmente esos datos desde NumPy.
  • tensorflow : la biblioteca central de código abierto para ayudarlo a desarrollar y entrenar modelos de AA. Comience rápidamente ejecutando los cuadernos de Colab directamente en su navegador.
  • Keras : Keras es una API de redes neuronales de alto nivel, escrita en Python y capaz de ejecutarse sobre TensorFlow, CNTK o Theano. Fue desarrollado con un enfoque en permitir una experimentación rápida. 
  • Flask : Flask es un microframework para Python basado en Werkzeug, Jinja 2 y buenas intenciones. Se usará para mostrar resultados gráficos del buscador, por lo que cuando subas un archivo se analizará y te devolverá las imágenes que coincidan con tu búsqueda.

Para obtener más información sobre este proyecto, visite el repositorio oficial en Github aquí .

2. Almacena tus imágenes

Ahora que el proyecto se ha descargado e instalado todas las dependencias, podemos continuar con un trabajo manual. Dentro de la estructura del proyecto, necesitará almacenar las imágenes de su "base de datos de imágenes" que serán, por así decirlo, comparadas con la imagen de la consulta.

Almacena todas las imágenes que quieras tener como referencia, y que el usuario podrá buscar, dentro del directorio /sis/static/img. Todas las imágenes deben estar en formato JPEG:

Picture Storage Static Keras Tensorflow Image Search Engine

Este paso depende totalmente de ti, tú serás quien decida la información y tipo de imágenes que tu proyecto podrá ofrecer. Una vez que los tenga, podremos extraer la información en el siguiente paso.

3. Genere archivos PKL de cada imagen

Este script extrae características profundas de las imágenes. Dado un conjunto de imágenes de base de datos, se extrae una función 4096D fc6 para cada imagen utilizando la red VGG16 con pesos pre-entrenados de ImageNet. Para generar los archivos pkl, ejecute el script offline.py en el directorio raíz de sis con python:

python3 offline.py

Debido a su profundidad y cantidad de nodos completamente conectados, VGG16 tiene más de 533 MB. Esto se descargará una vez que ejecute el script por primera vez.

Después de ejecutar el script, encontrará nuevos archivos binarios con información sobre las imágenes. Esta información extraída por la clase FeatureExtractor (Keras Models) se serializará usando  pickle en archivos binarios PKL en el directorio /sis/static/feature:

PKL Files Keras Tensorflow

Tensorflow los usará para hacer coincidir su consulta de imagen en la lógica de fondo.

4. Prueba con una interfaz web

Ahora, como se mencionó durante la instalación de las dependencias, el proyecto viene con un ejemplo listo para usar basado en una interfaz web que ha sido construida usando Flask. Esta interfaz (que es básicamente una página HTML simple con una sola entrada de archivo y algunos títulos) te permitirá subir un archivo a la misma página y te devolverá como resultado, imágenes relacionadas con tu búsqueda. Puede iniciar el servidor ejecutando el script server.py:

python3 server.py

Esto iniciará la demostración en http://0.0.0.0:5000  y podrás probarla (siempre que ya tenga algunas imágenes en su base de datos):

Simple Image Search Engine

La lógica en el fondo clasifica una imagen con un valor de incertidumbre, como puede ver en el ejemplo, cuanto más cercano sea el valor a 1 y menor, mejor coincidencia es.

Lógica personalizada

Por supuesto, como el proyecto es de código abierto, puede modificar la forma en que funciona. Simplemente puede crear también un script de Python que imprima solo los datos que necesita en la terminal, el orden de los elementos que coinciden con la consulta, etc. Por ejemplo, cree el siguiente archivo custom.pycon el siguiente contenido:

# Our Code World custom implementation
# Read article at: 
# https://ourcodeworld.com/articles/read/981/how-to-implement-an-image-search-engine-using-keras-tensorflow-with-python-3-in-ubuntu-18-04
import os
import numpy as np
from PIL import Image
from feature_extractor import FeatureExtractor
import glob
import pickle
import json

if __name__=="__main__":
    fe = FeatureExtractor()
    features = []
    img_paths = []

    # Append every generated PKL file into an array and the image version as well
    for feature_path in glob.glob("static/feature/*"):
        features.append(pickle.load(open(feature_path, 'rb')))
        img_paths.append('static/img/' + os.path.splitext(os.path.basename(feature_path))[0] + '.jpg')

    # Define the query image, in our case it will be a hamburguer
    img = Image.open("/home/ourcodeworld/Desktop/hamburguer_query.jpg")  # PIL image

    # Search for matches
    query = fe.extract(img)
    dists = np.linalg.norm(features - query, axis=1)  # Do search
    ids = np.argsort(dists)[:30] # Top 30 results
    scores = [(dists[id], img_paths[id]) for id in ids]

    # Store results in a dictionary
    results = []

    for item in scores:
        results.append({
            "filename" : item[1],
            "uncertainty": str(item[0])
        })

    # Create a JSON file with the results
    with open('data.json', 'w') as outputfile:
        json.dump(results, outputfile, ensure_ascii=False, indent=4)

Y ejecutarlo con:

python3 custom.py

Esto creará un archivo JSON con una lista ordenada de las imágenes que parece coincidir con su consulta, en nuestro ejemplo buscamos con una hamburguesa y como puede ver, los primeros elementos son imágenes de hamburguesas:

[
    {
        "filename": "static/img/hamburguer_4.jpg",
        "uncertainty": "0.95612574"
    },
    {
        "filename": "static/img/hamburguer_2.jpg",
        "uncertainty": "1.0821809"
    },
    {
        "filename": "static/img/hamburguer_3.jpg",
        "uncertainty": "1.099425"
    },
    {
        "filename": "static/img/hamburguer.jpg",
        "uncertainty": "1.1565413"
    },
    {
        "filename": "static/img/hot_dog2.jpg",
        "uncertainty": "1.1644002"
    },
    {
        "filename": "static/img/hot_dog_5.jpg",
        "uncertainty": "1.2176604"
    },
    {
        "filename": "static/img/portrait-if-a-spitz-pomeranian_t20_v3o29E-5ae9bbdca18d9e0037d95983.jpg",
        "uncertainty": "1.262754"
    },
    {
        "filename": "static/img/smiley_dog.jpg",
        "uncertainty": "1.3276863"
    },
    {
        "filename": "static/img/golden-retriever-puppy.jpg",
        "uncertainty": "1.3307321"
    },
    {
        "filename": "static/img/husky-winter-dogsled_h.jpg",
        "uncertainty": "1.3511014"
    }
]

Esta implementación es bastante útil, ya que también puede filtrar imágenes con más de 1.0 de incertidumbre. Comprender este ejemplo personalizado le ayudará a implementar esta lógica con sus propios proyectos y crear, por ejemplo, algún tipo de API.

Recursos y agradecimientos especiales

Este artículo no sería posible sin información y recursos valiosos extraídos de las siguientes fuentes:

También puede leerlos para complementar todo lo aprendido en este artículo.

Que te diviertas ❤️!


Interesado en la programación desde los 14 años, Carlos es un programador autodidacta, fundador y autor de la mayoría de los artículos de Our Code World.

Conviertete en un programador más sociable

Patrocinadores