Organizando fotos con ImageMagick


El semestre antepasado lleve la clase de tratamiento de imágenes multiespectrales con el Dr jorge Lira. Fue un curso muy pesado tareas y practicas a diestra y siniestra, además incluían manejar imágenes en un formato RAW para evitar la pedida de información, (esto se traducía en que cada practica o tarea que queríamos hacer, involucraba de 500MB a 1GB en 10 o 15 imágenes). Lo mas feo del asunto es que las imágenes en RAW no son interpretables en casi ningún programa, para poder transformarlas en lindos png o jpg (o tiff) que pudiéramos usar en los reportes y tareas (Documentos de LaTeX o de Open Office).

Prácticamente dependíamos de un programa comercial (privativo) que el Dr tenia en su laboratorio para guardar una copia de la imagen en algún formato mas universal. No contentos con llevar nuestro GB de imágenes en raw con los datos de la practica, teníamos que viajar con una copia de la imagen en jpg para poder escribir nuestro reporte.

Fue entonces cuando mi amiga Etna, me presento con ImageMagick.

Y que es ImageMagick…

Es un conjunto de programas libres que sirven para convertir, transformar, y procesar imágenes en casi cualquier formato (y lo digo en serio). Lo que lo hace tan poderoso y flexible es que su interfaz es en linea de comandos, por lo que es ideal para desarrollar programas que ocupen ImageMagick y procesen imágenes (de hecho hay bindings para varios lenguajes de programación).

Una de las chucherias de ImageMagick es convertir de formato raw a cualquier formato.

Por que lo querría usar uno normalmente.

La segunda vez que me encontré con la necesidad de procesar un montón de imágenes y que me motivo a escribir este post fue regresando de las vacaciones en Oaxaca. Yo no llevaba mi cámara, pero Erika y Mag me pasaron sus fotos.

Ya saben tenia cientos de imágenes con títulos bien descriptivos como IMG_2379.JPG que pesaban algo así como 600Kb y median como 3072×2304 píxeles. Lo cual si hubiera querido subir en mi blog, conllevan un montón de trafico de red, y además seria un desperdicio, por que quien tiene un monitor con esa resolución (Vamos los que las vieran las tendrían que rescalar antes de verlas).

La solución de nuevo es ImageMagick

Como se usa ImageMagik

Pues el comando convert (que no es el único que conforma ImageMagick), nos da toda la versatilidad que queremos.

Escalando una imagen

Al escalar una imagen debemos de tener cuidado de hacerlo de una manera de que conserve su proporción (su aspect ratio), la mayoría del SW nos deja hacerlo si le decimos que no queremos deformaciones, también se puede hacer en ImageMagick

convert -resize 50% input.jpg output.jpg

Al darle en porcentaje el tamaño, Imagemagick sabe que no debe modificar el aspect ratio.

Reduciendo la calidad de la imagen

Hay dos tipos de compresión una donde no se pierde información llamada lossless, y otra llamada lossy compresión que es cuando un imagen pierde parte de su información al comprimirse. Cuando guardamos una imagen en formato jpg se esta haciendo una compresión con pérdida (lossy). El algoritmo del jpg es lo suficientemente flexible para dejarnos controlar la perdida con un parámetro de calidad. Mientras menos sea la calidad menor sera la perdida y mayor el tamaño de la imagen.

Sin embargo el algoritmo es tan bueno que bajar un poco la calidad de la imagen, suele bajar en mucho el tamaño (en bytes) de la misma, aproximadamente una imagen al 90% de calidad mide una cuarta parte que la imagen original. El estándar para publicar en una web es del 85%.

Para hacerlo en ImageMagick se ocupa el siguiente comando

convert -quality 85% input.jpg output.jpg

Corrigiendo la orientación

Otra cosa interesante es que ImageMagick puede corregir la orientación de una imagen de una cámara si los metadatos de la foto tienen esa orientación con el comando

convert -auto-orient input.jpg output.jpg

Ojo esto no siempre funciona (a veces los metadatos de la cámara no están bien), por lo que siempre es bueno darle una checada a la imagen de salida. También recuerda que en muchos navegadores de archivos se aplica esta corrección, pero eso no quiere decir que la imagen este volteada, si no que el visor de imágenes la esta transformando para que la veas.

Eso puede provocar que en tu máquina tu veas la imagen al derecho y cuando la subas a un sitio web, la veas al revés. La única forma de saberlo es viendo el tamaño de la imagen y ver si es mas alta que ancha o viceversa.

Y desde luego todos estos pasos se pueden llevar a cabo al mismo tiempo. Por ejemplo:

convert -auto-orient -quality 85% -resize 50% input.jpg output.jpg

Y poniendo todo en un script

Aprovechando que tuve que aprender un poco de bash, para un programa de la tesis, escribí el siguiente scrip en bash, para hacer las operaciones antes descritas sobre una carpeta con muchas imágenes.

El script tiene las siguientes características:

  • Siempre trata de hacer la corrección de orientación
  • Acepta opcionalmente los siguientes parámetros
  • -q quality Para reducir de calidad las imágenes, el parámetro debe ser entero y estar en el intervalo (0, 100)
  • -s size Para reducir el tamaño en un porcentaje, (en ImageMagick esto no necesariamente tiene que especificarse así, pero en el scrip valido que solo se pueda cambiar el tamaño en un porcentaje) que acepta enteros en el intervalo (0, 100)
  • -n name Para especificar un patrón de nombre de la imagen de salida, en caso de que este parámetro no se le proporcione, las imágenes de salida tendrán el mismo nombre que las de salida (puede que las sobrescriban), con la única excepción que valido que en la imagen de salida la extensión siempre sea en minúsculas (odio que en la mayoría de las cámaras, las extensiones de las imágenes estén en mayúsculas DSC_001.JPG)

En resumen el scrip corrido en su forma completa por ejemplo:

photo2wp.sh -q 85 -s 50  –name Vacaciones

Tomara todas las imágenes con extensión jpg ó JPG que haya en el directorio actual. A cada una de ellas las escalará al 50% respetando su aspect ratio, las comprimirá en jpg, con el 85% de calidad y las imágenes de salida tendrán el nombre VacacionesXXX.jpg. Donde XXX es un numero progresivo que depende de la cantidad de imágenes que haya en la carpeta.

Es posible pasar mas de una palabra en el nombre pero entonces hay que encerrarlo en comillas:

photo2wp.sh -q 85 -s 50  –name “Mis Vacaciones”

Todos los argumentos son opcionales:

photo2wp.sh -q 85  –name Vacaciones

Por ejemplo comprime todas las imágenes al 85% y las renombra como VacacionesXXX.jpg, sin escalar su tamaño.

En un abuso de las opciones, puede usarse sin argumentos

photo2wp.sh

Que toma todas las imágenes, trata de corregir su orientación, y las guarda con el mismo nombre pero asegurándose que la extensión sea en minúsculas (si las imágenes originales tienen su extensión en minúsculas, las va a sobrescribir)

Por ultimo algunas recomendaciones:

  • No he testeado el script al 100%, así que siempre ten una copia de tus imágenes originales. (Aún cuando no uses mi script esto es buena practica)
  • Recuerda que el script solo funciona cuando ya tienes instalado el ImageMagick en tu maquina.
  • Si quieres usar el script, recuerda que antes que nada debes darle permisos de ejecución.
  • Recuerda que el script solo actúa sobre el directorio en el que esta siendo ejecutado. No se mete recursivamente en carpetas.

Finalmente el script esta aqui (copia y pega en un archivo de texto yo lo llame photo2wp.sh, pero pon el nombre que quieras):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#!/bin/bash
 
#Este scrip toma todas las fotos de la carpeta donde se ejecute y las
#procesa. Primero la pone al derecho dependiendo de los metadatos, 
#les cambia de nombre y las guarda con un tamaño y una calidad 
#determinadas por las opciones
 
 
function dameNumero {
 
	if [ $total -lt 100 ]; then
 
		if [ $cont -lt 10 ]; then
			number="0$cont"
		else
			number="$cont"
		fi
 
	elif [ $total -lt 1000 ]; then
 
		if [ $cont -lt 10 ]; then
			number="00$cont"
		elif [ $cont -lt 100 ]; then
			number="0$cont"
		else
			number="$cont"
		fi
 
	else
 
		if [ $cont -lt 10 ]; then
			number="000$cont"
		elif [ $cont -lt 100 ]; then
			number="00$cont"
		elif [ $cont -lt 1000 ]; then
			number="0$cont"
		else
			number="$cont"
		fi
 
	fi 
 
}
 
#Aqui parseamos las opciones
qflag=0
sflag=0
nflag=0
 
while getopts 'q:s:n:' OPTION
do
  case $OPTION in
  q)	qflag=1
		quality="$OPTARG"
		;;
  s)	sflag=1
		size="$OPTARG"
		;;
  n)	nflag=1
		nameBase="$OPTARG"
		;;
  *)	printf "Usage: photo2wp.sh [-q <quality>] [-s <size>] [-n <name>]" >&2
		exit 2
		;;
  esac
done
 
#Si no nos dieron quality asume el 100
if [ $qflag -ne 1 ]; then
	quality=100
fi
 
#Si no nos dieron size asume el 100
if [ $sflag -ne 1 ]; then
	size=100
fi
 
 
#Checamos que quality sea valido
if [[ $quality =~ ^[0-9]+$ ]]; then
    if [ $quality -gt 100 -o $quality -lt 0 ]
    then
		echo "El parámetro quality debe se un número entero en el intervalo [0, 100]" >&2
		exit 3
    fi
else 
	echo "El parámetro quality debe se numérico y entero" >&2
    exit 3
fi
 
#Ahora validamos el valor de size
if [[ $size =~ ^[0-9]+$ ]]; then
    if [ $size -gt 100 -o $size -lt 0 ]
    then
		echo "El parámetro size debe se un número entero en el intervalo [0, 100]" >&2
		exit 3
    fi
else 
	echo "El parámetro size debe se numérico y entero" >&2
    exit 3
fi
 
#Contamos cuantas imagenes hay
total=`ls *.[jJ][pP][gG] 2>/dev/null | wc -l`
 
if [ $total -eq 0 ]; then
	echo "No hay imagenes que procesar en esta carpeta"
	exit 1
fi
 
#Calculemos las opciones y avisemos al usuario que vamos a hacer
opciones="-auto-orient"
 
echo "Hay $total fotos"
 
if [ $sflag -eq 1 ]; then
	echo "Se van a escalar a un tamaño de: $size%"
	opciones="$opciones -resize $size%"
fi
 
if [ $qflag -eq 1 ]; then
	echo "Se van a comprimir con una calidad de: $quality%"
	opciones="$opciones -quality $quality%"
fi
 
if [ $nflag -eq 1 ]; then
	echo "Se guardaran con el nombre: $nameBase[XXX].jpg"
fi
 
#Todo correcto empezamos a procesar
cont=0
number=""
output_file=""
images=*.[jJ][pP][gG]
 
#Ciclo principal sobre todas las imagenes de entrada
for input_file in $images
do
	#Calculamos el nombre de la imagen de salida
	cont=`expr $cont + 1`
	dameNumero
	if [ $nflag -eq 1 ]; then
		output_file="$nameBase$number"
	else
		output_file=${input_file%%.*}
	fi
 
	#Realizamos la conversion
	if convert $opciones "$input_file" "$output_file.jpg" 2>/dev/null ; then
		echo "Imagen $cont de $total"
	else
		echo "$input_file no pudo ser procesada..." >&2
	fi
 
done
 
exit 0
Share on Facebook
  1. #1 by Etna on 16 julio 2010 - 18:00 pm

    Suuuper padre el artículo :D

  2. #2 by nemediano on 16 julio 2010 - 19:21 pm

    Gracias, ahora que lo leo me falto decir como transformar los raw, que era el meollo con el que empezó esto XD.
    Que bueno que te gusto :) y pues ahora a seguirle dando al Imagemagick

  3. #3 by Juan Adan on 28 agosto 2010 - 17:37 pm

    Que ondas Antonio!!

    me di tiempo y entre a tu blog
    saludos!

  4. #4 by nemediano on 30 agosto 2010 - 13:37 pm

    Gracias por la visita Juan.
    Tiene desde el noveno semestre de la carrera que no te veo y también un buen rato que no se de ti.
    espero que tu estés bien, saludos

(No será publicado)