Ordenar imágenes por relación de aspecto

13

Estoy tratando de seleccionar algunas imágenes de arte para que quepan en algunos cuadros nuevos. Me gustaría poder ordenar estas imágenes por proximidad a una relación de aspecto particular y luego verlas en orden decreciente de proximidad a través de algo como feh.

¿Hay alguna gloriosa expresión de Unix de una línea? De lo contrario, unas pocas docenas de líneas de Python deberían aclarar esto.

Jeff
fuente
3
Puede extraer la relación de aspecto a través de ImageMagick, por ejemplo identify -format "%[fx:w/h]:%M\n" *.jpg. No sé cómo ordenar fácilmente por proximidad a un valor arbitrario. sortno parece apoyar tal clasificación.
NN
Bueno, básicamente, desearía convertir esos números a una métrica de distancia entera, y luego podría pasarlos a sort -n. Parece que en realidad puedes hacer todos los cálculos con ImageMagick.
derobert

Respuestas:

8

Usando el comentario ImageNagick de NN como una ventaja, resulta que puede hacer que realice cálculos arbitrarios como parte de su -formatsalida. Entonces, una forma posible:

identify -format "%[fx:round(100000*abs((4/3)-(w/h)))]:%M\n" *.jpg | \
    sort -n -k1 -t:

Debes hacer lo que quieras. Tenga en cuenta que 4/3 hay una relación de aspecto constante, la deseada. Por supuesto, podría encontrarlo como el resultado de un anterior identify(para que coincida con "más cercano a esta imagen").

Para explicar, estamos tomando la diferencia simple entre la relación de aspecto deseada y real. Luego multiplica por un gran número y redondea. La multiplicación y la ronda se deben a que la ordenación solo maneja enteros, no racionales.

editar

Resulta sortque parece hacer racionales, no solo enteros. Incluso se especifica en la especificación Single Unix (v4). Entonces, puede deshacerse de esa solución alternativa:

identify -format "%[fx:abs((4/3)-(w/h))]:%M\n" *.jpg | \
    sort -n -k1 -t:
derobert
fuente
¿Dónde encontró la documentación sobre la opción de identificación de formato? No vi nada en la página de manual y pasé bastante tiempo tratando de resolver la maldita cosa :).
terdon
Ah, y en mi sistema su comando no parece funcionar. Llego 33333:cover.jpgdonde cover.jpg es 500x500.
terdon
2
@terdon bueno, eso es porque tiene una relación de 1/1 no 4/3. 4 / 3-1 = 1/3 = .333…. Simplemente cambie ese 4/3 a la proporción que desee (que suena como su 1/1). Los documentos están en imagemagick.org/script/fx.php de una manera típicamente confusa. También me llevó un tiempo encontrarlos.
derobert
Gracias por el enlace. En cuanto al resto, estaba siendo un idiota. Solo tenía un jpg en mi carpeta de prueba (el resto son pngs), así que dado que solo vi una línea de salida, supuse que era el resultado deseado y esa identidad afirmaba que la imagen tenía una relación de aspecto de 4/3. Eso es lo que obtengo por tratar de pensar los lunes por la noche ... +1 por una solución elegante.
terdon
¡Buena respuesta! ¿Hay alguna forma de agregar algún tipo de etiqueta a los nombres de archivo de todas las imágenes que no se adhieren a la proporción deseada?
Mentalista
3

Bueno, la forma más fácil de hacer esto sería usar ImageMagick . Debe estar en los repositorios de su distribución de Linux, para sistemas basados ​​en Debian, ejecute:

sudo apt-get install imagemagick

Uno de los programas de la suite ImageMagick es identifyque imprimirá las características de una lista de archivos de imagen de entrada. Combinarlo con sortle dará una lista de imágenes ordenadas por tamaño (puede cambiar png para cualquier extensión que tenga:

identify *png | sort -gk 3

Si realmente necesita la relación de aspecto y no solo el tamaño, intente algo como esto:

  1. Opción simple, supone que los nombres de sus imágenes no tienen espacios :

    identify *png *jpg *gif | \
    gawk '{split($3,sizes,"x"); print $1,sizes[1]/sizes[2]}' | \
    sed 's/\[.\]//' | sort -gk 3
    

    El comando gawk divide el tercer campo (el tamaño de la imagen que tiene el formato LxH) en los "tamaños" de la matriz y luego imprime el primer campo (el nombre de la imagen) y el resultado de dividir la longitud de la imagen por su altura. lossed comando simplemente embellece la salida y sortordena el resultado de acuerdo con la relación de tamaño de imagen.

  2. Más complejo, este puede tratar con espacios en los nombres de archivo:

    find . \( -iname  "*png" -o -iname "*jpg" -o -iname "*gif" \) -exec identify {} \; |\
    perl -ne '/(.+?)\s+[A-Z]{3}\s+(\d+)x(\d+)/; print "$1 ", $2/$3, "\n"' | \
    sort -gk 2
    

    Aquí estamos utilizando findpara identificar los archivos que nos interesan y ejecutar elidentify comando, y luego canalizar su salida a través de un pequeño script PERL. La expresión regular busca tres letras mayúsculas ( [A-Z]{3}) que deberían ser el formato de imagen. Una vez que hayamos encontrado eso, es fácil identificar el nombre y las dimensiones de la imagen.

    No estoy usando gawk aquí porque la presencia de espacios en los nombres de los archivos de entrada confundirá los números de campo. Finalmente, el script imprimirá el nombre de la imagen y el resultado de la división de longitud / altura que sortnuméricamente.

Si simplemente explorar las relaciones de aspecto disponibles no es suficiente, si tiene al menos una imagen con la relación de aspecto deseada, solo use grep para extraer esas imágenes cuya relación es más cercana:

identify *png *jpg *gif | \
gawk '{split($3,sizes,"x"); print $1,sizes[1]/sizes[2]}' |\
sed 's/\[.\]//' | sort -gk 3 | grep -C 10 GOOD_IMAGE.jpg
terdon
fuente
2

Puede calcular la diferencia de cada relación de aspecto con la referencia. Parece la respuesta de derobert, pero más simple:

ref=4/3
identify -format "%[fx:abs(w/h - $ref)] %M\n" *.jpg | sort -n -k1
Pedro Lacerda
fuente
Hmm, aparentemente ordenar hace racionales. Tenía la impresión de que no ...
derobert
2

Una relación de aspecto es solo un número, por lo que puede explorar las imágenes según sus nombres, si el nombre tiene el prefijo de la relación de aspecto. La creación de enlaces simbólicos con la relación de aspecto preestablecida le permite explorar las imágenes ordenadas por relación de aspecto.

Los siguientes espectadores funcionan como se esperaba. ( Feh no avanza / retrocede, incluso para imágenes reales, en mi sistema)

  • comix
  • eog (Eye of Gnome / Image Viewer)
  • gwenview

picd='/media/dat_ext4/pictures/jpg/misc'
srtd="$picd/ar-sort"   # directory to hold "sorted" symbolic links
mkdir -p "$srtd"              

find "$picd" -maxdepth 1 -type f -name "*" -print0 | 
  while IFS= read -d $'\0' -r file ; do
    [[ $(file -ib "$file") != image* ]] && continue  # skip non-image files
    ar="$(identify -format "%[fx:w/h]" "$file")"  
    slink="$(printf '%s/%06.4f %s' "$srtd" "$ar" "$(basename "$file")")"
    # make symbolic link in 'ar-sort' directory
    ln -s "$file" "$slink"  
    echo "$slink" 
  done 

Vaya al ar-sortdirectorio y simplemente navegue desde el punto de partida (relación de aspecto) que le interese.

Los nombres de los enlaces simbólicos se ven así:

0.6732 Gold Bars.jpg
0.7242 Light Bulb.jpg
0.8022 Escher - Waterfall.jpg
1.3696 Old Typewriter.jpg
1.6000 King Tut.jpg
Peter.O
fuente
Nota: si la configuración regional usa otro signo decimal que no sea un punto, esto no funcionará. Sin embargo, fácil de arreglar: stackoverflow.com/questions/12845997/…
Jobjörn Folkesson el
1

Mi línea habitual de razonamiento es utilizar la métrica de la distancia de error al cuadrado donde escucho las palabras "grado de proximidad". Seguramente se pueden usar valores absolutos, y sería más rápido. El script toma como argumento la relación de aspecto ideal , procesa todos los archivos * .jpg en el directorio actual y los genera ordenados en orden creciente de divergencia de la relación ideal.

head elimina el carácter final de línea insertado por ImageMagick.

El script contiene un comando gawk que establece el separador de campo de salida en un carácter improbable, calcula la diferencia al cuadrado e imprime el nombre de archivo de diferencia de pares. Se realiza la clasificación y se elimina la información innecesaria (diferencia de relación de aspecto al cuadrado) cut.

#!/bin/sh
if [ x"$1" = "x" ] ; then
  echo "Usage: $0 TargetAspectRatio" >&2
  exit 2
fi
ASPECT_CMD="BEGIN{OFS=\"|\";}\
{\
print (\$1-$1)^2, \$2;\
}"
identify -format "%[fx:w/h]:%M\n" *.jpg | head -n-1 | gawk -F":" "$ASPECT_CMD" | sort -k1 -t"|" | cut -f2 -d"|"
Cazador de ciervos
fuente
Tenga en cuenta que utiliza la distancia cuadrática y los cálculos dentro de gawk / awk :) (Gracias a @NN por el acceso directo inicial)
Deer Hunter
¿Podría agregar una explicación del guión a su respuesta? Lo haría mejor.
NN