Classifique todos os pixels de uma imagem pelo número de ocorrências

8

Entrada

O nome de um arquivo no formato gráfico de varredura de sua escolha. O formato escolhido deve suportar pelo menos 8 bits por canal e 3 canais.

Resultado

Um arquivo no mesmo formato, com as mesmas dimensões e pixels que o primeiro, mas cujos pixels são agrupados em ordem decrescente do número de vezes que ocorrem, classificados da esquerda para a direita, de cima para baixo.

  • Se certas cores de pixels aparecerem o mesmo número de vezes, a ordem delas não será especificada.
  • Você não deve sobrescrever o arquivo de entrada (use um nome de arquivo diferente para a saída).
  • Toda e qualquer biblioteca de processamento de imagens de terceiros é permitida.

Exemplo

panda

Produzirá resultados semelhantes a:

pixels classificados da imagem do panda

Especialmente nas partes inferiores da imagem, algumas variações podem ocorrer, devido a diferentes rompimentos entre cores de igual frequência.

EMBLEMA
fonte
1
Podemos usar outros formatos de arquivo, como PNM, para a saída?
FUZxxl 14/03/2015
@EMBLEM Não sei ao certo o que você quer dizer com "renunciar à escala de cinza".
FUZxxl 14/03/2015
@ MartinBüttner Bom ponto, eu mudei para entrada e saída, sendo os mesmos formatos.
EMBLEM 14/03
1
@EMBLEM Acho que ele quis dizer "laços", como em "dois pixels ocorrem com a mesma frequência". Posso assumir que a ordem deles não é especificada neste caso?
FUZxxl 14/03/2015
1
Para ser claro na entrada / saída ... podemos usar uma string (nome do arquivo), um fluxo de bytes ou um Fileobjeto de tipo complexo ...? Isso faria uma grande diferença em alguns idiomas.
Geobits 14/03/2015

Respostas:

4

J, 94 81 bytes

Uma função que pega o nome de um arquivo PNG (sem canal de transparência) e grava o resultado no nome do arquivo de entrada precedido por "o".

f=.3 :0
load'graphics/png'
(($a)$#/|:\:~(#,{.)/.~,a=.readpng y)writepng'o',y
)

entrada resultado

Método

  • Crie uma lista de todos os números de cores e o número de aparências
  • Classifique a lista pelo número de aparências
  • Multiplique cada número de cor igual às suas aparências
  • Remodelar a nova lista para a forma da imagem original
randomra
fonte
você pode salvar um caractere se tornar a função diádica e salvar o PNG classificado x.
FUZxxl 15/03/2015
@FUZxxl Na verdade, ele salvaria 3 caracteres, mas não acho que esteja de acordo com a especificação. Também pude salvar a imagem em um arquivo sem extensão de 1 letra, mas isso não é muito elegante.
Aleatório
@FUZxxl Bem, acabou havia bastante alguns caracteres extras no corpo da função ...
randomra
Eu não falo J, mas na especificação há uma string como entrada. Aqui, o nome do arquivo de entrada é codificado no programa.
Edc65 17/03/2015
@ edc65 Em J, se você definir uma função, seu argumento será sempre acessado pelo ypersonagem. (Se você definir uma função com dois argumentos aqueles são acessados xe ye você não pode definir funções com mais argumentos.)
randomra
6

Mathematica, 125 123 bytes

Export["a"<>#,i=ImageData@Import@#;Image@ArrayReshape[Join@@ConstantArray@@@SortBy[Tally[Join@@i],-Last@#&],Dimensions@i]]&

Isso define uma função sem nome que pega o nome do arquivo em qualquer formato de imagem comum e grava o resultado no arquivo com o mesmo nome, mas anexado a. O resultado parece um pouco diferente do OP, já que o Mathematica SortByquebra os vínculos por ordem de classificação padrão, portanto, os bits inferiores onde ocorrem gravatas parecem um pouco mais organizados:

Não é um panda.

A implementação em si é realmente direta:

  • ImageData para obter uma grade de valores de cores.
  • Join para achatar a matriz.
  • Tally para contar a ocorrência de cada cor.
  • SortBy[...,-Last@#&] para classificar por frequências do mais alto para o mais baixo.
  • ConstantArraye Joinexpandir os cálculos novamente.
  • ArrayReshapepara recuperar a forma da imagem original (obtida com Dimensions).
  • Image para converter os dados novamente em um objeto de imagem.

FYI, 22 bytes são usados ​​no arquivo E / S. Uma versão equivalente que pega e retorna um objeto de imagem chega em 103 bytes:

(i=ImageData@#;Image@ArrayReshape[Join@@ConstantArray@@@SortBy[Tally[Join@@i],-Last@#&],Dimensions@i])&
Martin Ender
fonte
4

Python2 / PIL, 244 226 225 223 222 202 186 182 170 159

from PIL.Image import*
s=raw_input();i=open(s);g=list(i.getdata());i.putdata(sum([[c[1]]*-c[0]for c in sorted((-g.count(r),r)for r in set(g))],[]));i.save(2*s)

Changelog

Versão mais curta por stokastic , 123

from PIL.Image import*
s=raw_input();i=open(s);d=list(i.getdata());i.putdata(sorted(d,key=lambda D:d.count(D)));i.save(2*s)

Bem, vamos pelo menos tentar, mesmo que já esteja vencido.

É extremamente lento, o Panda processado por vários minutos no meu laptop.

Salva com um nome de arquivo com o nome do arquivo original repetido duas vezes.

panda

PurkkaKoodari
fonte
você pode salvar 32 bytes usando i=open(raw_input());d=list(i.getdata());i.putdata(sorted(d,key=lambda D:d.count(D)));i.save('o.png'), embora seja muito lento para imagens grandes (chamadas list.count em cada pixel).
stokastic
@stokastic Bem, vou acrescentar isso, mas credito por isso. Eu prefiro ler o nome de uma variável (que se o usuário insere uma imagem chamada o.png?)
PurkkaKoodari
justo! :)
stokastic
2

Python, 1197 bytes

# -*- coding: utf-8 -*-
from __future__ import division
from collections import Counter
import png
from sys import argv,exit
script,file_name,output_file_name=argv
def group(s,n):
    return zip(*[iter(s)]*n)
def flatten(list_of_lists):
    result=[]
    for lst in list_of_lists:
        result.extend(lst)
    return result
def group_list(old_list,tuples_per_list):
    new_list=[]
    i=1
    appended_row=[]
    for item in old_list:
        appended_row.extend(flatten([item]))
        if i==tuples_per_list:
            new_list.append(appended_row)
            i=1
            appended_row=[]
        else:
            i+=1
    return new_list
input_image=png.Reader(file_name)
image_data=input_image.read()
width=image_data[0]
height=image_data[1]
pixels=list(image_data[2])
if image_data[3]["alpha"]:
    ints_per_colour=4
elif image_data[3]["greyscale"]:
    ints_per_colour=2
else:
    ints_per_colour=3
colours=Counter(colour for row in pixels for colour in group(row,ints_per_colour)).most_common()
pixel_list=flatten([element]*count for element,count in colours)
ordered_rows=group_list(pixel_list,width)
f=open(output_file_name,"wb")
png_object=png.Writer(width,height,greyscale=image_data[3]["greyscale"],alpha=image_data[3]["alpha"])
png_object.write(f,ordered_rows)
f.close()

O pngmódulo que eu usei .

EMBLEMA
fonte
2
Obrigado por fornecer uma solução de referência! Costumamos colocá-las no próprio post de desafio para que as pessoas possam encontrá-las mais facilmente, mas postá-las como resposta também é legal.
FUZxxl 14/03/2015
1

C # 413

Programa completo. Passe o nome do arquivo na linha de comando, a saída será salva no mesmo formato do arquivo "o".

Não usando alguns recursos interessantes do linq, como SelectMany e Enumerable.Range, pois o programa seria mais limpo, mas mais longo.

using System.Collections.Generic;using System.Linq;using System.Drawing;
class P{
static void Main(string[]a){
var d=new Dictionary<Color,int>();var b=new Bitmap(a[0]);
int n,x,y,w=b.Width,h=b.Height;
for (x=w;x-->0;)for(y=h;y-->0;){var p=b.GetPixel(x,y);d[p]=d.ContainsKey(p)?d[p]+1:1;}
y=h;foreach(var q in d.OrderBy(v=>v.Value)){for(n=q.Value;n-->0;){
if(x<=0){x=w;--y;}b.SetPixel(--x, y, q.Key);}}b.Save("o");
}}

Formatação legível, cortesia do VS2010

using System.Collections.Generic;
using System.Linq;
using System.Drawing;

class P
{
    static void Main(string[] a)
    {
        var d = new Dictionary<Color, int>();
        var b = new Bitmap(a[0]);
        int n,x,y,w = b.Width, h=b.Height;

        for (x = w; x-- > 0;)    
            for (y = h; y-- > 0;)
            {
                var p = b.GetPixel(x, y);
                d[p] = d.ContainsKey(p) ? d[p]+1 : 1;
            }
        y = h;
        foreach (var q in d.OrderBy(v => v.Value))
        {
            for (n = q.Value; n-- > 0; )
            {
                if (x <= 0)
                {
                    x = w;
                    --y;
                 }
                 b.SetPixel(--x, y, q.Key);
            }
        }
        b.Save(a[0]+".");
    }
}
edc65
fonte
Pode ser que eu esteja errado, mas eu acho que você pode remover as novas linhas depois {caracteres
sergiol
E antes dos }caracteres
sergiol 05/04
Quess algo como tio.run/##VY/Ba8IwGMX/… funcionaria!
Sergiol #
1

Python 2: 191 bytes

Aqui está a minha tentativa. Imaginei que poderia economizar algum espaço usando Counter, mas não acabou tão pequeno quanto a resposta de Pietu1998.

from collections import Counter
from PIL import Image
i=Image.open(raw_input())
s=reduce(lambda x,y:x+y,map(lambda(a,b):[a]*b,Counter(i.getdata()).most_common()))
i.putdata(s)
i.save("o.png")

Saída do Panda

Saída do Panda

danmcardle
fonte