Sortieren Sie alle Pixel eines Bildes nach der Anzahl der Vorkommen

8

Eingang

Der Name einer Datei im Raster-Grafikformat Ihrer Wahl. Das gewählte Format muss mindestens 8 Bit pro Kanal und 3 Kanäle unterstützen.

Ausgabe

Eine Datei im selben Format mit denselben Abmessungen und Pixeln wie die erste, deren Pixel jedoch in absteigender Reihenfolge der Häufigkeit ihres Auftretens gruppiert sind, sortiert von links nach rechts, von oben nach unten.

  • Wenn bestimmte Farben von Pixeln gleich oft angezeigt werden, ist ihre Reihenfolge nicht angegeben.
  • Sie dürfen die Eingabedatei nicht überschreiben (verwenden Sie einen anderen Dateinamen für die Ausgabe).
  • Alle Bildverarbeitungsbibliotheken von Drittanbietern sind zulässig.

Beispiel

Panda

Gibt eine Ausgabe ähnlich wie:

sortierte Pixel aus Panda-Bild

Insbesondere in den unteren Teilen des Bildes können Abweichungen auftreten, da zwischen Farben gleicher Frequenz unterschiedliche Bindungen unterbrochen werden.

EMBLEM
quelle
1
Können wir andere Dateiformate wie PNM für die Ausgabe verwenden?
FUZxxl
@EMBLEM Ich bin mir nicht sicher, was du mit "auf Graustufen verzichten" meinst.
FUZxxl
@ MartinBüttner Guter Punkt, ich habe es in Eingabe und Ausgabe in den gleichen Formaten geändert.
EMBLEM
1
@EMBLEM Ich denke, er meinte "Bindungen" wie in "zwei Pixel treten mit der gleichen Frequenz auf". Kann ich davon ausgehen, dass ihre Bestellung in diesem Fall nicht angegeben ist?
FUZxxl
1
Um bei der Eingabe / Ausgabe klar zu sein ... können wir eine Zeichenfolge (Dateiname), einen Bytestrom oder ein FileObjekt vom komplexen Typ verwenden ...? Das würde in einigen Sprachen einen großen Unterschied machen.
Geobits

Antworten:

4

J, 94 81 Bytes

Eine Funktion, die den Namen einer PNG-Datei (ohne Transparenzkanal) verwendet und das Ergebnis in den mit "o" vorangestellten Eingabedateinamen schreibt.

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

Eingang Ausgabe

Methode

  • Erstellen Sie eine Liste aller Farbnummern und der Anzahl ihrer Erscheinungen
  • Sortieren Sie die Liste nach der Anzahl ihrer Erscheinungen
  • Multiplizieren Sie jede Farbzahl mit ihrem Aussehen
  • Passen Sie die neue Liste an die Form des Originalbilds an
randomra
quelle
Sie können ein Zeichen speichern, wenn Sie die Funktion dyadisch machen und das sortierte PNG in speichern x.
FUZxxl
@FUZxxl Es würde tatsächlich 3 Zeichen sparen, aber ich denke nicht, dass dies mit der Spezifikation übereinstimmt. Ich könnte das Bild auch in einer 1-Buchstaben-Datei ohne Erweiterung speichern, aber das ist nicht zu elegant.
Randomra
@FUZxxl Nun, es stellte sich heraus, dass es einige zusätzliche Zeichen im Körper der Funktion gab ...
randomra
Ich spreche kein J, aber in der Spezifikation gibt es eine Zeichenfolge als Eingabe. Hier ist der Name der Eingabedatei im Programm fest codiert.
edc65
@ edc65 Wenn Sie in J eine Funktion definieren, greift das yZeichen immer auf das Argument zu . (Wenn Sie eine Funktion mit zwei Argumenten definieren, auf die zugegriffen wird, xund ySie keine Funktionen mit mehr Argumenten definieren können.)
randomra
6

Mathematica, 125 123 Bytes

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

Dies definiert eine unbenannte Funktion, die den Dateinamen in einem beliebigen gängigen Bildformat verwendet und das Ergebnis in eine Datei mit demselben Namen schreibt, der jedoch vorangestellt ist a. Das Ergebnis sieht ein bisschen anders aus als das der OPs, da Mathematica die SortByBindungen standardmäßig sortiert, sodass die unteren Bits, in denen viele Bindungen auftreten, etwas ordentlicher aussehen:

Kein Panda.

Die Implementierung selbst ist sehr einfach:

  • ImageData um ein Raster mit Farbwerten zu erhalten.
  • Join um das Array zu reduzieren.
  • Tally um das Auftreten jeder Farbe zu zählen.
  • SortBy[...,-Last@#&] nach Frequenzen vom höchsten zum niedrigsten sortieren.
  • ConstantArrayund Joindie Tallies wieder zu erweitern.
  • ArrayReshapeum die ursprüngliche Bildform wiederherzustellen (erhalten mit Dimensions).
  • Image um die Daten wieder in ein Bildobjekt zu konvertieren.

Zu Ihrer Information, 22 Bytes werden für Datei-E / A verwendet. Eine äquivalente Version, die ein Bildobjekt akzeptiert und zurückgibt, hat eine Größe von 103 Byte:

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

Änderungsprotokoll

Kürzere Version von 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)

Lass es uns wenigstens versuchen, obwohl es bereits geschlagen ist.

Es ist extrem langsam, Panda hat einige Minuten auf meinem Laptop verarbeitet.

Speichert mit einem Dateinamen, wobei der ursprüngliche Dateiname zweimal wiederholt wird.

Panda

PurkkaKoodari
quelle
Sie können 32 Bytes mit verwenden i=open(raw_input());d=list(i.getdata());i.putdata(sorted(d,key=lambda D:d.count(D)));i.save('o.png'), obwohl dies für große Bilder sehr, sehr langsam ist (ruft list.count für jedes Pixel auf).
stokastic
@stokastic Nun, ich werde das hinzufügen, aber ich danke Ihnen dafür. Ich lese den Namen lieber einer Variablen vor (was ist, wenn der Benutzer ein Bild mit dem Namen o.png
eingibt
Meinetwegen! :)
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()

Das pngModul, das ich verwendet habe .

EMBLEM
quelle
2
Vielen Dank für die Bereitstellung einer Referenzlösung! Normalerweise fügen wir diese in den Herausforderungsbeitrag selbst ein, damit die Leute sie leichter finden können, aber es ist auch in Ordnung, sie als Antwort zu veröffentlichen.
FUZxxl
1

C # 413

Komplettes Programm. Übergeben Sie den Dateinamen in die Befehlszeile, die Ausgabe wird im gleichen Format wie die Datei "o" gespeichert.

Einige nette Funktionen von linq wie SelectMany und Enumerable.Range werden nicht verwendet, da das Programm sauberer, aber länger wäre.

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

Lesbare Formatierung mit freundlicher Genehmigung von 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
quelle
Vielleicht irre ich mich, aber ich denke, Sie können die Zeilenumbrüche nach {Zeichen entfernen
Sergiol
Und vor den }Zeichen
Sergiol
Ich frage so etwas wie tio.run/##VY/Ba8IwGMX/… würde funktionieren!
Sergiol
1

Python 2: 191 Bytes

Hier ist mein Versuch. Ich dachte, ich könnte vielleicht etwas Platz sparen Counter, aber es war nicht so klein wie die Antwort von 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")

Ausgabe von Panda

Ausgabe von Panda

Danmcardle
quelle