Trier les images par rapport d'aspect

13

J'essaie de sélectionner quelques images d'art pour s'adapter à de nouveaux cadres. J'aimerais pouvoir trier ces images par proximité à un rapport d'aspect particulier, puis les visualiser dans un ordre décroissant de proximité à travers quelque chose comme feh.

Existe-t-il une glorieuse expression Unix sur une seule ligne? Sinon, quelques dizaines de lignes de Python devraient clarifier cela.

Jeff
la source
3
Vous pouvez tirer le rapport d'aspect via ImageMagick, par exemple identify -format "%[fx:w/h]:%M\n" *.jpg. Je ne sais pas comment trier facilement par proximité d'une valeur arbitraire. sortne semble pas supporter un tel tri.
NN
Eh bien, en gros, vous voudriez convertir ces nombres en une métrique de distance entière, puis vous pourriez le passer au tri -n. Il semble que vous puissiez réellement faire tout le calcul avec ImageMagick.
derobert

Réponses:

8

En utilisant le commentaire ImageMagick de NN comme piste, il s'avère que vous pouvez lui faire faire des calculs arbitraires dans le cadre de sa -formatsortie. Donc, une façon possible:

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

devrait faire ce que vous voulez. Notez que 4/3 dans il y a une constante, le rapport d'aspect souhaité. Vous pouvez bien sûr trouver cela en sortie d'un précédent identify(pour correspondre à "le plus proche de cette image").

Pour expliquer, nous prenons la différence évidente entre la ration d'aspect souhaitée et réelle. Puis multiplier par un grand nombre et arrondir. La multiplication et l'arrondi sont dus au fait que le tri ne gère que les entiers, pas les rationnels.

Éditer

Il s'avère que sortcela semble faire des rationnels, pas seulement des entiers. Il est même spécifié dans la spécification Single Unix (v4). Donc, vous pouvez vous débarrasser de cette solution de contournement:

identify -format "%[fx:abs((4/3)-(w/h))]:%M\n" *.jpg | \
    sort -n -k1 -t:
derobert
la source
Où avez-vous trouvé la documentation sur l'option -format de Identifier? Je n'ai rien vu dans la page de manuel et j'ai passé pas mal de temps à essayer de comprendre le truc :).
terdon
Oh, et sur mon système, votre commande ne semble pas fonctionner. Je reçois 33333:cover.jpgoù cover.jpg est 500x500.
terdon
2
@terdon bien, c'est parce qu'il a un ratio de 1/1 et non 4/3. 4 / 3-1 = 1/3 = .333…. Modifiez simplement ce 4/3 au rapport souhaité (ce qui ressemble à son 1/1). Les documents sont sur imagemagick.org/script/fx.php d'une manière généralement confuse. Ça m'a pris du temps pour les trouver aussi.
derobert
Merci pour le lien. Pour le reste, j'étais un idiot. Je n'avais qu'un seul jpg dans mon dossier de test (les autres sont des pngs), donc comme je n'ai vu qu'une seule ligne de sortie, j'ai supposé que c'était le résultat souhaité et que l'identifiant affirmait que l'image avait un rapport d'aspect 4/3. C'est ce que j'obtiens en essayant de penser le lundi soir ... +1 pour une solution élégante.
terdon
Bonne réponse! Existe-t-il un moyen d'ajouter une sorte d'étiquette aux noms de fichiers de toutes les images ne respectant pas le rapport souhaité?
Mentalist
3

Eh bien, la façon la plus simple de le faire serait d'utiliser ImageMagick . Il devrait être dans les référentiels de votre distribution Linux, pour les systèmes basés sur Debian, exécutez:

sudo apt-get install imagemagick

L'un des programmes de la suite ImageMagick est identify, cela imprimera les caractéristiques d'une liste de fichiers d'images d'entrée. La combinaison avec sortvous donnera une liste d'images triées par taille (vous pouvez changer le png pour n'importe quelle extension):

identify *png | sort -gk 3

Si vous avez réellement besoin du rapport d'aspect et pas seulement de la taille, essayez quelque chose comme ceci:

  1. Option simple, suppose que vos noms d'images n'ont pas d'espaces :

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

    La commande gawk divise le 3ème champ (la taille d'image qui a le format LxH) en "tailles" de tableau puis imprime le 1er champ (le nom de l'image) et le résultat de la division de la longueur de l'image par sa hauteur. La sedcommande embellit simplement la sortie et la sortcommande trie le résultat en fonction du rapport de taille d'image.

  2. Plus complexe, celui-ci peut gérer les espaces dans les noms de fichiers:

    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
    

    Ici, nous utilisons findpour identifier les fichiers qui nous intéressent et exécuter la identifycommande, puis canaliser sa sortie via un petit script PERL. L'expression régulière recherche trois lettres majuscules ( [A-Z]{3}) qui devraient être le format d'image. Une fois que nous avons trouvé cela, il est facile d'identifier le nom et les dimensions de l'image.

    Je n'utilise pas gawk ici parce que la présence d'espaces dans les noms de fichiers d'entrée confondra les numéros de champ. Enfin, le script imprimera le nom de l'image et le résultat de la division longueur / hauteur que nous avons sortnumériquement.

Si le simple fait de parcourir les rapports d'aspect disponibles ne suffit pas, si vous avez au moins une image avec le rapport d'aspect souhaité, utilisez simplement grep pour extraire les images dont le rapport est le plus proche:

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
la source
2

Vous pouvez calculer la différence de chaque rapport d'aspect avec la référence. Ressemble à la réponse de Derobert, mais plus simple:

ref=4/3
identify -format "%[fx:abs(w/h - $ref)] %M\n" *.jpg | sort -n -k1
Pedro Lacerda
la source
Hmm, apparemment, le tri fait des raisonnements. J'avais l'impression que ce n'était pas le cas ...
derobert
2

Un rapport d'aspect n'est qu'un nombre, vous pouvez donc parcourir les images en fonction de leurs noms, si le nom est préfixé par le rapport d'aspect. La création de liens symboliques avec le rapport d'aspect pré-suspendu vous permet de parcourir les images triées par rapport d'aspect.

Les visionneuses suivantes fonctionnent comme prévu. ( feh ne fait pas avancer / reculer, même pour de vraies images - sur mon système)

  • 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 

Allez dans le ar-sortrépertoire et naviguez à partir du point de départ (rapport d'aspect) qui vous intéresse.

Les noms des liens symboliques ressemblent à ceci:

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
la source
Remarque: si vos paramètres régionaux utilisent un autre signe décimal qu'un point, cela ne fonctionnera pas. Facile à réparer cependant: stackoverflow.com/questions/12845997/…
Jobjörn Folkesson
1

Mon raisonnement habituel consiste à utiliser la mesure de la distance d'erreur au carré partout où j'entends des mots "degré de proximité". On peut sûrement utiliser des valeurs absolues, et ce serait plus rapide. Le script prend comme argument le rapport hauteur / largeur idéal , traite tous les fichiers * .jpg du répertoire courant et les sort triés dans l'ordre croissant de divergence par rapport au rapport idéal.

head supprime le caractère de fin de ligne inséré par ImageMagick.

Le script contient une commande gawk qui définit le séparateur de champ de sortie sur un caractère improbable, calcule la différence au carré et imprime la différence de paire | nom de fichier. Le tri est effectué et les informations inutiles (différence de rapport hauteur / largeur au carré) sont supprimées 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"|"
Chasseur de cerf
la source
Veuillez noter qu'il utilise la distance quadratique et les calculs dans gawk / awk :) (Merci à @NN pour le raccourci initial)
Deer Hunter
Pourriez-vous s'il vous plaît ajouter une explication du script à votre réponse? Ce serait mieux.
NN