Por Julio Alberto Lascano
En esta entrada, exploraremos dos scripts útiles para la manipulación de imágenes: uno para aplicar una marca de agua y otro para clasificar imágenes según sus características. Ambos scripts son herramientas valiosas para fotógrafos, diseñadores gráficos y cualquier persona que trabaje con imágenes digitales. La combinación de Bash y Python permite crear una solución eficiente y automatizada para procesar múltiples imágenes a la vez.
Introducción a las Librerías cv2 (OpenCV) y NumPy
En el mundo de la programación y la informática, existen herramientas poderosas que nos permiten realizar tareas complejas de manera más sencilla y eficiente. Hoy, vamos a explorar dos de estas herramientas: cv2 (también conocida como OpenCV) y NumPy.
¿Qué es cv2 (OpenCV)?
OpenCV (Open Source Computer Vision Library) es una biblioteca de software de visión por computadora. Esto significa que proporciona una gran cantidad de funciones que permiten a las computadoras "ver" y procesar imágenes y videos. Con OpenCV, puedes realizar tareas como:
- Detectar y reconocer caras en imágenes.
- Seguir objetos en movimiento en videos.
- Aplicar filtros y efectos a imágenes.
- Medir distancias y tamaños en fotografías.
 |
Detectar y reconocer caras en imágenes |
La librería cv2 es simplemente el módulo de Python para usar OpenCV. Es una herramienta muy potente en el campo de la inteligencia artificial y la visión por computadora.
¿Qué es NumPy?
NumPy (Numerical Python) es una biblioteca para el lenguaje de programación Python que permite realizar operaciones matemáticas y estadísticas de manera eficiente. Es especialmente útil cuando trabajamos con grandes cantidades de datos, ya que está diseñada para realizar cálculos rápidos y precisos. Con NumPy, puedes:
- Crear y manipular arreglos (matrices) de datos.
- Realizar operaciones matemáticas complejas.
- Procesar datos de manera eficiente.
- Integrar con otras librerías científicas y de análisis de datos.
NumPy es la base para muchas otras librerías científicas y de aprendizaje automático en Python, como SciPy, Pandas y TensorFlow.
 |
NumPy - Software de análisis numérico |
¿Por qué Usar cv2 y NumPy Juntas?
La combinación de cv2 y NumPy es muy común en proyectos de visión por computadora. NumPy se utiliza para manejar y procesar los datos de las imágenes (que son, en esencia, matrices de números) de manera eficiente, mientras que cv2 proporciona las herramientas específicas para la visión por computadora. Juntas, estas librerías permiten desarrollar aplicaciones poderosas que pueden analizar y manipular imágenes y videos de maneras muy avanzadas.
Descripción de los Scripts
aplicar_marca_agua.sh
Este script de Bash automatiza el proceso de aplicar una marca de agua a todas las imágenes en un directorio especificado. Utiliza las potentes herramientas de ImageMagick para realizar esta tarea de manera eficiente. A continuación, se detalla el flujo de trabajo del script:
- Verificación de comandos de ImageMagick: Se asegura de que los comandos 'identify', 'convert' y 'composite' estén disponibles.
- Definición de parámetros: Se especifican las rutas de las marcas de agua (blanca y negra), el directorio de imágenes a procesar, el factor de escala para el tamaño de la marca de agua y el directorio de salida.
- Verificación de parámetros y rutas: Se comprueba que todos los parámetros necesarios se han proporcionado y que las rutas de las marcas de agua y el directorio de imágenes existen. Si el directorio de salida no existe, se crea automáticamente.
- Bucle para procesar cada imagen: Itera sobre cada archivo en el directorio de imágenes, verificando si es una imagen válida.
- Obtención del tamaño de la imagen: Utiliza el comando 'identify' para obtener el tamaño de la imagen en píxeles.
- Cálculo del tamaño de la marca de agua: Calcula el tamaño de la marca de agua proporcional al tamaño de la imagen original.
- Redimensionamiento de la marca de agua: Redimensiona la marca de agua al tamaño calculado.
- Aplicación de la marca de agua: Aplica la marca de agua al pie de la imagen con un margen inferior centrado.
- Eliminación de archivos temporales: Elimina el archivo temporal de la marca de agua redimensionada después de aplicarla a la imagen.
clasificar_imagen_v5.py
Este script de Python se utiliza para determinar el color (blanco o negro) más adecuado para la marca de agua en función de la luminosidad de la región inferior de la imagen. Utiliza las bibliotecas OpenCV (cv2) y NumPy, que son herramientas poderosas para la visión por computadora y la manipulación de matrices numéricas.
- OpenCV (cv2): Es una biblioteca popular de código abierto para visión por computadora y procesamiento de imágenes. Proporciona una amplia gama de funciones para manipular y analizar imágenes.
- NumPy: Es una biblioteca fundamental en Python para la computación científica y numérica. Proporciona un objeto de matriz multidimensional y una variedad de funciones para operar sobre estas matrices.
Cómo Funciona
El script de Python realiza una segmentación basada en color en la región inferior de la imagen para identificar ciertos tonos o rangos de color. Luego, calcula la luminosidad promedio de esta región y decide si la marca de agua debe ser blanca o negra basándose en la luminosidad calculada.
Pasos del Proceso
- Carga de la imagen: El script carga la imagen proporcionada como argumento.
- Definición de la región inferior: Se define una región en la parte inferior de la imagen, que es donde se aplicará la marca de agua.
- Segmentación basada en color: Se segmenta la región inferior para identificar ciertos tonos de color.
- Cálculo de la luminosidad promedio: Se calcula la luminosidad promedio de la región inferior y de la región donde se detecta un color específico.
- Decisión del color de la marca de agua: Basándose en la luminosidad promedio y la presencia de un color específico, el script decide si la marca de agua debe ser blanca o negra.
Este enfoque asegura que la marca de agua se vea correctamente en la imagen, proporcionando un buen contraste independientemente de la luminosidad de la región donde se aplica.
Descripción del Script: aplicar_marca_agua.sh
El script aplicar_marca_agua.sh automatiza el proceso de aplicar una marca de agua a todas las imágenes en un directorio especificado. A continuación, se explica paso a paso lo que hace el script:
- Verificación de comandos de ImageMagick: Se verifica si los comandos 'identify', 'convert' y 'composite' están disponibles.
- Definición de parámetros:
- MARCA_DE_AGUA_BLANCA: Ruta de la imagen que se utilizará como marca de agua blanca.
- MARCA_DE_AGUA_NEGRA: Ruta de la imagen que se utilizará como marca de agua negra.
- DIRECTORIO_IMAGENES: Directorio que contiene las imágenes a las que se aplicará la marca de agua.
- FACTOR_ESCALA: Factor de escala que determina el tamaño proporcional de la marca de agua en relación con el ancho de la imagen original.
- DIRECTORIO_SALIDA: Directorio donde se guardarán las imágenes con la marca de agua aplicada.
- Verificación de parámetros y rutas:
- Se verifica que todos los parámetros necesarios se han proporcionado.
- Se verifica que las rutas de las marcas de agua y el directorio de imágenes existen.
- Si el directorio de salida no existe, se crea automáticamente.
- Bucle para procesar cada imagen: Se utiliza un bucle 'for' para iterar sobre cada archivo en el directorio de imágenes especificado.
- Obtención del tamaño de la imagen: Se utiliza el comando 'identify' para obtener el tamaño de la imagen en píxeles.
- Cálculo del tamaño de la marca de agua: Se calcula el tamaño de la marca de agua proporcional al tamaño de la imagen original, utilizando el factor de escala definido.
- Redimensionamiento de la marca de agua: Se redimensiona la marca de agua al tamaño calculado y se elimina cualquier perfil de color incrustado para evitar advertencias.
- Aplicación de la marca de agua: Se aplica la marca de agua al pie de la imagen con un margen inferior centrado utilizando el comando 'composite'.
- Eliminación de archivos temporales: Se elimina el archivo temporal de la marca de agua redimensionada después de aplicarla a la imagen.
if ! command -v identify &> /dev/null || ! command -v convert &> /dev/null || ! command -v composite &> /dev/null
then
echo "ImageMagick no está instalado o los comandos necesarios no están disponibles. Por favor, instálalo antes de ejecutar este script."
exit 1
fi
set -e
while getopts "b:n:d:s:o:" opt; do
case ${opt} in
b ) MARCA_DE_AGUA_BLANCA=$OPTARG ;;
n ) MARCA_DE_AGUA_NEGRA=$OPTARG ;;
d ) DIRECTORIO_IMAGENES=$OPTARG ;;
s ) FACTOR_ESCALA=$OPTARG ;;
o ) DIRECTORIO_SALIDA=$OPTARG ;;
\? ) echo "Uso: aplicar_marca_agua.sh -b [marca_agua_blanca] -n [marca_agua_negra] -d [directorio_imagenes] -s [factor_escala] -o [directorio_salida]"
exit 1 ;;
esac
done
if [ -z "$MARCA_DE_AGUA_BLANCA" ] || [ -z "$MARCA_DE_AGUA_NEGRA" ] || [ -z "$DIRECTORIO_IMAGENES" ] || [ -z "$FACTOR_ESCALA" ] || [ -z "$DIRECTORIO_SALIDA" ]; then
echo ""
echo "Uso: aplicar_marca_agua.sh -b [marca_agua_blanca] -n [marca_agua_negra] -d [directorio_imagenes] -s [factor_escala] -o [directorio_salida]"
echo ""
echo "Todos los parámetros (-b, -n, -d, -s, -o) son obligatorios."
echo "-------------------------------------------------------------------------------------------------------------"
echo "Factor de escala para el tamaño de la marca de agua -s [factor_escala]"
echo "Por ejemplo: -s 0.15 , un factor de escala del 15% es adecuado para la fotografia de paisajes."
echo "-------------------------------------------------------------------------------------------------------------"
exit 1
fi
if [ ! -f "$MARCA_DE_AGUA_BLANCA" ]; then
echo "La ruta de la marca de agua blanca ($MARCA_DE_AGUA_BLANCA) no existe."
exit 1
fi
if [ ! -f "$MARCA_DE_AGUA_NEGRA" ]; then
echo "La ruta de la marca de agua negra ($MARCA_DE_AGUA_NEGRA) no existe."
exit 1
fi
if [ ! -d "$DIRECTORIO_IMAGENES" ]; then
echo "El directorio de imágenes ($DIRECTORIO_IMAGENES) no existe."
exit 1
fi
if [ ! -d "$DIRECTORIO_SALIDA" ]; then
echo "El directorio de salida ($DIRECTORIO_SALIDA) no existe. Creando el directorio..."
mkdir -p "$DIRECTORIO_SALIDA"
fi
SCRIPT_DIR="$(dirname "$(realpath "${BASH_SOURCE[0]}")")"
SCRIPT_PATH="$SCRIPT_DIR/scripts/clasificar_imagen_v5.py"
if [[ ! -f "$SCRIPT_PATH" ]]; then
echo "El script $SCRIPT_PATH no existe. Verifica la ruta."
exit 1
fi
contador=0
tiempo_inicio=$(date +%s)
for IMAGEN in "$DIRECTORIO_IMAGENES"/*; do
if [ -f "$IMAGEN" ] && file --mime-type "$IMAGEN" | grep -q -E "image/(png|gif|jpeg|jpg)"; then
nombre_imagen=$(basename "$IMAGEN")
extension_imagen="${nombre_imagen##*.}"
tamano_imagen=$(identify -format "%wx%h" "$IMAGEN")
ancho_imagen=$(echo "$tamano_imagen" | cut -d'x' -f 1)
altura_imagen=$(echo "$tamano_imagen" | cut -d'x' -f 2)
tamano_marca=$(echo "$ancho_imagen * $FACTOR_ESCALA" | bc)
resultados=$(python "$SCRIPT_PATH" "$DIRECTORIO_IMAGENES$nombre_imagen" "$FACTOR_ESCALA")
read -r resultado_color luminosidad <<< "$resultados"
echo "-------------------------------"
echo "Color marca de agua: $resultado_color"
echo "Luminosidad: $luminosidad"
echo "-------------------------------"
echo "Aplicando marca de agua a $DIRECTORIO_IMAGENES$nombre_imagen -> $DIRECTORIO_SALIDA${nombre_imagen%.*}_wm.$extension_imagen"
case "$resultado_color" in
"blanco")
MARCA_DE_AGUA=$MARCA_DE_AGUA_BLANCA
;;
"negro")
MARCA_DE_AGUA=$MARCA_DE_AGUA_NEGRA
;;
*)
echo "Color desconocido: $color. Usando la marca de agua blanca por defecto."
MARCA_DE_AGUA=$MARCA_DE_AGUA_BLANCA
;;
esac
marca_de_agua_redimensionada=$(mktemp)
convert "$MARCA_DE_AGUA" -resize "${tamano_marca}x${tamano_marca}" -strip "$marca_de_agua_redimensionada"
composite -dissolve 50% -gravity South -geometry +0+50 "$marca_de_agua_redimensionada" "$IMAGEN" "$DIRECTORIO_SALIDA/${nombre_imagen%.*}_wm.$extension_imagen"
rm "$marca_de_agua_redimensionada"
contador=$((contador + 1))
fi
done
tiempo_fin=$(date +%s)
tiempo_total=$((tiempo_fin - tiempo_inicio))
horas=$((tiempo_total / 3600))
minutos=$(( (tiempo_total % 3600) / 60 ))
segundos=$((tiempo_total % 60))
echo "Total de imágenes procesadas: $contador"
printf "Tiempo total transcurrido: %02d:%02d:%02d\n" $horas $minutos $segundos
Descripción del Script: clasificar_imagen_v5.py
El script clasificar_imagen_v5.py carga la imagen y define la región inferior de la misma para segmentación basada en color y análisis de luminosidad promedio. A continuación, se detallan las funcionalidades del script:
- Segmentación basada en color en la región inferior:
- Identifica ciertos tonos o rangos de color en la región inferior de la imagen.
- Cálculo de la luminosidad promedio:
- Calcula la luminosidad promedio de la región inferior y de la región donde se detecta un color específico.
- Basándose en la luminosidad promedio y la presencia de color específico, decide si la marca de agua debe ser blanca o negra.
- Bibliotecas utilizadas:
- cv2 (OpenCV): Biblioteca popular para la visión por computadora y el procesamiento de imágenes.
- NumPy: Biblioteca fundamental para computación científica y numérica en Python.
El script imprime el resultado (blanco o negro) junto con la luminosidad promedio de la región inferior.
import sys
import cv2
import numpy as np
def calcular_luminosidad_promedio(region):
luminosidad = cv2.mean(region)[0]
return luminosidad
def main():
if len(sys.argv) < 3:
print("Uso: clasificar_imagen_v5.py ")
sys.exit(1)
ruta_imagen = sys.argv[1]
try:
FACTOR_ESCALA = float(sys.argv[2])
except ValueError:
print("El factor de escala debe ser un número.")
sys.exit(1)
img = cv2.imread(ruta_imagen)
if img is None:
print("Error al cargar la imagen. Verifique la ruta y el formato del archivo.")
sys.exit(1)
alto, ancho, _ = img.shape
alto_cuadrante = int(alto * FACTOR_ESCALA * 2)
ancho_cuadrante = int(ancho * FACTOR_ESCALA * 2)
y_inicio = alto - alto_cuadrante
x_inicio = (ancho - ancho_cuadrante) // 2
region_inferior = img[y_inicio:, x_inicio:x_inicio + ancho_cuadrante]
region_inferior_hsv = cv2.cvtColor(region_inferior, cv2.COLOR_BGR2HSV)
lower_color = (0, 50, 50)
upper_color = (20, 255, 255)
mask_color = cv2.inRange(region_inferior_hsv, lower_color, upper_color)
luminosidad_color = calcular_luminosidad_promedio(mask_color)
luminosidad_color_mean = np.mean(luminosidad_color)
luminosidad_color_std = np.std(luminosidad_color)
umbral_color = luminosidad_color_mean + 2 * luminosidad_color_std
luminosidad_region_inferior = calcular_luminosidad_promedio(region_inferior)
if luminosidad_region_inferior <= 127 and luminosidad_color_mean <= umbral_color:
resultado_color = "blanco"
else:
resultado_color = "negro"
print(resultado_color, luminosidad_region_inferior)
if __name__ == "__main__":
main()
Uso de la Desviación Estándar
La desviación estándar mide qué tan dispersos están los valores de luminosidad. Si todos los valores son muy similares, la desviación estándar será baja; si hay mucha variación, será alta.
Se calcula un "umbral" dinámico usando la desviación estándar. Este umbral es una combinación de la luminosidad promedio del color y la desviación estándar de esa luminosidad.
Conclusión
La combinación de estos dos scripts proporciona una solución robusta y eficiente para aplicar marcas de agua a un gran número de imágenes de manera automatizada. Utilizando Bash y Python, se puede asegurar que cada imagen reciba una marca de agua que se ajuste perfectamente a sus características específicas, mejorando así la presentación y protección de sus imágenes digitales.
Dependencias
- **Imagemagick**:Paquete de software para manipular y editar imágenes.
- **bc**: es una calculadora de precisión arbitraria en Unix-like.
- **OpenCV (`cv2`)**: una popular biblioteca de código abierto diseñada para visión por computadora y procesamiento de imágenes.
- **NumPy**: Biblioteca fundamental en Python para computación científica y numérica. Se utiliza para calcular estadísticas como la media y la desviación estándar de la luminosidad para la detección de color en la región inferior de la imagen.
antix1@antix1:~ sudo apt-get install imagemagick bc
antix1@antix1:~ sudo apt-get install python3-opencv
antix1@antix1:~ sudo apt-get install python3-numpy
Los escript se pueden descargar desde mi repositorio en GitHub:
https://github.com/DrCalambre/watermark
Entradas relacionadas tambien en este blog:
Como crear una Marca de Agua con GIMP.