Classificar imagens por proporção

13

Estou tentando selecionar algumas imagens de arte para ajustar alguns novos quadros. Gostaria de poder classificar essas imagens por proximidade a uma proporção específica e depois visualizá-las em ordem decrescente de proximidade através de algo como feh.

Existe alguma expressão gloriosa de Unix de uma linha? Caso contrário, algumas dezenas de linhas de Python devem esclarecer isso.

Jeff
fonte
3
Você pode puxar a relação de aspecto via ImageMagick, por exemplo identify -format "%[fx:w/h]:%M\n" *.jpg. Não sei como classificar facilmente por proximidade a um valor arbitrário. sortparece não apoiar essa classificação.
NN
Bem, basicamente, você desejaria converter esses números em uma métrica de distância inteira e, em seguida, passá-lo para a classificação -n. Parece que você pode realmente fazer todas as contas com o ImageMagick.
Derbert # 8/12

Respostas:

8

Usando o comentário do ImageNagick da NN como líder, acontece que você pode fazer cálculos arbitrários como parte de sua -formatsaída. Então, uma maneira possível:

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

deve fazer o que quiser. Observe que 4/3 em há uma constante, a proporção desejada. Obviamente, você pode achar isso como a saída de um anterior identify(para corresponder a "mais próximo desta imagem").

Para explicar, estamos considerando a clara diferença entre a proporção desejada e a real. Multiplicando por um número grande e arredondando. A multiplicação e a rodada são porque a classificação manipula apenas números inteiros, não racionais.

editar

Acontece sortque parece fazer racional, não apenas números inteiros. É até especificado na Single Unix Specification (v4). Portanto, você pode se livrar dessa solução alternativa:

identify -format "%[fx:abs((4/3)-(w/h))]:%M\n" *.jpg | \
    sort -n -k1 -t:
derobert
fonte
Onde você encontrou a documentação na opção -format do identity? Não vi nada na página de manual e passei um bom tempo tentando descobrir o que havia de errado :).
terdon
Ah, e no meu sistema seu comando não parece funcionar. Eu chego 33333:cover.jpgonde cover.jpg é 500x500.
terdon
2
@terdon bem, isso é porque tem uma proporção de 1/1 e não 4/3. 4 / 3-1 = 1/3 = 0,333…. Apenas altere 4/3 para a proporção desejada (que soa como 1/1). Os documentos estão em imagemagick.org/script/fx.php de uma maneira tipicamente confusa. Levei um tempo para encontrá-los também.
Derobert # 8/12
Obrigado pelo link. Quanto ao resto, eu estava sendo um idiota. Eu tinha apenas um jpg na minha pasta de teste (o restante são pngs), portanto, como vi apenas uma linha de saída, presumi que esse era o resultado desejado e que o identificador alegava que a imagem tinha uma proporção de 4/3. É o que eu ganho por tentar pensar nas noites de segunda-feira ... +1 para uma solução elegante.
terdon
Boa resposta! Existe uma maneira de anexar algum tipo de rótulo aos nomes de arquivos de todas as imagens que não estejam aderindo à proporção desejada?
Mentalista
3

Bem, a maneira mais fácil de fazer isso seria usar o ImageMagick . Ele deve estar nos repositórios da sua distribuição Linux, para sistemas baseados em debian, execute:

sudo apt-get install imagemagick

Um dos programas do ImageMagick é identifyo de imprimir as características de uma lista de arquivos de imagem de entrada. Combiná-lo com sort, fornecerá uma lista de imagens classificadas por tamanho (você pode alterar png para qualquer extensão que tenha:

identify *png | sort -gk 3

Se você realmente precisa da proporção e não apenas do tamanho, tente algo como isto:

  1. Opção simples, assume que os nomes das suas imagens não têm espaços :

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

    O comando gawk divide o terceiro campo (o tamanho da imagem que tem o formato LxH) na matriz "tamanhos" e depois imprime o 1º campo (o nome da imagem) e o resultado da divisão do comprimento da imagem pela sua altura. O sedcomando está apenas embelezando a saída e o sortcomando classifica o resultado de acordo com a proporção do tamanho da imagem.

  2. Mais complexo, este pode lidar com espaços nos nomes dos arquivos:

    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
    

    Aqui estamos usando findpara identificar os arquivos nos quais estamos interessados ​​e executar o identifycomando e, em seguida, canalizar sua saída através de um pequeno script PERL. A expressão regular procura três letras maiúsculas ( [A-Z]{3}), que devem ser o formato da imagem. Depois que descobrimos isso, é fácil identificar o nome e as dimensões da imagem.

    Não estou usando o gawk aqui porque a presença de espaços nos nomes dos arquivos de entrada confundirá os números dos campos. Finalmente, o script imprimirá o nome da imagem e o resultado da divisão comprimento / altura que sortnumericamente.

Se simplesmente navegar nas proporções disponíveis não for suficiente, se você tiver pelo menos uma imagem com a proporção desejada, basta usar grep para extrair as imagens cuja proporção estiver mais próxima:

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
fonte
2

Você pode calcular a diferença de cada proporção com a referência. Parece a resposta de derobert, mas mais simples:

ref=4/3
identify -format "%[fx:abs(w/h - $ref)] %M\n" *.jpg | sort -n -k1
Pedro Lacerda
fonte
Hmm, aparentemente o tipo faz racionais. Fiquei com a impressão de que não ...
derobert
2

Uma proporção é apenas um número, para que você possa navegar pelas imagens de acordo com seus nomes, se o nome tiver o prefixo com a proporção. A criação de links simbólicos com a proporção pré-pendente permite navegar pelas imagens classificadas por proporção.

Os seguintes visualizadores funcionam como esperado. ( feh não encaminha / recua, mesmo para imagens reais - no meu sistema)

  • comix
  • eog (Olho do Gnome / Visualizador de imagens)
  • 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 

Vá para o ar-sortdiretório e navegue do ponto de partida (proporção) em que estiver interessado.

Os nomes dos links simbólicos são assim:

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
fonte
Nota: se suas configurações de localidade usarem outro sinal decimal que não um ponto, isso não funcionará. Fácil de consertar: stackoverflow.com/questions/12845997/…
Jobjörn Folkesson
1

Minha linha usual de raciocínio é usar a métrica da distância quadrática do erro sempre que ouvir as palavras "grau de proximidade". Pode-se certamente usar valores absolutos, e seria mais rápido. O script usa como argumento a proporção ideal , processa todos os arquivos * .jpg no diretório atual e os produz em ordem crescente de divergência em relação à proporção ideal.

head remove o caractere de final de linha à direita inserido pelo ImageMagick.

O script contém um comando gawk que define o separador do campo de saída como um caractere improvável, calcula a diferença ao quadrado e imprime de volta o nome do arquivo de diferença do par. A classificação é realizada e as informações desnecessárias (diferença quadrática da proporção) são selecionadas 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"|"
Deer Hunter
fonte
Por favor, note que ele usa distância quadrática e cálculos dentro gawk / awk :) (Graças a @NN para o atalho inicial)
Deer Hunter
Você poderia adicionar uma explicação do script à sua resposta? Isso tornaria melhor.
NN