Sortuj obrazy według proporcji

13

Próbuję wybrać kilka obrazów artystycznych, aby pasowały do ​​nowych ramek. Chciałbym móc sortować te obrazy według odległości od określonego współczynnika kształtu, a następnie wyświetlać je w malejącej kolejności bliskości przez coś w rodzaju feh.

Czy jest jakaś chwalebna jednowierszowa ekspresja Uniksa? W przeciwnym razie kilkadziesiąt linii Pythona powinno to wyjaśnić.

Jeff
źródło
3
Możesz pobrać proporcje obrazu za pomocą ImageMagick, np identify -format "%[fx:w/h]:%M\n" *.jpg. Nie wiem, jak łatwo sortować według bliskości dowolnej wartości. sortnie obsługuje takiego sortowania.
NN
Zasadniczo chciałbyś przekonwertować te liczby na metrykę całkowitą odległości, a następnie przekazać ją do sortowania -n. Wygląda na to, że faktycznie możesz wykonać całą matematykę dzięki ImageMagick.
derobert

Odpowiedzi:

8

Używając komentarza ImageMagick firmy NN jako potencjalnej szansy, okazuje się, że możesz mieć do wykonania dowolnych obliczeń w ramach -formatwyników. Więc jeden możliwy sposób:

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

powinien robić co chcesz. Zauważ, że 4/3 jest tam stała, pożądany współczynnik kształtu. Można oczywiście znaleźć to jako wynik poprzedniego identify(w celu dopasowania „najbliżej tego obrazu”).

Aby wyjaśnić, bierzemy wyraźną różnicę między pożądanym a rzeczywistym współczynnikiem proporcji. Następnie pomnożenie przez dużą liczbę i zaokrąglenie. Mnożenie i zaokrąglanie jest spowodowane tym, że sort obsługuje tylko liczby całkowite, a nie racjonalne.

edytować

Okazuje się, sortże robi racjonalne, nie tylko liczby całkowite. Jest nawet określony w specyfikacji Single Unix (v4). Możesz więc pozbyć się tego obejścia:

identify -format "%[fx:abs((4/3)-(w/h))]:%M\n" *.jpg | \
    sort -n -k1 -t:
derobert
źródło
Gdzie znalazłeś dokumentację dotyczącą opcji -format identyfikatora? Nic nie widziałem na stronie podręcznika i spędziłem sporo czasu próbując odkryć tę cholerną rzecz :).
terdon
Aha, w moim systemie twoje polecenie wydaje się nie działać. Rozumiem, że 33333:cover.jpgcover.jpg to 500 x 500.
terdon
2
@terdon cóż, to dlatego, że ma stosunek 1/1, a nie 4/3. 4 / 3-1 = 1/3 = .333…. Po prostu zmień 4/3 na żądany współczynnik (który brzmi jak 1/1). Dokumenty znajdują się na stronie imagemagick.org/script/fx.php w typowo mylący sposób. Zajęło mi to również ich znalezienie.
derobert
Dzięki za link. Co do reszty, byłem idiotą. Miałem tylko jeden plik jpg w moim folderze testowym (pozostałe to pngs), więc ponieważ widziałem tylko jedną linię wyjściową, założyłem, że był to pożądany wynik i że identyfikacja twierdziła, że ​​obraz ma proporcje 4/3. To właśnie dostaję za próbę myślenia w poniedziałkowe wieczory ... +1 za eleganckie rozwiązanie.
terdon
Niezła odpowiedź! Czy istnieje sposób na dołączenie jakiegoś rodzaju etykiety do nazw plików wszystkich obrazów, które nie odpowiadają pożądanemu współczynnikowi?
Mentalista
3

Najłatwiejszym sposobem na to byłoby użycie ImageMagick . Powinien znajdować się w repozytoriach twojej dystrybucji Linuksa, dla systemów opartych na Debianie uruchom:

sudo apt-get install imagemagick

Jednym z programów pakietu ImageMagick jest identifyto, że wydrukuje on charakterystykę listy wejściowych plików obrazów. Łącząc go z sort, otrzymasz listę zdjęć posortowanych według rozmiaru (możesz zmienić png dla dowolnego rozszerzenia (-ów):

identify *png | sort -gk 3

Jeśli faktycznie potrzebujesz proporcji, a nie tylko rozmiaru, spróbuj czegoś takiego:

  1. Prosta opcja, zakłada , że w nazwach obrazów nie ma spacji :

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

    Polecenie gawk dzieli trzecie pole (rozmiar obrazu, który ma format LxH) na tablicę „rozmiary”, a następnie drukuje pierwsze pole (nazwa obrazu) i wynik podziału długości obrazu przez jego wysokość. sedKomenda jest tylko upiększania wyjścia i sortpolecenie sortuje wyniki według wskaźnika rozmiaru obrazu.

  2. Bardziej złożony, ten może zajmować się spacjami w nazwach plików:

    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
    

    Tutaj używamy finddo identyfikowania plików, którymi jesteśmy zainteresowani, i uruchamiamy identifypolecenie, a następnie przesyłamy dane wyjściowe za pomocą małego skryptu PERL. Wyrażenie regularne szuka trzech wielkich liter ( [A-Z]{3}), które powinny być formatem obrazu. Po stwierdzeniu, że łatwo jest zidentyfikować nazwę i wymiary obrazu.

    Nie używam tutaj gawk, ponieważ obecność spacji w nazwach plików wejściowych myli numery pól. Na koniec skrypt wydrukuje nazwę obrazu i wynik podziału długości / wysokości, który sortliczbowo.

Jeśli samo przeglądanie dostępnych współczynników proporcji nie wystarczy, jeśli masz co najmniej jeden obraz o pożądanym współczynniku proporcji, po prostu użyj grep, aby wyodrębnić te obrazy, których współczynnik jest najbliższy:

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
źródło
2

Możesz obliczyć różnicę dla każdego współczynnika kształtu z odniesieniem. Wygląda na odpowiedź deroberta, ale prostszą:

ref=4/3
identify -format "%[fx:abs(w/h - $ref)] %M\n" *.jpg | sort -n -k1
Pedro Lacerda
źródło
Hmm, najwyraźniej sortowanie robi racjonalne. Miałem wrażenie, że nie ...
derobert,
2

Współczynnik kształtu to tylko liczba, więc możesz przeglądać obrazy według ich nazw, jeśli nazwa jest poprzedzona współczynnikiem kształtu. Tworzenie dowiązań symbolicznych z uprzednio przygotowanym współczynnikiem proporcji pozwala przeglądać obrazy posortowane według współczynników proporcji.

Następujący przeglądający działają zgodnie z oczekiwaniami. ( feh nie przesyła dalej / wstecz, nawet dla prawdziwych obrazów - w moim systemie)

  • 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 

Przejdź do ar-sortkatalogu i po prostu przeglądaj od dowolnego punktu początkowego (proporcji), który Cię interesuje.

Nazwy dowiązań symbolicznych wyglądają tak:

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
źródło
Uwaga: jeśli ustawienia regionalne używają innego znaku dziesiętnego niż kropka, to nie zadziała. Łatwy do naprawienia: stackoverflow.com/questions/12845997/...
Jobjörn Folkesson
1

Moje zwykłe rozumowanie polega na stosowaniu kwadratowej miary odległości błędu wszędzie tam, gdzie słyszę słowa „stopień bliskości”. Z pewnością można użyć wartości bezwzględnych i byłoby to szybsze. Skrypt przyjmuje jako argument idealny współczynnik proporcji, przetwarza wszystkie pliki * .jpg w bieżącym katalogu i wysyła je posortowane w rosnącym porządku rozbieżności od idealnego współczynnika.

head usuwa końcowy znak końca linii wstawiony przez ImageMagick.

Skrypt zawiera polecenie gawk, które ustawia separator pola wyjściowego na mało prawdopodobny znak, oblicza różnicę do kwadratu i wypisuje różnicę nazwy pliku | Sortowanie jest wykonywane, a zbędne informacje (różnica kwadratów) są usuwane 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"|"
Łowca jeleni
źródło
Należy pamiętać, że używa kwadratowej odległości i obliczeń w gawk / awk :) (Podziękowania dla @NN za początkowy skrót)
Deer Hunter
Czy możesz dodać wyjaśnienie skryptu do swojej odpowiedzi? Poprawiłoby to sytuację.
NN