Ordenar todos los píxeles de una imagen por el número de ocurrencias

8

Entrada

El nombre de un archivo en el formato de gráficos de trama que elija. El formato elegido debe admitir al menos 8 bits por canal y 3 canales.

Salida

Un archivo en el mismo formato, con las mismas dimensiones y píxeles que el primero, pero cuyos píxeles se agrupan en orden descendente de la cantidad de veces que ocurren, ordenados de izquierda a derecha, de arriba a abajo.

  • Si ciertos colores de píxeles aparecen la misma cantidad de veces, su orden no se especifica.
  • No debe sobrescribir el archivo de entrada (use un nombre de archivo diferente para la salida).
  • Se permiten todas y cada una de las bibliotecas de procesamiento de imágenes de terceros.

Ejemplo

panda

Dará una salida similar a:

píxeles ordenados de la imagen de panda

Especialmente en las partes inferiores de la imagen puede haber alguna variación, debido a la ruptura de lazos entre colores de igual frecuencia.

EMBLEMA
fuente
1
¿Podemos usar otros formatos de archivo, como PNM, para la salida?
FUZxxl
@EMBLEM No estoy seguro de lo que quieres decir con "renunciar a la escala de grises".
FUZxxl
@ MartinBüttner Buen punto, lo he cambiado a entrada y salida con los mismos formatos.
EMBLEMA
1
@EMBLEM Creo que se refería a "lazos" como en "dos píxeles ocurren con la misma frecuencia". ¿Puedo suponer que su orden no está especificada en este caso?
FUZxxl
1
Para ser claros en la entrada / salida ... ¿podemos usar una cadena (nombre de archivo), una secuencia de bytes o un Fileobjeto de tipo complejo ...? Eso marcaría una gran diferencia en algunos idiomas.
Geobits

Respuestas:

4

J, 94 81 bytes

Una función que toma el nombre de un archivo PNG (sin canal de transparencia) y escribe el resultado en el nombre de archivo de entrada precedido por "o".

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

entrada salida

Método

  • Cree una lista de cada número de color y el número de sus apariencias
  • Ordenar la lista por el número de apariencias
  • Multiplica cada número de color por sus apariencias
  • Cambie la forma de la nueva lista a la forma de la imagen original
randomra
fuente
puede guardar un carácter si hace que la función sea diádica y guarde el PNG ordenado x.
FUZxxl
@FUZxxl En realidad, ahorraría 3 caracteres, pero no creo que esté en línea con la especificación. También podría guardar la imagen en un archivo sin extensión de 1 letra, pero eso no es demasiado elegante.
randomra
@FUZxxl Bueno, resultó que había algunos caracteres adicionales en el cuerpo de la función ...
randomra
No hablo J, pero en la especificación hay una cadena como entrada. Aquí el nombre del archivo de entrada está codificado en el programa.
edc65
@ edc65 En J, si define una función, el argumento siempre tiene acceso al argumento y. (Si se define una función con dos argumentos los que se accede por xy yy no se puede definir funciones con más argumentos.)
randomra
6

Mathematica, 125 123 bytes

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

Esto define una función sin nombre que toma el nombre del archivo en cualquier formato de imagen común y escribe el resultado en un archivo con el mismo nombre pero antepuesto a. El resultado se ve un poco diferente de los OP, ya que Mathematica SortByrompe los lazos por orden de clasificación predeterminado, por lo que los bits inferiores donde se producen muchas ataduras se ven un poco más limpios:

No es un panda

La implementación en sí es realmente sencilla:

  • ImageData para obtener una cuadrícula de valores de color.
  • Join para aplanar la matriz.
  • Tally para contar la ocurrencia de cada color.
  • SortBy[...,-Last@#&] ordenar por frecuencias de mayor a menor.
  • ConstantArrayy Joinpara ampliar los recuentos de nuevo.
  • ArrayReshapepara recuperar la forma de la imagen original (obtenida con Dimensions).
  • Image para volver a convertir los datos en un objeto de imagen.

Para su información, se usan 22 bytes en el archivo de E / S. Una versión equivalente que toma y devuelve un objeto de imagen viene en 103 bytes:

(i=ImageData@#;Image@ArrayReshape[Join@@ConstantArray@@@SortBy[Tally[Join@@i],-Last@#&],Dimensions@i])&
Martin Ender
fuente
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)

Registro de cambios

Versión más corta de 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)

Bueno, al menos intentemos, aunque ya esté vencido.

Es extremadamente lento, Panda procesó durante varios minutos en mi computadora portátil.

Guarda con un nombre de archivo con el nombre de archivo original repetido dos veces.

panda

PurkkaKoodari
fuente
puede guardar 32 bytes mediante el uso i=open(raw_input());d=list(i.getdata());i.putdata(sorted(d,key=lambda D:d.count(D)));i.save('o.png'), aunque es muy lento para imágenes grandes (llamadas list.count en cada píxel).
estocástico
@stokastic Bueno, lo agregaré, pero te doy crédito por ello. Prefiero leer el nombre de una variable (¿y si el usuario o.png
ingresa
¡lo suficientemente 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()

El pngmódulo que usé .

EMBLEMA
fuente
2
¡Gracias por proporcionar una solución de referencia! Por lo general, los incluimos en la publicación de desafío para que las personas puedan encontrarlos más fácilmente, pero publicarlos como respuesta también está bien.
FUZxxl
1

C # 413

Programa completo Pase el nombre del archivo en la línea de comando, la salida se guarda en el mismo formato que el archivo "o".

No usar algunas características interesantes de linq, como SelectMany y Enumerable.Range, ya que el programa sería más limpio pero más largo.

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");
}}

Formateo legible por cortesía de 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
fuente
Puede que me equivoque, pero creo que puedes eliminar las nuevas líneas después de los {caracteres
sergiol 05 de
Y antes de los }caracteres
sergiol 05 de
¡Cuestiono que algo como tio.run/##VY/Ba8IwGMX/… funcionaría!
sergiol
1

Python 2: 191 bytes

Aquí está mi intento. Pensé que podría ahorrar algo de espacio usando Counter, pero no terminó tan pequeño como la respuesta 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")

Salida de Panda

Salida de Panda

danmcardle
fuente