Este proyecto permite comparar una imagen capturada mediante JavaScript (fileLoad) con un conjunto de imágenes almacenadas en un servidor externo (en este caso, Google Drive). El proceso se desarrolla en las siguientes etapas:
1. Captura de imagen:
- El usuario selecciona una imagen utilizando el control
fileLoad
de JavaScript. - Se admiten diversos formatos de imagen, incluyendo JPG, PNG, y WebP, tanto para la imagen de entrada como para las imágenes del conjunto de comparación.
2. Envío de datos al servidor Python:
- Una vez seleccionada la imagen, se extraen sus datos en formato base64.
- La información de la imagen (base64) y la identificación del conjunto de comparación se envían al servidor Python.
3. Procesamiento en el servidor Python:
- El servidor Python recibe los datos de la imagen en base64 y la identificación del conjunto de comparación.
- Debido a que las librerías de comparación de imágenes como OpenCV no permiten el acceso directo a rutas externas, se realiza la siguiente conversión:
- Se descarga la imagen del conjunto de comparación desde la URL correspondiente.
- La imagen descargada se convierte a formato base64.
- Tanto la imagen de entrada como las imágenes del conjunto se convierten a escala de grises y se redimensionan a 256 píxeles para mejorar la comparación.
- Se realiza una búsqueda secuencial en el conjunto de imágenes, comparando la imagen de entrada con cada imagen del conjunto.
- Las coincidencias encontradas se almacenan en un arreglo.
4. Visualización de resultados:
- El servidor Python envía el arreglo de coincidencias al cliente JavaScript.
- El cliente JavaScript procesa los datos recibidos y los presenta al usuario en la pantalla, mostrando las imágenes coincidentes y su nivel de coincidencia.
Mejoras implementadas:
- Reducción de consumo de recursos: La conversión de imágenes a escala de grises y su redimensionamiento a 256 píxeles optimiza el proceso de comparación, reduciendo el consumo de memoria y CPU.
- Mayor precisión: La búsqueda secuencial garantiza que se encuentren todas las coincidencias posibles, incluso si son parciales.
- Flexibilidad de formatos: El sistema admite diversos formatos de imagen tanto para la imagen de entrada como para las del conjunto de comparación.
- Eficiencia en la comunicación: La transmisión de datos entre el cliente JavaScript y el servidor Python se realiza en formato base64, optimizando el uso de ancho de banda.
En resumen, este proyecto ofrece una solución robusta y eficiente para comparar imágenes utilizando JavaScript y Python, permitiendo al usuario identificar coincidencias con un conjunto de imágenes almacenadas en un servidor externo de forma precisa y versátil.
Consideraciones para la implementación del servidor de procesamiento de imágenes
Entorno de prueba y producción:
Es importante tener en cuenta que la presente guía está diseñada para su uso en entornos de prueba. Para entornos de producción, se recomienda emplear un servidor web robusto como Gunicorn o uWSGI en conjunto con WSGI. A continuación, se presentan algunos enlaces de referencia:
Optimización para tarjetas NVIDIA:
Cabe destacar que el servidor de procesamiento de imágenes no está optimizado para su ejecución en tarjetas NVIDIA mediante librerías CUDA. Si se desea utilizar este tipo de hardware, se recomienda emplear modelos TensorFlow entrenados específicamente para su aprovechamiento.
Implementación del servidor de procesamiento de imágenes
Este documento proporciona una guía para la implementación del servidor de procesamiento de imágenes. Es importante tener en cuenta los siguientes aspectos:
Entorno de prueba: La presente guía está diseñada para su uso en entornos de prueba. Para entornos de producción, se recomienda emplear un servidor web robusto como Gunicorn o uWSGI en conjunto con WSGI.
Optimización para tarjetas NVIDIA: El servidor de procesamiento de imágenes no está optimizado para su ejecución en tarjetas NVIDIA mediante librerías CUDA. Si se desea utilizar este tipo de hardware, se recomienda emplear modelos TensorFlow entrenados específicamente para su aprovechamiento.
Consideraciones adicionales:
- El servidor de procesamiento de imágenes está diseñado para manejar una carga de trabajo moderada. Para entornos con mayor demanda, se recomienda escalar la infraestructura de acuerdo a las necesidades.
- Es importante monitorear el rendimiento del servidor de procesamiento de imágenes para identificar posibles cuellos de botella y optimizar su funcionamiento.
Esperamos que esta guía le sea útil para la implementación del servidor de procesamiento de imágenes.
Instalar librerías del sistema operativo necesarias.
A continuación hay un detalla del uso de las librerías citas anteriormene y que son usadas en el actual proyecto.
Instalación de dependencias para el proyecto
Paso 1: Instalar dependencias del sistema operativo
Ejecute el siguiente comando para instalar las dependencias necesarias del sistema operativo:
dnf install cmake gif libjpeg-turbo-devel libpng-devel jasper-devel openexr-devel
- Cree un entorno virtual utilizando
venv
:
- Active el entorno virtual:
source myenv/bin/activate
- Actualice
pip
:
pip3 install --upgrade pip
Debe actualiar sin problemas en caso de que encuente algun inconveniente
desinstale pip :
$ sudo dnf remove python3-pip
e instale de nuevo
# Buscar el ejecutable pip3
sudo find / -name pip3
# (Si se encuentra en /usr/local/bin) Actualizar el PATH
export PATH=$PATH:/usr/local/bin
echo 'export PATH=$PATH:/usr/local/bin' >> ~/.bashrc
source ~/.bashrc
# Reinstalar pip especificando el directorio
sudo python3 get-pip.py --prefix=/usr/local
# Verificar la instalación
/usr/local/bin/pip3 --version
# Alternativa: Usar ensurepip
sudo python3 -m ensurepip --upgrade
- Instale las dependencias de Python:
pip3 install numpy
pip3 install pillow
pip3 install opencv-python-headless==4.5.5.64
pip3 install grpcio
pip3 install Flask
pip3 install flask-cors
pip3 install scikit-image
pip3 install requests
pip3 install opencv-python-headless
pip3 install tensorflow
Numpy: Proporciona funciones para el manejo eficiente de arrays multidimensionales, esenciales para el procesamiento de imágenes.
Pillow: Una biblioteca para el procesamiento de imágenes en Python, que ofrece funciones para cargar, guardar, manipular y visualizar imágenes.
opencv-python-headless: Una versión de OpenCV sin interfaz gráfica de usuario, ideal para entornos sin cabeza como servidores. Permite realizar tareas de procesamiento de imágenes sin necesidad de mostrar ventanas en pantalla.
grpcio: Un marco para la comunicación RPC (Remote Procedure Call) entre aplicaciones, utilizado para la comunicación entre el servidor y el cliente en este proyecto.
Flask: Un framework web ligero y flexible para Python, empleado para crear el servidor web que procesa las solicitudes de comparación de imágenes.
flask-cors: Una extensión de Flask que permite habilitar el Cross-Origin Resource Sharing (CORS) para que el cliente JavaScript pueda comunicarse con el servidor Flask.
scikit-image: Una biblioteca de procesamiento de imágenes de código abierto que ofrece una amplia gama de algoritmos y herramientas para tareas como la segmentación de imágenes, el filtrado y la extracción de características.
requests: Una biblioteca popular para realizar solicitudes HTTP en Python, utilizada para enviar la imagen de entrada al servidor y recibir los resultados de la comparación.
Resumen:
La instalación de las dependencias descritas anteriormente permite configurar el entorno de desarrollo necesario para ejecutar el proyecto de comparación de imágenes. Cada librería juega un rol específico en el proceso, desde el manejo de arrays y el procesamiento de imágenes hasta la comunicación entre el servidor y el cliente y la obtención de resultados
*** A continuación una presentación mas detallada de las librerías utilizadas en el proyecto. al final los programas tanto de interface de usuario en javascript como el servidor phyton.
Crear y Activar un Entorno Virtual
Existen varias razones por las que se recomienda usar un entorno virtual al trabajar con Python:
1. Aislamiento de proyectos:
Cada entorno virtual crea un espacio aislado para tu proyecto, incluyendo su propia instalación de Python, bibliotecas y dependencias. Esto significa que los cambios realizados en un proyecto no afectarán a otros proyectos que tengas instalados en tu sistema.
Esto evita conflictos entre las dependencias de diferentes proyectos, lo que puede causar errores y problemas de compatibilidad.
2. Reproducibilidad:
Al crear un entorno virtual, se crea una copia exacta del entorno de desarrollo del proyecto, incluyendo las versiones específicas de Python y las bibliotecas utilizadas.
Esto permite que otros desarrolladores que trabajan en el proyecto puedan replicar tu entorno de desarrollo con precisión, lo que facilita la colaboración y la resolución de problemas.
3. Gestión de dependencias:
Los entornos virtuales te permiten controlar las versiones exactas de las bibliotecas que se utilizan en tu proyecto.
Esto evita problemas de compatibilidad que pueden surgir cuando diferentes proyectos utilizan versiones diferentes de la misma biblioteca.
Además, facilita la actualización de las bibliotecas sin afectar a otros proyectos que dependen de ellas.
4. Experimentación segura:
Los entornos virtuales te permiten experimentar con nuevas bibliotecas o versiones de Python sin afectar a tu entorno de desarrollo principal.
Esto te permite probar nuevas ideas y soluciones sin riesgo de romper tu proyecto en funcionamiento.
5. Facilidad de implementación:
Implementar un entorno virtual es un proceso sencillo que solo requiere unos pocos comandos.
Existen herramientas como venv y virtualenv que hacen que la creación y gestión de entornos virtuales sea aún más fácil.
$ python3 -m venv myenv
# Activar el entorno virtual
source myenv/bin/activate
Actualizar pip (pip3)
Es recomendable antes de iniciar el proceso actualizar pip a su ultima versión para que tenga correspondencia con las diferentes librerías a instalar Numpy, TensorFlow y OpenCV
$ pip3 install --upgrade pip
Instalar setuptools
setTools: es una biblioteca esencial en el ecosistema de Python, utilizada para gestionar la instalación de paquetes. Cuando utilizas pip para instalar paquetes de Python, setuptools proporciona las herramientas necesarias para encontrar, descargar y configurar esos paquetes de manera eficiente.
Gestión de Paquetes:Permite definir y construir paquetes de Python.
Facilita la creación de archivos de distribución que pueden ser utilizados por pip para instalar paquetes.
$ pip3 install --upgrade pip setuptools
Instalar wheel
En Python, un wheel (rueda en inglés) es un formato de empaquetado que se utiliza para distribuir bibliotecas y paquetes de software. Es un archivo comprimido que contiene todos los archivos necesarios para instalar una biblioteca o paquete en un entorno de Python específico. Los wheels ofrecen varias ventajas sobre los métodos tradicionales de instalación de paquetes, como pip install:
$ pip3 install wheel
Instalar Otras bibliotecas con pip , como Numpy, OpenCV, tensor flow se instalan de forma independiente porque pueden haber versiones diferentes que presenten inconsistencias con la instalación que se esta ejecutando
Instalar Numpy
NumPy (abreviatura de Numerical Python) es una biblioteca fundamental para el lenguaje de
programación Python que proporciona un conjunto de herramientas de alto nivel para el cálculo científico, el procesamiento de matrices y el análisis de datos.
¿Qué funcionalidades ofrece NumPy?
NumPy se basa en el concepto de arreglos multidimensionales, los cuales son estructuras de datos que almacenan elementos de un mismo tipo en una estructura de matriz. NumPy ofrece una amplia gama de operaciones que se pueden aplicar a estos arreglos, incluyendo:
Creación y manipulación de arreglos: Crear, modificar y eliminar arreglos de diferentes dimensiones y formas.
Operaciones matemáticas: Realizar operaciones matemáticas básicas como suma, resta, multiplicación, división, potencias, etc., sobre arreglos enteros, decimales y complejos.
Funciones matemáticas: Aplicar funciones matemáticas avanzadas como logaritmos, exponenciales, senos, cosenos, tangentes, etc., a elementos de arreglos.
Álgebra lineal: Resolver sistemas de ecuaciones lineales, calcular matrices inversas, encontrar autovalores y autovectores, y realizar otras operaciones de álgebra lineal sobre matrices.
Estadística: Calcular medidas estadísticas como media, mediana, moda, varianza, desviación estándar, etc., sobre conjuntos de datos almacenados en arreglos.
E/S de datos: Leer y escribir datos desde y hacia archivos de texto, CSV, HDF5 y otros formatos.
Visualización de datos: Crear gráficos y visualizaciones de datos utilizando bibliotecas como Matplotlib y Seaborn.
¿En qué se diferencia NumPy de las listas de Python?
Las listas de Python son estructuras de datos versátiles que pueden almacenar una variedad de tipos de datos. Sin embargo, no están optimizadas para el cálculo científico y el procesamiento de matrices.
En cambio, los arreglos de NumPy están diseñados específicamente para el cálculo numérico y ofrecen un rendimiento significativamente superior a las listas para operaciones matemáticas y de matrices. Además, NumPy proporciona funciones y herramientas especializadas para el análisis de datos que no están disponibles en las listas de Python.
¿Por qué usar NumPy?
Existen varias razones por las que NumPy es una biblioteca esencial para el desarrollo científico y el análisis de datos en Python:
Velocidad y eficiencia: NumPy ofrece un rendimiento superior a las listas de Python para operaciones matemáticas y de matrices, lo que lo convierte en una herramienta ideal para trabajar con grandes conjuntos de datos.
Precisión: NumPy utiliza tipos de datos precisos y eficientes para almacenar y calcular valores numéricos, lo que garantiza la precisión de los resultados.
Facilidad de uso: NumPy proporciona una interfaz intuitiva y fácil de aprender para trabajar con arreglos y realizar operaciones matemáticas.
Amplia gama de funciones: NumPy ofrece una amplia gama de funciones para el cálculo científico, el procesamiento de matrices y el análisis de datos, lo que la convierte en una biblioteca versátil y completa.
Popularidad: NumPy es una de las bibliotecas más populares para el cálculo científico en Python y cuenta con una gran comunidad de usuarios y desarrolladores.
$ pip3 install numpy
Instalar TensorFlow
Nota: Para la personas que usan Aws ec2 , recordar que en las instalaciones de las instancias usualmente crea automáticamente una carpeta /tmp con unos 400 MB, eso es usualmente suficiente, pero para instalar TensorFliut se requieren casi 600MB para la descarga del archivo de instalación , para obviar este inconveniente una forma sencilla es definir de forma temporal el directorio TMPDIR a un lugar donde hay suficiente espacio export TMPDIR=/var/tmp' por ejemplo. Luego se puede volver asignar el valor por defecto /tmp o reinicair el sistema para que tome los valores por defecto.
TensorFlow es una biblioteca de software de código abierto y de gran alcance para la computación numérica que utiliza gráficos de flujo de datos. Fue desarrollada originalmente por investigadores e ingenieros del equipo de Google Brain Machine Learning dentro de la división de investigación de Google y se utiliza para investigación y producción en una amplia gama de campos, incluyendo el aprendizaje automático y el aprendizaje profundo.
Características principales de TensorFlow:
Gráficos de flujo de datos: TensorFlow utiliza gráficos de flujo de datos para representar los cálculos, lo que permite una ejecución y paralelización eficientes.
Implementación flexible: TensorFlow se puede implementar en diversas plataformas, incluyendo CPUs, GPUs, TPUs y dispositivos móviles.
Ecosistema extenso: TensorFlow cuenta con un rico ecosistema de herramientas, bibliotecas y extensiones, lo que la hace versátil para diversas aplicaciones.
Usos comunes de TensorFlow:
Reconocimiento de imágenes: Clasificación y análisis de imágenes, como detección de objetos y reconocimiento facial.
Procesamiento de lenguaje natural: Procesamiento y comprensión del lenguaje humano, incluyendo análisis de sentimientos y traducción automática.
Reconocimiento de voz: Conversión del lenguaje hablado en texto y viceversa.
Sistemas de recomendación: Recomendación de productos, películas u otros elementos en función de las preferencias del usuario.
Aprendizaje por refuerzo: Entrenamiento de agentes para tomar decisiones óptimas en entornos complejos.
Beneficios de usar TensorFlow:
Potente y escalable: TensorFlow maneja eficientemente los cálculos a gran escala y se puede escalar para satisfacer diversas necesidades.
Flexible y personalizable: La arquitectura flexible de TensorFlow permite su personalización y adaptación a tareas específicas.
De código abierto y basado en la comunidad: La naturaleza de código abierto de TensorFlow fomenta una comunidad vibrante que contribuye a su desarrollo y proporciona soporte.
Listo para producción: TensorFlow es utilizado en entornos de producción por grandes empresas y organizaciones.
$ pip3 install tensorflow
Instalar Pillow (la biblioteca de Python):
Pillow es una biblioteca de Python gratuita y de código abierto para trabajar con imágenes. Es una bifurcación del proyecto PIL (Python Imaging Library) y agrega muchas nuevas funciones y correcciones de errores. Pillow es la biblioteca de procesamiento de imágenes más utilizada para Python, y es utilizada por una amplia variedad de aplicaciones, que incluyen desarrollo web, computación científica y codificación creativa.
Algunas de las características de Pillow incluyen:
Cargar y guardar imágenes en una variedad de formatos, incluidos JPEG, PNG, GIF y TIFF
Manipular imágenes, como redimensionarlas, rotarlas y recortarlas
Aplicar efectos a las imágenes, como difuminarlas, enfocarlas y ajustar los colores
Trabajar con datos de imágenes, como píxeles e histogramas
$ pip3 install pillow
Instalar un versión especifica de opencv para la fecha de este ejercicio era la 4.5.5.64
OpenCV (Open Source Computer Vision Library) es una biblioteca de software libre y de código abierto para el procesamiento de imágenes y la visión artificial. Fue desarrollada originalmente por Intel y actualmente es mantenida por una comunidad activa de investigadores y desarrolladores.
OpenCV ofrece una amplia gama de funciones para el procesamiento de imágenes y la visión artificial, que incluyen:
Lectura y escritura de imágenes: Cargar y guardar imágenes en diferentes formatos, como JPEG, PNG, TIFF, etc.
Manipulación de imágenes: Aplicar transformaciones geométricas a las imágenes, como escalar, rotar, recortar y cambiar de tamaño.
Mejora de la imagen: Mejorar la calidad de las imágenes mediante técnicas como el ajuste de brillo, contraste, nitidez y eliminación de ruido.
Análisis de imágenes: Extraer información de las imágenes, como bordes, líneas, formas, objetos y texto.
Reconocimiento de objetos: Identificar y localizar objetos en imágenes y vídeos.
Seguimiento de objetos: Rastrear objetos a medida que se mueven en vídeos.
Realidad aumentada: Superponer objetos virtuales en imágenes y vídeos del mundo real.
Visión artificial 3D: Procesar y analizar imágenes y videos en 3D.
¿Para qué se utiliza OpenCV?
OpenCV se utiliza en una amplia variedad de aplicaciones, incluyendo:
Fotografía: Editar y mejorar fotos, eliminar ruido, corregir colores y aplicar efectos especiales.
Robótica: Permitir que los robots naveguen por su entorno, eviten obstáculos y manipulen objetos.
Seguridad: Reconocer rostros, identificar matrículas de vehículos y detectar anomalías en las imágenes de vigilancia.
Medicina: Analizar imágenes médicas, como radiografías y tomografías computarizadas, para diagnosticar enfermedades.
Agricultura: Monitorizar cultivos, detectar plagas y enfermedades y optimizar la cosecha.
Transporte: Desarrollar sistemas de asistencia al conductor, como la detección de carriles y la advertencia de colisiones.
OpenCV es una opción popular para el procesamiento de imágenes y la visión artificial debido a sus siguientes ventajas:
Gratuito y de código abierto: Cualquiera puede usar y modificar OpenCV sin restricciones.
Amplia gama de funciones: OpenCV ofrece una amplia gama de funciones para una variedad de tareas de procesamiento de imágenes y visión artificial.
Comunidad activa: OpenCV tiene una comunidad activa de desarrolladores y usuarios que brindan soporte y comparten recursos.
Multiplataforma: OpenCV está disponible para una variedad de plataformas, incluyendo Windows, macOS, Linux, Android e iOS.
Documentación extensa: OpenCV tiene una documentación extensa y tutoriales que facilitan el aprendizaje y uso de la biblioteca.
$ pip3 install opencv-python-headless==4.5.5.64
Instalar grpcio (opcional)grpcio es una biblioteca poderosa para la implementación de comunicación basada en RPC entre aplicaciones en Python, ofreciendo características avanzadas y alta eficiencia mediante el uso de HTTP/2 y Protocol Buffers. Es particularmente útil en arquitecturas de micro-servicios y sistemas distribuidos donde la comunicación eficiente y segura entre servicios es crucial.
En mi caso lo uso para interactuar entre tomcat/phyton para envío y recepción de información, mediante
fetch y response.
$ pip3 install grpcio
Instalar el servidor Flask de python para llamar el servicio de comparación de imágenes
* Abrir el puerto 5000 sobre el cual funcionará el servidor Flask de phyton
Depende del sistema operativo para dar apertura del puerto, iptables, firewalld, nfttables, ufw o las consola de aws pueden ser algunas alternativas para lograrlo.
Instalar script Phyton del servicio de comparación de imágenes que correr sobre Flask
Notar que este servidor recibe un par de rutas (path) a las imágenes a comparar, que le son pasadas desde un Front end , mediante flech que en este caso particular esta hecho en JavaScript y retorna un valor de umbral dependiendo de sis las imágenes comparadas son semejantes o no mediante response.
El valor de umbral es un valor < 10 para indicar de que hay semejanza o superior para indicar que no coinciden. Se debe ajustar este valor para que se un poco mas tolerante a la comparación valores < 25 pueden ser una buen rango si se desea buscar imágenes aproximadas,
El tiempo de comparación depende del hardward que se tenga instalado, con servidor básico de poca memoria puede demorar unos 3 o 4 segundos
$ pip3 install Flask
Estas lineas usan TensorFlow con modelo entrenado CUDA
TensorFlow xon CUSA ( remplazar el en codigo de comparacion de imagenes si se desea usar
la tarjeta NVIDIA para acelerar los procesos de tratamiento de imagenes.
Instalar CORS
Para habilitar CORS (Cross-Origin Resource Sharing) en tu servidor Flask y permitir solicitudes desde un origen diferente al del servidor, puedes utilizar la extensión flask-cors
. Aquí te muestro cómo hacerlo: permite llamar el servidor flask desde javascript
$ pip3 install flask-cors
Instalar scikit--image
Ees una biblioteca de Python de código abierto ampliamente utilizada para el procesamiento de imágenes. Ofrece un conjunto completo de algoritmos y herramientas para diversas tareas de procesamiento de imágenes, que incluyen:
Adquisición y E/S de imágenes: Leer y escribir imágenes desde varios formatos de archivo, como PNG, JPEG, TIFF y más.
Preprocesamiento de imágenes: Mejorar la calidad de la imagen, preparar las imágenes para el análisis y realizar operaciones como la reducción de ruido, la normalización y la conversión del espacio de color.
Segmentación de imágenes: Dividir una imagen en múltiples regiones significativas, como identificar objetos o separar el primer plano del fondo.
Representación y características de la imagen: Extraer y analizar características de las imágenes, como bordes, formas y texturas.
Registro de imágenes: Alinear y hacer coincidir imágenes en función de sus características o transformaciones geométricas.
Filtrado de imágenes: Aplicar varios filtros para mejorar o modificar aspectos específicos de una imagen, como suavizado, nitidez y detección de bordes.
Operaciones morfológicas: Analizar y manipular imágenes en función de su estructura y forma, como operaciones de dilatación, erosión y apertura/cierre.
Características principales de scikit-image:
$ pip3 install scikit-image
Instalar requests
Requests es una biblioteca popular y poderosa para realizar solicitudes HTTP en Python. Simplifica el proceso de envío y recepción de datos a través de la web, lo que la convierte en una herramienta valiosa para el desarrollo web, la extracción de datos y la interacción con API.
Instalar opencv-python-headless
opencv-python-headless es un paquete de Python que proporciona las funcionalidades de OpenCV sin la necesidad de una interfaz gráfica de usuario (GUI). Esto lo hace ideal para entornos sin cabeza, como servidores o sistemas sin una pantalla visible.
Diferencias entre opencv-python y opencv-python-headless:
opencv-python: El paquete completo de OpenCV para Python, que incluye todas las funcionalidades, incluyendo la manipulación de imágenes y la visualización de resultados en una GUI.
opencv-python-headless: Un subconjunto del paquete opencv-python que excluye las funciones relacionadas con la GUI. Esto significa que no puede mostrar imágenes o crear ventanas en la pantalla.
Casos de uso de opencv-python-headless:
Procesamiento de imágenes en servidores: Analizar y procesar imágenes en un servidor sin necesidad de una interfaz gráfica.
Aplicaciones de línea de comandos: Crear scripts de Python que realicen tareas de procesamiento de imágenes sin necesidad de una interfaz gráfica.
Entornos de computación en la nube: Implementar aplicaciones de procesamiento de imágenes en la nube sin necesidad de recursos gráficos.
Beneficios de usar opencv-python-headless:
Reducción del uso de recursos: Menor consumo de memoria y CPU al no tener que ejecutar una GUI.
Ejecución en entornos sin cabeza: Permite ejecutar aplicaciones de procesamiento de imágenes en servidores o sistemas sin una pantalla visible.
Mayor eficiencia: Puede procesar imágenes más rápidamente al no tener que renderizar una GUI.
$ pip3 install opencv-python-headless
--------------------------------------------------------------------------------------------------------------------
from flask import Flask, request, jsonify
import numpy as np
from tensorflow.keras.applications.resnet50 import ResNet50, preprocess_input
from tensorflow.keras.preprocessing import image
import os
app = Flask(__name__)
model = ResNet50(weights='imagenet', include_top=False, pooling='avg')
---------------------------------------------------------------------------------------------------------------------
Este código antes de procesar kas imágenes remueve el background para obtener una mejora en la respuesta de la comparación:
- Lee las imágenes en escala de grises desde el inicio para evitar problemas de conversión posteriores.
- Aplica un desenfoque Gaussian para reducir el ruido.
- Binariza la imagen usando el algoritmo de umbralización de Otsu.
- Encuentra los contornos y crea una máscara.
- Aplica la máscara para remover el fondo de la imagen.
- Redimensiona las imágenes antes de compararlas.
- Compara las imágenes utilizando diferencias absolutas.
- Determina la similitud en base a un umbral especificado.
---------------------------------------------------------------------------------------------------------------------
server.py (servidor de comparación de imágenes sin CUDA)from flask import Flask, request, jsonify
from flask_cors import CORS
from skimage.metrics import structural_similarity as ssim
import cv2
import base64
import numpy as np
import requests
import gc
app = Flask(__name__)
CORS(app)
def remove_background(image):
# Convert to grayscale
#gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
print("Imagen procesada inicio")
# Apply Gaussian blur
blur = cv2.GaussianBlur(image, (5, 5), 0)
print("Imagen procesada blur")
# Threshold the image
_, thresh = cv2.threshold(blur, 128, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
print("Imagen procesada thresh")
# Find contours
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
print("Imagen procesada contours")
# Create mask
mask = np.zeros(image.shape[:2], np.uint8)
cv2.drawContours(mask, contours, -1, 255, -1)
print("Imagen procesada mask")
# Apply mask to remove background
bg_removed = cv2.bitwise_and(image, image, mask=mask)
print("Imagen procesada remove")
# Guardar la imagen resultante en /tmp
if bg_removed is not None:
cv2.imwrite("/tmp/imagen1_processed.png", bg_removed)
print("Imagen procesada guardada en /tmp/imagen1_processed.png")
else:
print("No se pudo procesar la imagen." + image)
return bg_removed
def url_to_image(url):
response = requests.get(url)
if response.status_code == 200:
image_data = np.asarray(bytearray(response.content), dtype="uint8")
image = cv2.imdecode(image_data, cv2.IMREAD_GRAYSCALE)
return image
else:
raise ValueError("Error al descargar la imagen: {response.status_code}")
def base64_to_image(base64_data):
# Extraer la parte base64 de la cadena
try:
base64_str = base64_data.split(',')[1] if ',' in base64_data else base64_data
image_bytes = base64.b64decode(base64_str)
image_array = np.frombuffer(image_bytes, np.uint8)
image = cv2.imdecode(image_array, cv2.IMREAD_GRAYSCALE)
if image is None:
raise ValueError("No se pudo decodificar la imagen en base64")
return image
except IndexError:
raise ValueError("El formato de la cadena base64 es incorrecto")
def compare_images(image1_data, image2_path):
# Leer la segunda imagen desde los datos en base64
img1 = base64_to_image(image1_data)
# Leer la segunda imagen desde la URL
img2 = url_to_image(image2_path)
if img2 is None:
raise ValueError(f"No se pudo leer el path de la imagen image2_path")
img1 = remove_background(img1)
img2 = remove_background(img2)
# Redimensionar ambas imágenes
img1 = cv2.resize(img1, (256, 256))
img2 = cv2.resize(img2, (256, 256))
similarity, _ = ssim(img1, img2, full=True)
return float(similarity)
@app.route('/compare', methods=['POST'])
def compare():
data = request.json
id = data['id']
nombre = data['nombre']
image1_data = data['image1']
image2_path = data['image2']
try:
similarity = compare_images(image1_data, image2_path)
threshold = 0.87 # Umbral de aceptación
is_similar = similarity >= threshold
gc.collect()
if is_similar:
return jsonify({'similar': True, 'similarity': similarity, 'id':id , 'nombre': nombre, 'imagen':image2_path }), 200
else:
return jsonify({'similar': False}), 200
except Exception as e:
return jsonify({'error': str(e)}), 500
if __name__ == '__main__':
app.run(debug=True)
-----------------------------------------------------------------------------------------
CompararImagenes
Guion HTML en Javascript para capturar y comparar imágenes
Descripción:
Este guion HTML en Javascript permite capturar dos imágenes, las procesa y las envía a un servidor Python que ejecuta Flask para compararlas. El servidor Python devuelve un valor de umbral que indica la similitud entre las imágenes.
Funcionamiento:
Captura de imágenes: El guion utiliza el control fileLoad
para que el usuario seleccione dos imágenes.
Procesamiento de imágenes: Las imágenes seleccionadas se convierten a formato base64 para su transmisión al servidor Python.
Envío de datos al servidor: Se realiza una petición HTTP POST al servidor Python en el puerto 5000, enviando los datos de las imágenes en formato JSON.
Comparación de imágenes: El servidor Python recibe las imágenes en base64, las procesa y las compara utilizando algoritmos de comparación de imágenes.
Retorno del valor de umbral: El servidor Python envía un valor de umbral como respuesta a la petición HTTP, indicando la similitud entre las imágenes.
Visualización del resultado: El guion Javascript recibe el valor de umbral y lo muestra al usuario.
Consideraciones:
- El guion HTML debe estar ubicado en el mismo directorio que las imágenes a comparar.
- El servidor Python debe estar ejecutándose en el puerto 5000 y debe tener acceso a la ruta de las imágenes almacenadas en el servidor externo.
- Se recomienda utilizar un servidor web robusto como Gunicorn o uWSGI en conjunto con WSGI para entornos de producción.
Estructura del sistema:
El sistema consta de tres archivos:
CompararImagenesCrear.jsp: Un modelo JSP para servidores Tomcat que permite cargar las imágenes a comparar.
CompararImagenesInput.html: Un archivo HTML que captura la imagen a comparar y la envía al servidor Python para su procesamiento.
CompararImagenesCrearValidar.html: Un archivo HTML que recibe la información de la imagen seleccionada, recupera el conjunto de imágenes del servidor externo y las envía al servidor Python para su comparación. Finalmente, muestra el resultado de la comparación al usuario.
Nota:
En el caso de utilizar Tomcat como servidor de aplicaciones y CompararImagenes.jsp como archivo JSP, es necesario tener Tomcat y Flask ejecutándose simultáneamente para que el sistema funcione correctamente.
ComparaImagenesCrear.jsp
<!DOCTYPE html>
<!-- CompararImagenes
30/05/2024 18:50 Original
-->
<% String inputAccion = "CompararImagenes()" ; %>
<% String accion = "CREAR" ; %>
<html lang="es">
<head>
<title>Comparar imágenes</title>
<%@ include file="../../plantillas/Head.jsp" %>
<%@ include file="CompararImagenesVariables.jsp" %>
<%@ include file="ReferenciasListado.jsp" %>
<%@ include file="CompararImagenesCrearValidar.jsp" %>
</head>
<body>
<%@ include file="CompararImagenesInput.jsp" %>
<%@ include file="../BACKOFFICE/Adjunto.jsp" %>
<%@ include file="../BACKOFFICE/PiePagina.jsp" %>
</body>
</html>
---------------------------------------------------------------------------------------
<!DOCTYPE html>
<!-- CompararImagenes
30/05/2024 18:50 Original
-->
<% String inputAccion = "CompararImagenes()" ; %>
<% String accion = "CREAR" ; %>
<html lang="es">
<head>
<title>Comparar imágenes</title>
<%@ include file="../../plantillas/Head.jsp" %>
<%@ include file="CompararImagenesVariables.jsp" %>
<%@ include file="ReferenciasListado.jsp" %>
<%@ include file="CompararImagenesCrearValidar.jsp" %>
</head>
<body>
<%@ include file="CompararImagenesInput.jsp" %>
<%@ include file="../BACKOFFICE/Adjunto.jsp" %>
<%@ include file="../BACKOFFICE/PiePagina.jsp" %>
</body>
</html>
ComparrrImagenesInput.html
----------------------------------------------------------------------------------------
<!DOCTYPE html>
<html lang="en">
<head>
<title>Comparar imagenes</title>
<%@ include file="../BACKOFFICE/EncabezadoCRUD.jsp" %>
<style>
body {
display: flex;
min-height: 100vh;
flex-direction: column;
}
.wrapper {
display: flex;
width: 100%;
height: 100%;
}
#sidebar {
min-width: 250px;
max-width: 250px;
background: #343a40;
color: #fff;
transition: all 0.3s;
}
#sidebar .list-group-item {
background: #343a40;
color: #fff;
border: none;
}
#sidebar .list-group-item:hover {
background: #495057;
}
</style>
</head>
<body>
<div class="wrapper">
<!-- Sidebar -->
<nav id="sidebar">
<div class="sidebar-header p-3">
<h3>Categorías</h3>
</div>
<div id = "presentaCompararImagenesCategorias" ></div>
</nav>
<!-- Page Content -->
<div id="content" class="p-4 w-100">
<h3><div id ="categoriaDescripcion" class="text-info"></div></h3>
<div id="mensaje" style="display:block" >
<h3>Elija una categoría de búsqueda</h3>
</div>
<div id="mostrarBoton" style="display:none">
<h3>Seleccione una imagen a buscar</h3>
<form id="imageForm">
<div class="mb-3">
<label for="imageInput" class="form-label">Subir imagen</label>
<input class="form-control" type="file" id="archivoAdjunto" accept="image/*">
</div>
<button type="submit" class="btn btn-primary">Enviar</button>
</form>
<div id="preview" class="mt-3"></div>
</div>
<div id="iconProceso" class="fa-2x" style="display:none" >
<i class="text-info fa-solid fa-sync fa-spin"></i>
</div>
<div id="resultError" class='text-danger text-end'></div>
<br>
<div id="result" class='text-start'></div>
</div>
</div>
<script>
document.getElementById('imageForm').addEventListener('submit', function(event) {
event.preventDefault();
const input = document.getElementById('archivoAdjunto');
const file = input.files[0];
if (file) {
document.getElementById("iconProceso").style.display = "block";
const reader = new FileReader();
reader.onload = function(e) {
// Enviar la imagen y el nombre del archivo al script de procesamiento
procesarImagenes(e.target.result, file.name);
};
reader.readAsDataURL(file);
}
});
function procesarImagenes(imageData, fileName) {
// Mostrar el nombre del archivo en la página
if ( fileName == null )
{
alert("Seleccionar imagen a buscar")
}
CompararImagenes(imageData) ;
}
referenciaCategoriaBuscar = "" ;
referenciaCategoriaSort = "DESCRIPCION" ;
var c = {
referenciaCategoriaBuscar :referenciaCategoriaBuscar,
referenciaCategoriaSort :referenciaCategoriaSort,
referenciaCategoriaEntorno:entorno
} ;
dwr.engine.setAsync(false) ;
zephyrHandler.ReferenciasCategoriaID( usuarioDB,
c,
CategoriasFoot
) ;
function CategoriasFoot(referenciaCategoriaInfo)
{
var mR = ""
mR += " <ul class='list-group list-group-flush'> "
for ( i = 0 ; i < referenciaCategoriaInfo.length ; i++)
{
f = referenciaCategoriaInfo[i] ;
referenciaCategoriaId = f.referenciaCategoriaId ;
referenciaCategoriaDescripcion = (f.referenciaCategoriaDescripcion != null ? f.referenciaCategoriaDescripcion: "");
referenciaCategoriaMostrar = f.referenciaCategoriaMostrar;
referenciaCategoriaDescripcion = MayusculaPrimeraLetra(referenciaCategoriaDescripcion);
if (referenciaCategoriaMostrar != "si")
{
continue ;
}
parametros = referenciaCategoriaId + "," + referenciaCategoriaDescripcion;
mR += " <li class='list-group-item'>" ;
mR += " <a id=" + referenciaCategoriaId ;
mR += " class='text-decoration-none text-white' " ;
mR += " href='#'" ;
mR += " onclick=ReferenciasConsultar('" + parametros + "') " ;
mR += " >" ;
mR += referenciaCategoriaDescripcion ;
mR += " </a>" ;
mR += " </li>" ;
}
mR += "</ul>"
dwr.util.byId("presentaCompararImagenesCategorias").innerHTML = mR ;
}
</script>
CompararImagenesCrearValidar.html
----------------------------------------------------------------------------------------
<!DOCTYPE html>
<!-- CompararImagenes
30/05/2024 18:50 Original
<!-- en informacion a Phyton para que compare 2 imagenes
la imagen a buscar se pasa con su data completa y
las imagenes con las cuales se va comparar se le
pasa el path de la imagen
Esto es asi porque el servidor phyton requiere que
se le pasen las rutas de las imagenes completas
y javascript por seguirad pasar lo path de la
los archivos a procesar.-->
<script>
function CompararImagenes(imagenBuscar) {
var datosImagen = [] ;
var mI = "<div class='container'>";
mI += "<div row'>";
var img1Data = imagenBuscar;
var fetchPromises = []; // Array para almacenar todas las promesas Fetch
for (var i = 0; i < imagenesInfo.length; i++)
{
var info = imagenesInfo[i].split(",");
var id = info[0];
var nombre = info[1];
var imagen = info[2];
var img2Path = imagen;
nombre = MayusculaPrimeraLetra(nombre);
var fetchPromise = fetch('http://localhost:5000/compare', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
id : id,
nombre: nombre,
image1: img1Data,
image2: img2Path
})
})
.then(response => response.json())
.then(data => {
if (data && data.similar) {
if (data.similar) {
idCoincide = data.id
nombreCoincide = data.nombre
imagenCoincide = data.imagen
datosImagen.push(idCoincide + "," + nombreCoincide + "," + imagenCoincide)
}
}
})
.catch(error => {
console.error('Error:', error);
document.getElementById('resultError').innerText = 'Ocurrioun error al comparar las imagenes.';
});
fetchPromises.push(fetchPromise); // Agregar la promesa al array
}
// Esperar a que todas las promesas se completen
Promise.all(fetchPromises)
.then(() => {
mI = "<div class='container my-5'>"
mI += " <div class='row'>"
for ( i = 0 ; i < datosImagen.length ; i ++)
{
parametros = datosImagen[i].split(",") ;
idCoincide = parametros[0] ;
nombreCoincide = parametros[1] ;
imagenCoincide = parametros[2] ;
mI += "<div class='col-md-3 mb-4'>"
mI += " <div class='card'>"
mI += " <img src='" + imagenCoincide + "' class='card-img-top' style='height: 150px; object-fit: cover;' alt=''>"
mI += " <div class='card-body'>"
mI += " <h5 class='card-title'>" + idCoincide + "</h5>"
mI += " <p class='card-text'>" + nombreCoincide + "</p>"
mI += " </div>"
mI += " </div>"
mI += "</div>"
}
mI += " </div>" ;
mI += "</div>" ;
document.getElementById("result").innerHTML = mI;
document.getElementById("iconProceso").style.display = "none";
});
}
</script>
-----------------------------------------------------------------------------------------
Ejecutar el proceso de comparación de imágenes
Activar ambiente virtual.
$ source venv/bin/activate
verificar que Flask esta instalado
$ pip3 show Flask
Si muestra error o ninguna informacion instalrlo
$ pip3 install Flask venv/bin/activate
ejecutar el servidor de comparcion de imagenes
$ python server.py
Una vez ejecutado los pasos anteriores es una buena practica verificar si el puerto
5000 de Flask está escuchando
escuchado
Los comandos:
$ lsof -i :5000
y/o
$ netstat -tuln | grep 5000
Si el puerto se encuentra escuchando (LISTEN) puede proceder algunas pruebas básicas con CURL para verificar el funcionamiento del servid
para verificar que el servidor está respondiendo.
Nota: remplace path con la ruta real de sus imagen a comparar, en imagen1 debe pasarse es la
dataInfo de la imagen no el path, porque javascript no permite que se le pase al navegador por seguridad,
$ curl -X POST http://localhost:
5000/compare -H "Content-Type: application/json" -d '{"image1": "datainfoImage1", "image2": "path/image2"}'
debe ver mensajes similares a lo siguiente
Para imagens similares[root@rockylinux8 python]# curl -X POST http://localhost:5000/compare -H "Content-Type: application/json" -d '{"image1": "/dataInfoImagen1.jpg", "image2": "psth/imagen1.jpg"}'
{
"difference": 1
"similar": true
}
Para imagenes diferentes
[root@rockylinux8 python]# curl -X POST http://localhost:5000/compare -H "Content-Type: application/json" -d '{"image1": "/datainfoImagen1.jpg", "image2": "path/imagen2.jpg"}'
{
"difference": .85,
"similar": false
}
Usted debe decir el nivel de umbral que mas le convenga, mediante ensayo y error para determinar
que tan parecidas son las imagen valor devuelto como difference., la diferencia esta entre 0 y 1 siendo 1 coincidencia total
Para activar el servicio de comparar imágenes en segundo plano puede hacer uso del siguiente comanp.
$ nohup bash -c 'source /miCarpeta/myenv/bin/activate && python /myCarpeta/server.py' &
Nota importante: Este ejercicio supone que se tienen todos los permisos y acceso a la red donde se ejecuta el servidor tipo http.
Para servidores tipo https , es necesario considerar darle acceso a la aplicación mediante el uso de certificados y uso de SSL o equivalente
Comentarios
Publicar un comentario