Hinweis : Anders Kaseorg hat vorerst die Auszeichnung erhalten, um auf seine großartige Antwort aufmerksam zu machen, aber die Herausforderung ist noch lange nicht vorbei! Es gibt immer noch eine 400-Punkte-Prämie im Angebot für alle, die die höchste Punktzahl erreichen, ohne die integrierte Komprimierung zu verwenden.
Unten ist eine 386x320
PNG-Darstellung von Van Goghs Sternennacht.
Ihr Ziel ist es, dieses Bild in maximal 1024 Byte Code so genau wie möglich wiederzugeben. Für die Zwecke dieser Herausforderung wird die Bildnähe anhand der quadratischen Unterschiede der RGB-Pixelwerte gemessen, wie nachstehend erläutert wird.
Das ist eine Code-Herausforderung . Die Bewertungen werden mit dem unten stehenden Validierungsskript berechnet. Die niedrigste Punktzahl gewinnt.
Ihr Code muss den folgenden Einschränkungen entsprechen:
- Es muss ein vollständiges Programm sein
- Es muss ein Bild in einem Format ausgegeben werden, das vom unten stehenden Überprüfungsskript auf meinem Computer gelesen werden kann. Das Skript verwendet die PIL-Bibliothek von Python, mit der eine Vielzahl von Dateiformaten geladen werden können , darunter png, jpg und bmp.
- Es muss vollständig in sich geschlossen sein, keine Eingaben machen und keine Dateien laden (außer das Importieren von Bibliotheken, was erlaubt ist).
- Wenn Ihre Sprache oder Bibliothek eine Funktion enthält, die Sternennacht ausgibt, dürfen Sie diese Funktion nicht verwenden.
- Es sollte deterministisch ablaufen und jedes Mal die gleiche Ausgabe erzeugen.
- Die Abmessungen des Ausgabebildes müssen sein
386x320
- Zur Vermeidung von Zweifeln: Für gültige Antworten müssen Programmiersprachen gemäß den üblichen PPCG-Regeln verwendet werden . Es muss ein Programm sein, das ein Bild ausgibt, nicht nur eine Bilddatei.
Es ist wahrscheinlich, dass einige Einsendungen selbst durch Code generiert werden. Wenn dies der Fall ist, geben Sie in Ihrer Antwort bitte den Code an, mit dem Ihre Einreichung erstellt wurde , und erläutern Sie die Funktionsweise. Die obigen Einschränkungen gelten nur für das von Ihnen eingereichte 1-KB-Image-Generierungsprogramm. Sie gelten nicht für Code, der zum Generieren verwendet wird.
Wertung
Um Ihre Punktzahl zu berechnen, nehmen Sie Ihr Ausgabebild und das obige Original und konvertieren Sie die RGB-Pixelwerte in Gleitkommazahlen zwischen 0 und 1. Die Punktzahl eines Pixels ist (orig_r-img_r)^2 +(orig_g-img_g)^2 + (orig_b-img_b)^2
der quadratische Abstand im RGB-Raum zwischen den beiden Bildern. Die Punktzahl eines Bildes ist die Summe der Punktzahlen seiner Pixel.
Im Folgenden finden Sie ein Python-Skript, das diese Berechnung durchführt. Bei Inkonsistenzen oder Unklarheiten wird die endgültige Punktzahl von dem Skript berechnet, das auf meinem Computer ausgeführt wird.
Beachten Sie, dass die Punktzahl basierend auf dem Ausgabebild berechnet wird. Wenn Sie also ein verlustbehaftetes Format verwenden, wirkt sich dies auf die Punktzahl aus.
Je niedriger die Punktzahl, desto besser. Das Originalbild der Sternennacht hätte eine Punktzahl von 0. Im astronomisch unwahrscheinlichen Fall eines Unentschieden entscheidet die Antwort mit den meisten Stimmen über den Gewinner.
Bonusziele
Da die Antworten von Lösungen mit integrierter Komprimierung dominiert wurden, habe ich eine Reihe von Prämien für Antworten vergeben, die andere Techniken verwenden. Das nächste wird eine Prämie von 400 Punkten sein , die vergeben wird, wenn eine Antwort, die keine eingebaute Komprimierung verwendet, insgesamt den ersten Platz einnimmt.
Die zuvor zuerkannten Bonusprämien waren wie folgt:
Für die Antwort von nneonneo wurde ein Kopfgeld von 100 Punkten vergeben, da dies die Antwort mit der höchsten Punktzahl war, die zu diesem Zeitpunkt keine eingebaute Komprimierung verwendete. Es hatte 4852,87 Punkte zum Zeitpunkt der Vergabe. Lobende Erwähnungen gehen an 2012rcampion, der einen tapferen Versuch unternahm, Nneonneo mit einem Ansatz zu schlagen, der auf Voronoi-Tesselation beruhte und 5076 Punkte erzielte, und an Sleafar, dessen Antwort mit 5052 Punkten bis zum Ende in Führung lag, mit einer ähnlichen Methode wie nneonneo.
Für Strawdogs Beitrag wurde eine Prämie von 200 Punkten vergeben . Dies wurde als optimierungsbasierte Strategie ausgezeichnet, die die Führung unter den nicht integrierten Komprimierungsantworten übernahm und eine Woche lang hielt. Mit einer beeindruckend cleveren Methode erzielte es 4749,88 Punkte.
Scoring / Validierungsskript
Das folgende Python-Skript sollte im selben Ordner wie das Bild oben (das benannt werden sollte ORIGINAL.png
) abgelegt und mit einem Befehl des Formulars ausgeführt werden python validate.py myImage.png
.
from PIL import Image
import sys
orig = Image.open("ORIGINAL.png")
img = Image.open(sys.argv[1])
if img.size != orig.size:
print("NOT VALID: image dimensions do not match the original")
exit()
w, h = img.size
orig = orig.convert("RGB")
img = img.convert("RGB")
orig_pix = orig.load()
img_pix = img.load()
score = 0
for x in range(w):
for y in range(h):
orig_r, orig_g, orig_b = orig_pix[x,y]
img_r, img_g, img_b = img_pix[x,y]
score += (img_r-orig_r)**2
score += (img_g-orig_g)**2
score += (img_b-orig_b)**2
print(score/255.**2)
Technische Anmerkung: Objektive Messungen der Bildähnlichkeit sind eine schwierige Sache. In diesem Fall habe ich mich für eine entschieden, die für jeden einfach zu implementieren ist, da ich weiß, dass es viel bessere Maßnahmen gibt.
Bestenliste
quelle
pip unistall PIL
, dannpip install pillow
) zu verwenden und die erste Zeile in zu ändernfrom PIL import Image
.Antworten:
Pyth (keine eingebaute Komprimierung), Score
4695.074656.034444.82Die einzige bildbezogene Funktion von Pyth ist das integrierte Schreiben einer Matrix von RGB-Tripeln als Bilddatei. Die verrückte Idee hier ist es, ein kleines tiefes neuronales Netzwerk auf die ( x , y ) ↦ ( r , g , b ) -Funktion zu trainieren , die das Bild darstellt, und es an den Koordinaten jedes Pixels auszuführen.
Der Plan
Das aktuelle Netzwerk besteht aus 45 Sigmoidneuronen, wobei jedes Neuron mit den Eingängen x , y und jedem vorherigen Neuron verbunden ist und die letzten drei Neuronen als r , g , b interpretiert werden . Es wird mit dem Adam- Algorithmus ohne Batching trainiert . Die Parameter, die die 1125 Verbindungen gewichten, werden unter Verwendung einer Variante der stochastischen Quantisierung auf einen Bereich von 93 möglichen Werten quantisiert (mit Ausnahme der konstanten Terme, die 93 2 mögliche Werte haben), wobei die primäre Variation darin besteht, den Gradienten für quantisierte Parameter auf Null zu setzen.
Das Ergebnis
Der Code
1023 Bytes, kodiert mit
xxd
(dekodiert mitxxd -r
). Ich habe die 2016-01-22-Version von Pyth verwendet, die zum Zeitpunkt der Veröffentlichung dieser Herausforderung aktuell war. Sie können den Code direkt in Pyth ausführen, aber Pyth in PyPy3 (pypy3 pyth starry.pyth
) führt ihn in etwa 3 Minuten neunmal schneller aus. Das Ausgabebild wird geschriebeno.png
.Wie es funktioniert
Ausbildung
Während meines letzten Trainingslaufs verwendete ich einen viel langsameren Quantisierungsplan und spielte interaktiv mit diesem und der Lernrate, aber der verwendete Code war ungefähr wie folgt.
Visualisierung
Dieses Bild zeigt die Aktivierung aller 45 Neuronen als Funktion der x , y- Koordinaten. Klicken um zu vergrößern.
quelle
Mathematica, Punktzahl 14125.71333
Speichert dieses Bild:
zu
a.png
.quelle
Java, 7399.80678201
Dies erinnerte mich an ein Projekt, das ich vor ein paar Semestern in meiner Klasse für numerische Berechnungen hatte und mit Hilfe der Polynominterpolation eine Silhouette des Mount Everest zeichnen sollte. Das wurde in MATLAB gemacht, aber ich mag MATLAB nicht sehr, also habe ich mich für Java entschieden. Die Grundidee dahinter ist, dass ich "intelligente" Punkte (hier als "zufällig" gelesen) für die Polynominterpolation ausgewählt habe. Mit den wenigen Bytes, die ich übrig hatte, habe ich eine Möglichkeit geschaffen, die Sterne zu zeichnen, was vor dem Zeichnen des Berges geschieht. Es kann möglich sein, den Code zu verdichten und ein weiteres Polynom für den Grund hinzuzufügen, um die Punktzahl zu verbessern.
Bearbeiten: Ich habe einige der Polynome hinzugefügt und geändert und alle Sterne hinzugefügt. Meine vorherige Punktzahl war 9807.7168935, wie Sie sehen, ist dies eine sehr große Verbesserung. Leider hat der Code einen Treffer in der Lesbarkeit erhalten, da ich die letzten Bytes auspressen musste, um alle Sterne zu erhalten und ihnen Gruppen zuzuweisen.
9807.7168935 Punkte: 7399.80678201 Punkte:
quelle
Python 3.4 +, 4697.26
Ich habe die gleiche Methode wie in meiner ImageMagick-Antwort verwendet, jedoch mit den folgenden Parametern:
Mit diesen Parametern habe ich das folgende 1003-Byte-Python-Programm generiert (ich habe keine Verbesserungen gegenüber der Ausgabemethode von @ kennytm gefunden):
Was wiederum dieses Bild erzeugt:
quelle
1
auslatin1
und ein Leerzeichen aus speichernimport *
, zumindest. Aber Golfen hatte keine Priorität (da es weniger als 1024 Bytes beträgt).Python 3, Punktzahl 5701,31
Skalieren Sie einfach ein 18 × 13 PNG-Bild neu.
quelle
Java, 8748,95
Ein anderer Ansatz:
Ich habe eine Klasse erstellt, die aus einer gegebenen Menge von Punkten ein Voronoi-Diagramm berechnet . Diese Punktmenge wird als Parametersatz verwendet, der als Eingabe für den Apache BOBYQAOptimizer dient . Die Auswertungsfunktion des Optimierers nimmt die Punkte und erstellt daraus ein Voronoi-Diagramm. Die Voronoi-Regionen werden mit der Durchschnittsfarbe der entsprechenden Region des Originalbilds gefärbt.
Der Optimierungsprozess wird hier gezeigt:
Das endgültige Bild ist dieses:
Das ergibt eine Punktzahl von 8748,95
(Dies wurde mit meiner eigenen Funktion gemessen, sollte aber mit dem Auswertungsskript identisch sein.)
Das Ergebnis dieses Prozesses ist nur eine Menge von 8 Punkten und den entsprechenden Farben. (Eine höhere Punktzahl führte zu schlechteren Ergebnissen, aber ich habe das nicht wirklich ausgiebig ausprobiert).
Der resultierende Code wird hier angezeigt (Entschuldigung, ich musste ein wenig Golf spielen, um ihn in das 1-kB-Limit zu drücken):
(Ich weiß, es gibt einige einfache Möglichkeiten, die bessere Ergebnisse hätten erzielen können, aber ... das hat irgendwie Spaß gemacht ...)
Als Antwort auf den Kommentar zum künstlerischen Stil eines solchen Voronoi-Bildes mit einer größeren Anzahl von Punkten: Dies sieht in der Tat interessant aus, und einige Bildbearbeitungswerkzeuge bieten dies tatsächlich als "Mosaikfilter" an - zum Beispiel das Mosaikfilter in GIMP ( Dies bietet jedoch Optionen zum Hervorheben der Kanten usw.).
Hier ist ein Beispiel für das Sternennacht-Bild mit 256 Punkten. (Diese werden zufällig ausgewählt, aber mit einer größeren Anzahl von Punkten verschwindet die Verbesserung, die durch eine Optimierung erreicht werden könnte.)
Dies ist nicht Teil des Wettbewerbs (da es nicht in 1kB passt), nur für die Neugierigen:
quelle
import java.util.*;
Tatsächlich alle Importklassen in Sternchen ändern.AutoIt ,
9183.257882.53AKTUALISIEREN
Es stellt sich also heraus, dass das Neuzeichnen des Bildes wie bei einem (betrunkenen) Kleinkind effektiver ist, als das Speichern einer beliebigen Version des Bildes. (Effizienter als meine alte Lösung).
Jede Linie, die ein Element zeichnet, ist entscheidend, um die Punktzahl zu verringern. Ich vermute, dass dieses Programm mit nur geringfügigen Änderungen Punktzahlen weit unter 7000 erzielen kann, da jede einzelne Änderung enorme (~ 20 bis 100 Punkte) Auswirkungen auf die Punktzahl hat. Das Programm verwendet meine
processing
Grafikbibliothek, die knappe Funktionsnamen zum Zeichnen mit GDI bereitstellt.Da es sich bei dieser Lösung um eine Zufallslösung handelt, setzen wir den PRNG mit dem konstanten Wert unter
0
Verwendung vonSRandom(0)
. Warum 0? Weil es bis zu 50 Punkte besser ist als alle anderen, dien<=100
ich ausprobiert habe.Die Leinwand beginnt als Leerzeichen
#587092
.Den Boden schaffen
Der untere Teil des Bildes (der sich herausstellt, dass er bei genau 233px beginnt [wieder wegen der Punkte]) wird mit genau
int(1e4*2.9)
Ellipsen gefüllt . Durch Ändern des Faktors (oder einer Dezimalstelle des Faktors) kann die Punktzahl um Hunderte von Punkten verringert und erhöht werden. Ich entschied mich nach ein paar Versuchen für 2,9. Dies dauert natürlich einige Zeit (einige Sekunden).Eine fünffarbige Palette wird mitgeliefert:
Kleckse auf dem Boden
Vier Ellipsen werden verwendet, um kontrastreiche Akzente im Bodenbereich zu setzen (
$4
ist ein Funktionszeiger aufellipse()
):Akzente am Himmel setzen
Einige Linien werden mit einem dickeren Stift gezeichnet, um signifikante Farbbereiche innerhalb des Himmels darzustellen, die für Ellipsen zu stark gedehnt sind:
Wiegen der Pixel
Danach wird alles gespült und wiederholt, bis die Bytes aufgebraucht sind. Dann wird eine Unschärfe angewendet, um die Validierungsmethode auszutricksen. Durch rohe Gewalt wurde festgestellt, dass ein Radius von genau 20 das beste Ergebnis liefert. Dies verbessert die Punktzahl um ca. 1,5k (!).
Endgültiges Bild
Code, 985 Bytes
ALTE ANTWORT
Hier werden 80 Farbwerte gespeichert, die ein 10 x 8 Pixel großes Bild ergeben. Dieses Rohbild hat eine Punktzahl von 10291. Da 10x8 ein Pixelfaktor von 40px ist, wird eine Gaußsche Unschärfe mit einem Radius von 40px angewendet, um die Punktzahl zu verringern. So erreicht das Skript 9183.25.
Dies sind die gespeicherten Daten:
Die erzeugte Datei ist True.png:
Das Programm ist 998 Bytes lang:
quelle
1e4*2.9
gleich29e3
?Windows BAT-Datei, Punktzahl 4458.854
Die Programmgröße beträgt 1024 Bytes.
Konvertiert ein Base64-codiertes BPG-Bild in PNG.
Verwendet certutil.exe (Standard-Windows-Dienstprogramm) und den Image-Decoder bpgdec.exe als Bibliotheken.
Kompression:
quelle
C ++ 11,
7441.681261056997.654348335198.16107651Weitere Updates
Ich mochte die Ellipsen von Perl so sehr, dass ich sie in C ++ 11 ausprobieren musste. Ich habe die rohe Zeichenfolge verwendet, um Bytes dorthin zu schieben, aber für eine Weile bekam ich eine leichte Diskrepanz mit der erwarteten Punktzahl und dem generierten Code. Es stellt sich heraus, dass Sie kein rohes 0x0d (Carriage Return) setzen können, da g ++ dies in 0x0a (New Line) konvertiert. Ich bin mir ehrlich gesagt nicht sicher, wie legitim diese generierte Quelle ist, aber sie wird auf einigen meiner Maschinen kompiliert und funktioniert.
Ich habe auch einen anderen Algorithmus ausprobiert, Adaptive Dimensional Search, nachdem der GA ins Stocken geraten zu sein schien, nur um zu versuchen, das lokale Minimum abzubauen und vielleicht Glück zu haben und in einen anderen Brunnen zu fallen.
Damit liefert C ++ 11 ein überraschend konkurrenzfähiges Ergebnis (weitaus besser, als ich ursprünglich vermutet hätte) ... Ich bin ziemlich überrascht, dass dies mit fstream als einzigem Include möglich ist.
Text (ja, die Zeilenumbrüche befinden sich in der eigentlichen Quelle ... ich könnte sie wahrscheinlich entfernen):
Hexdump:
Diese Antwort kombiniert mehrere Ansätze aus früheren Antworten, die ich unten erläutern werde. Leider musste ich das Programm etwas golfen, um in
944949 Zeichen (lautwc -c
) zu passen , so dass es nicht mehr wie C ++ aussieht (entschuldigt, wenn Dies verstößt gegen die Regeln der Herausforderung. Ich werde in Kürze versuchen, einige Verbesserungen vorzunehmen. Das habe ich anfangs nicht geplant, deshalb ist es immer noch nicht völlig unkenntlich und es gibt immer noch jede Menge tief hängende Früchte.Aktualisierte Ergebnisse
Nur den genetischen Algorithmus länger laufen zu lassen, hat zu einem etwas besseren Ergebnis geführt; Angesichts der Tatsache, dass sich die Konvergenz erheblich verlangsamt hat, würde ich sagen, dass diese spezielle Methode wahrscheinlich das Beste ist (oder ich bin in ein tiefes lokales Minimum gefallen). Ich habe das endgültige Programm noch ein wenig weiter ausgearbeitet, um ein paar Rechtecke mehr zusammenzudrücken (der Generator bleibt derselbe, außer dass die maximale Genomgröße erhöht wurde).
Das Implementieren des Crossovers zwischen Individuen wird helfen, wenn das Problem ein tiefes lokales Minimum ist, aber da es für eine Weile im selben Bereich bleibt, denke ich, dass dies in etwa so gut ist, wie es für die Anzahl der Rechtecke geht.
Voronoi Version, 7331.92407536, 989 Zeichen
Ich habe die Voronoi-Idee von Marco13 mit meinem GA-Code verwendet. Das hat tatsächlich nicht so gut funktioniert, wie ich gehofft hatte. Ich konnte nur ein paar Punkte mehr einpressen als Rechtecke. Ich denke, die potenziell unzusammenhängende Natur der Rechtecke aufgrund von Überlappungen hilft der Partitur ein bisschen. Ungeachtet dessen gefällt mir die Art und Weise, wie dies deutlich besser aussieht, trotz der ähnlichen Punktzahl wie bei meinem ersten Eintrag.
Alte Ergebnisse, 7441.68126105, 944 Zeichen
Ähnlich wie bei einigen anderen Einträgen zeichnet das Programm nur überlappende Rechtecke. Es verwendet binäres PPM, da das Format einfach ist (die Ausgabe ist
a.ppm
, aber ich habe eine PNG-Version hochgeladen, da SE das PPM nicht mochte) und es ist vollständig deterministisch.Erläuterung
Das Erzeugen des PPM nahm einen guten Teil des Boilerplate-Codes in Anspruch, was bedeutete, dass ich selbst nach einigem Golfen nicht zu viele Rechtecke haben konnte. Hier können wahrscheinlich noch ein paar mehr eingedrückt werden, um die Punktzahl weiter zu verbessern.
Die wahre Magie ist die Liste der Rechtecke. Ähnlich wie bei Wolfgang verwendete ich einen genetischen Algorithmus, um diese zu finden. Tatsächlich ist die Implementierung weitgehend unvollständig, da eine Rekombination zwischen Individuen noch nicht erfolgt, aber dennoch eine Mutation auftritt und die turnierartige Rangfolge nach Fitness die besten Organismen in der nächsten Runde behält. Elitismus wird auch verwendet, da eine Kopie des besten Individuums aus der letzten Runde in der nächsten Runde aufbewahrt wird, sodass der am besten geeignete Organismus immer mindestens so fit ist wie in der vorherigen Runde.
Ich habe mir den Code von Wolfgang seit meinem gestrigen Start nicht mehr so genau angesehen, aber anscheinend lässt er auch die Farbe variieren, was möglicherweise den Unterschied zwischen den Werten erklärt.
Um den Suchraum kleiner zu halten, habe ich nur die Rechteckposition betrachtet. Die Farbe wird anhand des kanalweisen Durchschnitts der sichtbaren Pixel aus diesem Rechteck berechnet, da wir das Ausgangsbild haben (ich glaube, wir können für dieses bestimmte Rechteck nichts Besseres tun, da dies den Quadratabstand minimiert).
Ich werde in den nächsten Änderungen ein Github-Repository erstellen, wenn ich weiter daran arbeite, aber der (Single-File-) Code befindet sich derzeit im Pastebin . Kompilieren Sie es im C ++ 11-Modus (Randnotiz: Es ist mir ziemlich peinlich, wie unordentlich es selbst für einen Einzelgänger ist).
Sie benötigen auch ein P3 PPM-Bild der Sternennacht, das
ORIGINAL.ppm
für diese Funktion benannt ist . Sie können die Datei von diesem GitHub Gist herunterladen .quelle
i r,g,b
statt separat deklariert und viele Leerzeichen verworfen werden). Ich war mir nicht sicher, ob das Programm die Datei direkt generieren sollte oder ob die Weiterleitung zu stdout / stderr in Ordnung war.#include <fstream>
? Löschen Sie auch die Zeilenumbrüche und schreiben Sie alles in eine Zeile, da C ++ sowieso Semikolons benötigtImageMagick, 4551,71
Verwendet die 'Programmiersprache' von ImageMagick und verwendet dabei die folgenden Optionen (Sie müssen möglicherweise das Kommando verlassen
!
):Angenommen, die folgende 968-Byte-Quelldatei (als Hexdump angegeben):
Herstellung dieses Bildes:
Sie fragen sich wahrscheinlich, wie ich die Eingabedatei generiert habe, und die Antwort ist ziemlich einfach. Ändern Sie die Größe mit dem Lanczos-Filter auf 48 x 40, verwenden Sie eine mit 20 Farben indizierte Palette und optimieren Sie das resultierende PNG.
Verwendet
convert
,pngquant
,optipng
undadvdef
.quelle
=(tail +2 $0)
Trick aus meiner Antwort können Sie ein einzelnes ZSH-Skript erstellen, das sowohl das ImageMagick-Skript als auch die PNG-Eingabedatei enthält.Python 2, 4749,88
1018 Bytes
Dieses Problem hat wohl inzwischen jeder vergessen, außer mir ....
Dieses Problem interessierte mich viel zu sehr, zumal sich schnell herausstellte, dass Ansätze mit Bildkomprimierungsalgorithmen zwar eindeutig die Nase vorn hatten, aber aus ästhetischer Sicht dennoch irgendwie unbefriedigend waren. Ansätze, die auf der Optimierung einer Reihe von Zeichnungsprimitiven basierten, waren vom Standpunkt der Code-Ästhetik aus gesehen etwas angenehmer, schienen jedoch knapp über der 5000-Punkte-Marke blockiert.
Die Methode von nneonneo, bei der keine Standard-Bildkomprimierung verwendet wurde, übertrifft die Marke von 5000, dies geschieht jedoch, indem ein winziges Bild codiert und hochskaliert wird.
Hier ist ein Programm, das nur Zeichenprimitive verwendet, automatisch durch eine Optimierungsmethode generiert wird und eine Punktzahl von 4749,88 erzielt.
was so aussieht:
und der Hexdump des Codes:
Es verwendet eine Reihe von Tricks, die zuvor hier verwendet wurden:
Als erstes Grundelement platziere ich eine Horizontlinie, die das Bild in zwei verschiedenfarbige Blöcke aufteilt. Danach habe ich als Grundelement einen Kreis verwendet, der zwischen zwei Punkten gezogen wurde. Dies sah für mich vage wie ein Pinselstrich aus, konnte aber in 7 Bytes ausgedrückt werden. Für den Suchvorgang habe ich eine geführte Mustersuche verwendet. Es wird fortgefahren, indem abwechselnd ein Grundelement hinzugefügt und dessen Parameter optimiert werden. Das Grundelement wird an dem Punkt hinzugefügt, an dem der verschwommene vorzeichenbehaftete Fehler am höchsten ist. Die Parameter werden nacheinander durch eine umfassende Linienoptimierung über einen kleinen Bereich optimiert. 40 bis 50 Grundelemente werden hinzugefügt und individuell optimiert. Dann wird die Liste der Grundelemente auf die Größe zurückgeschnitten, indem die Grundelemente weggeworfen werden, die der Bewertung am wenigsten helfen.
Dies übertrifft immer noch nicht Nneonneos Punktzahl. Um diese Punktzahl zu übertreffen, war eine zweite Optimierungsstufe erforderlich, bei der erneut Primitive auf verschiedenen Filterebenen hinzugefügt und Primitive weggeworfen wurden, um das generierte Programm auf die richtige Größe zu bringen. Was mich wirklich interessiert hat, war die Idee, dies auf andere Bilder anzuwenden. Ich habe es auf einige andere Bilder angewendet und hier in meinem Blog weitere Details und Animationen zu den gezeichneten Primitiven bereitgestellt .
Die beiden Programme, mit denen dies generiert wurde, passen nicht in den Speicherplatz, der für Stack Exchange-Posts zulässig ist, befinden sich jedoch in github: https://github.com/str4w/starrynight/tree/StackExchange
starrynight wird zuerst ausgeführt, gefolgt von stage2optimization. Das resultierende Programm befindet sich ebenfalls im selben Verzeichnis.
quelle
Matlab, Punktzahl 5388,3
Ohne eingebaute Kompression. Die Farbtiefe wird so reduziert, dass jedes Pixel durch ein druckbares Zeichen dargestellt werden kann. Und die Auflösung wird reduziert. Dies wird dann als String fest codiert. Der Code selbst kehrt den gesamten Prozess um. Für die Größenänderung wird ein Lanczos 3-Interpolationskern verwendet.
quelle
zsh + bpgdec, 4159.061760861207
Ja, eine andere BPG-Lösung. Ich denke, dies dient im Wesentlichen dazu, zu beweisen, dass BPG das beste derzeit verfügbare Bildkomprimierungsprogramm ist. Betrachten Sie es als eine Verbesserung gegenüber der BPG-Lösung von yallie .
Die Datei ist maximal 1024 Byte lang. Es besteht aus der Linie
gefolgt von der BPG-Rohausgabe von
In hex ist dies das Skript:
Die resultierende Datei ist
out.png
(derbpgdec
Standardspeicherort) und sieht folgendermaßen aus:Ich finde es ziemlich erstaunlich, dass
bpg
in nur 996 Bytes die scharfen Konturen des Baumes links und der Hügel rechts genau rekonstruiert wurden. Es hat sogar eine passable Annäherung für den Kirchturm! Der Detaillierungsgrad ist (für mich) für die kleine Dateigröße sehr beeindruckend. Natürlich ist esbpgdec
selbst kein kleines Programm, aber mir ist klar, dass BPG für die Bildkomprimierung eine Größenordnung besser ist als JPEG.Da dies verwendet wird
bpgdec
, ist diese Antwort offensichtlich nicht für die Prämie berechtigt.EDITED:
-n
Argument hinzugefügttail
, um es mit GNU kompatibel zu machentail
.quelle
tail: cannot open ‘+2’ for reading
. Auf Ubuntu braucht es-n +2
, was es auf 1025 Bytes bringt = /-n+2
was genau 1024 Bytes ergibt - versuchen Sie es und lassen Sie mich wissen, ob das funktioniert. Ich werde meine Antwort aus Kompatibilitätsgründen ändern.C 6641
999 Bytes, nur mit
stdio.h
undmath.h
.Ich habe eine
d()
Kreisfüllungsfunktion erstellt, die konzentrische RGB -Farbkreise über Radiuswerte r..0 zeichnet. Hier werden 21 Kreise verwendet. Ich könnte ein paar mehr einpressen, wenn ich mehr Whitespace weglassen würde, aber ich mag die relative Lesbarkeit in der jetzigen Form.Ich habe die grobe Kreisplatzierung mit Gimp-Ebenen im
Difference
Modus herausgefunden. Suchen Sie nach den hellen Stellen, fügen Sie einen Kreis hinzu und wiederholen Sie den Vorgang. VerwendetesHistogram
Werkzeug bei der Auswahl, um die zu verwendenden Anfangsfarben zu bestimmen.Ich habe mit den obigen Angaben eine Punktzahl von ungefähr 7700 erhalten, aber ich dachte mir, ich könnte es besser machen, wenn ich die Werte für Farbe und Radius ändere. Deshalb habe ich einen Code geschrieben, mit dem ich jeden Wert mit Brute-Force optimieren kann, indem ich -10 ändere. Rendern, Ausführen des Validators (den ich aus Geschwindigkeitsgründen in C umgeschrieben habe) und Speichern des Werts, der die niedrigste Punktzahl ergab. Am Ende wird das Wertearray ausgegeben, das ich wieder in den Code einfüge und neu kompiliere. Ich lief ein paar Pässe, und es senkte die Punktzahl um etwa 1000. Dann entfernte ich den Gerüstcode.
Code,
quelle
((x-xo)*(x-xo) + (y-yo)*(y-yo)) <= (r*r)
) scheint kürzer zu sein und die Abhängigkeit von auszuschließenmath.h
. Bei dieser Bildgröße glaube ich auch nicht, dass irgendetwas überlaufen könnte.Python 3, Score 5390,25, 998 Bytes
Ich habe ein simuliertes Glühprogramm verwendet, um Rechtecke in die Form der Sternennacht zu bringen. Anschließend werden die geraden rechteckigen Kanten mit einer Gaußschen Unschärfe geglättet.
Um einige Bytes zu sparen, habe ich die Rechteckdaten in Basis 94 komprimiert.
quelle
Python 2, 5238,59 Punkte
Es ist wahrscheinlich Zeit, meine eigene Antwort zu posten. Hier ist das Bild
Der Code sieht so aus
Oder als Hex-Dump:
Diese lange Zeichenfolge wird einfach in die Parameter zum Zeichnen von 95 durchscheinenden Ellipsen entpackt.
Wie viele andere Antworten wird der Code mithilfe eines genetischen Algorithmus generiert. Es verwendet eine bestimmte Art von genetischem Algorithmus, den ich erfunden habe, den ich "Genpool-Algorithmus" nenne, obwohl es durchaus möglich ist, dass jemand anderes ihn erfunden und ihm einen anderen Namen gegeben hat. Anstatt eine Population von Individuen zu haben, haben wir 95 "Genpools", einen für jedes Gen. Jeder Genpool enthält 10000 verschiedene Versionen des Gens. Ein Gen enthält die Parameter für eine Ellipse (Position, Form, Farbe, Alpha und deren Position in der z-Reihenfolge). Bei jeder Iteration erstellen wir zwei Bilder, indem wir aus jedem der 95 Pools ein Gen auswählen. Die Gene aus dem Bild mit der niedrigsten Bewertung ersetzen die Gene aus dem Bild mit der schlechtesten Bewertung mit einer kleinen Mutation.
Ich habe es bis zur 378000. Iteration ausgeführt, die ein paar Tage dauerte. Zu diesem Zeitpunkt ging die Punktzahl immer noch zurück, aber wirklich sehr, sehr langsam, so dass ich bezweifle, dass es ohne einige Änderungen am Algorithmus viel besser werden wird.
Hier ist der genetische Algorithmuscode:
Schließlich ist hier eine Animation , die den Algorithmus bei der Arbeit zeigt. Es zeigt das beste Bild, das bisher nach jeweils 1000 Iterationen generiert wurde. (Die GIF-Datei war viel zu groß, um sie in diesen Beitrag einzubetten.)
Es kann wahrscheinlich verbessert werden, indem (1) der Codierungstrick von nneonneo verwendet wird, um mehr Daten in den String zu stopfen; (2) Hinzufügen einer Gaußschen Unschärfe zum Ende des Rendering-Codes (was ihn jedoch langsamer macht) und (3) Verbessern des Algorithmus noch weiter. Im Moment erreicht es sehr schnell eine anständige Punktzahl, ändert sich dann aber sehr langsam - wenn ich die anfängliche Konvergenz irgendwie verlangsame, kann es am Ende zu einem besseren Ergebnis kommen. Vielleicht werde ich diese Dinge irgendwann umsetzen.
quelle
Starry ,
11428.189450210904.307927710874.1307958Sternenhimmel ist vielleicht nicht die beste Sprache dafür, aber sicherlich die passendste.
Sie können es online ausprobieren. Es scheint jedoch, dass die Ausgabe abgeschnitten ist, sodass Sie nicht das vollständige Bild erhalten.
Dieses Programm gibt eine unkomprimierte ppm-Datei aus, die standardmäßig ausgegeben wird.
Hier ist die Programmausgabe:
Erläuterung
Damit das Programm alle 123.520 erforderlichen Pixel ausgibt, habe ich das Bild in 8 horizontale Bänder unterteilt und 7 Schleifen erstellt, wobei die ersten 6 jeweils ein Band drucken, während das letzte zwei Bänder derselben Farbe druckt. Der Code besteht aus einem Header, der der ppm-Datei mitteilt, wie sie sich selbst formatieren soll, und den 7 oben genannten Schleifen.
quelle
Python 2, 4684.46
1021 Bytes.
Hierbei wird eine sehr ähnliche Dekodierungsmethode wie bei einigen anderen Antworten verwendet, jedoch in Python 2, sodass es sich um Base64-kodierte Daten anstelle von Base85 handelt.
Bei den codierten Daten handelt es sich um ein Bild im WebP-Format 64 x 48.
Hier ist der Code, mit dem ich die beste Bildgröße und Qualitätseinstellung gefunden habe. Ich habe den Suchbereich eingeschränkt, sodass die Ausführung nicht länger als ein paar Minuten dauert.
quelle
Python 2,
5098.245080.044869.154852.874755.88589004Keine eingebaute Dekompression verwendet! Nur das PIL-Dienstprogramm zur Größenänderung und ein manuell dekodiertes 16-Farben-Bild. Daher sollte es für die Prämie in Frage kommen.
Das Programm enthält eingebettete Nicht-ASCII-Zeichen. Es ist 1024 Bytes lang und sieht so aus:
und in hex:
und erzeugt dieses Bild:
Dieses Programm missbraucht die Tatsache, dass Sie im Grunde rohe Bytes in den Python-Quellcode verschieben können, solange Sie NULs und Backslashes umgehen.
Das Programm selbst besteht aus einer Palette mit
|
16 Einträgen (der getrennten Zeichenfolge) und einem Bild mit 16 Farben im Format 40 x 41 (codiert mit 4 Bit pro Pixel und decodiert durch Missbrauch.encode('hex')
). Das Bild wird mit einem bikubischen Filter auf die entsprechende Größe gebracht, und das war's.Das eigentliche Bild wurde mit ImageMagick erzeugt:
und die Paletten- und Bilddaten wurden aus dem resultierenden BMP extrahiert. (Beachten Sie, dass wir von ImageMagick 18 Farben anfordern, da IM automatisch einige nicht verwendete Einträge einfügt.)
Die Palette wurde leicht neu angeordnet, um die Anzahl der maskierten Zeichen in den Binärdaten zu verringern. Die endgültigen Binärdaten wurden ein wenig von Hand bearbeitet, damit das Ganze in 1024 Bytes passt.
BEARBEITET: Der Code wurde ein wenig verbessert, und die Genauigkeit wurde verbessert, indem 17 Farben von ImageMagick angefordert wurden.
BEARBEITET: Deaktivieren von Dithering führte zu einer enormen Verbesserung der Punktzahl. Es erreicht jetzt deutlich weniger als 5000 Punkte und wird mit Standardkomprimierungsalgorithmen konkurrenzfähig!
BEARBEITET: Hinzufügen
-filter Cosine
gibt eine weitere erhebliche Verbesserung. Aggressives Golfen, dank @primo für den UTF-8-BOM-Trick, ermöglichte es mir, eine weitere Reihe auf das Bild zu setzen und die Punktzahl weiter zu verbessern.quelle
!
wird eigentlich auf beiden Seiten von nicht druckbaren Zeichen flankiert. Die volle Farbe ist#1d211e
ein leicht bläuliches Dunkelgrau.#coding:latin
Zeile durch eine UTF-8-Byte-Ordnungsmarke ersetzt werden:
(0xEF, 0xBB, 0xBF).zsh + FLIF + ImageMagick, 4358.14
Da BPG das Scheinwerferlicht als verlustbehafteter Codec stiehlt, habe ich meinen verlustfreien, gehobenen Ansatz dahingehend verfeinert, FLIF anstelle von PNG zu verwenden, indem ich @ nneonneos Zsh-Trick verwende. ImageMagick wird hier nur als Upscaler verwendet.
Der Hexdump (diesmal mit
xxd
, ich wusste nicht, dass erhexdump
in meiner letzten Antwort nicht dem Standard entsprach):Ich habe das Skript mit ... einem anderen Skript generiert:
quelle
Mathematica, 5076,54
Mit genau 1024 Bytes schaffte ich es endlich , Nneonneos Punktzahl zu übertreffen ... bis er es vor einer Stunde verbesserte = (
Verwendet keine Standardkomprimierungsalgorithmen.
(Bessere Beschreibung später)
quelle
HTML / JavaScript,
10855.838000.55 (± 5, basierend auf dem Browser)Die Ergebnisse können aufgrund von Unterschieden im Browser oder in der GPU geringfügig abweichen.
Sie müssen mit der rechten Maustaste auf> Bild speichern unter klicken, um die Canvas-Daten als Bild zu speichern. Dies ist jedoch die einzige erforderliche Interaktion.
Ich habe GIMP verwendet, um bestimmte Bereiche auszuwählen und deren Durchschnitt zu ermitteln. Insbesondere das Farbauswahlwerkzeug und die Funktion "Ebenendifferenz" waren sehr hilfreich.
Versuch Nr. 1 (10855.83)
Versuch Nr. 2 (8000,55)
quelle
Scala, 6003,56
993 Zeichen. Ein Import ist die Scala-Bildbibliothek . Der zweite Import ist der Encoder der Basis 91 .
Dies sind die base91-Daten:
quelle
Java, Punktzahl 12251,19
Basierend auf dieser Mathematica-Antwort , aber mit mehr Rechtecken. Ich werde das wahrscheinlich später weiter modifizieren.
Ergebnisse:
Einige frühere Versionen:
quelle
Python 2 (keine eingebaute Komprimierung), Score 4497.730
Hierbei wird derselbe manuell decodierte 16-Farben-Bildansatz wie bei meiner vorherigen Antwort verwendet , aber dieses Mal habe ich tatsächlich eine Strategie zur Optimierung des Verlaufs angewendet, um die Punktzahl erheblich zu verbessern. Die vorherige Einreichung erzielte 4755,886 Punkte, während die neue Einreichung über 250 Punkte besser abschneidet und dabei viele integrierte Komprimierungsansätze übertrifft.
Das endgültige Programm ist nach wie vor genau 1024 Byte lang. Tatsächlich enthielt die Rohausgabe des Optimierungsalgorithmus vier Bytes, die escaped (
\0
) waren und die ich "fudgen" musste, um die Byteanzahl auf 1024 Bytes zu reduzieren. Ohne den Fudge würde das 1028-Byte-Programm 4490.685 Punkte - 7 Punkte besser erzielen.Die Grundidee ist, sowohl die Palette als auch die Daten gemeinsam zu optimieren. In einer einzigen Iteration durchsuche ich alle Optimierungen der Palette (im Grunde genommen jede geänderte Palette, die sich in einer Farbkomponente um 1 unterscheidet) und wähle die geänderte Palette aus, die die Punktzahl am besten verbessert. Dann durchsuche ich alle Optimierungen der Daten (jedes geänderte Indexarray, in dem ein Pixel in einen anderen Paletteneintrag geändert wird) und wähle eine Änderung, die die Punktzahl verringert (hier ist mir das Beste egal, weil ich es nicht tue) den vollen Speicherplatz von über 25000 Optimierungen bei jeder Iteration durchsuchen wollen).
Schließlich führe ich beim Generieren der endgültigen Programmausgabe einen weiteren Optimierungsdurchlauf durch, bei dem die Palette neu angeordnet wird, um die Anzahl der in der endgültigen Ausgabe erforderlichen Backslashes zu minimieren (z. B. wurde für das unten gezeigte Programm die Palette mithilfe der Hex-Tabelle "0e3428916b7df5ca" neu angeordnet).
Dieser Ansatz führte zu einer signifikanten Verbesserung der Anzahl und Wahrnehmung gegenüber dem vorherigen naiven ImageMagick-Ansatz. Bisherige Einreichungsergebnisse:
Und neue Submission-Ausgabe:
Der neue optimierungsbasierte Ansatz zeichnet sich durch deutlich detailliertere und genauere Farbwiedergabe aus.
Hier ist der Hexdump des endgültigen Programms:
Es gibt noch Raum für Verbesserungen. Ein einfaches Histogramm zeigt beispielsweise, dass einige Farben kaum verwendet werden:
Dies lässt darauf schließen, dass eine neu ausbalancierte Palette die Effizienz verbessern könnte, möglicherweise genug, um die BPG-Lösung mit dem fünften Platz zu erreichen. Ich bin jedoch ziemlich zweifelhaft, ob dieser Optimierungsansatz (oder wirklich alles, was nicht die außergewöhnliche Maschinerie von H.265 beinhaltet) die BPG-Implementierung auf den ersten Platz bringen kann.
quelle
Perl,
5955.96878124,5149.56218378Als ich mir den Ansatz des "nicht druckbaren Kauderwels" ansah, entschied ich, dass ich das auch in Perl versuchen könnte. Auch hier kenne ich Perl nicht wirklich, daher bin ich mir sicher, dass dies verbessert werden kann (die offensichtlichste Verbesserung, Reduzierung auf 7 Byte pro Ellipse durch Weglassen des Alphakanals, wurde bereits für die nächste Version implementiert, aber ich ' Ich arbeite immer noch an anderen Teilen dieses Codes und denke auch, dass das ganze Pop / Push-Geschäft mehr Golf spielen kann.
Ich glaube nicht, dass dies tatsächlich auf Windows-Rechnern funktioniert (ich kann es nicht testen), da ich keine einfache Möglichkeit gefunden habe, den DATA-Bereich im Binärmodus zu öffnen - auf meinen Linux-Rechnern hat es jedoch funktioniert.
Grundsätzlich konnte ich weiterhin denselben GA-Code verwenden, um Folgendes zu erstellen:
Wobei die xxd Ausgabe ist:
Welches erzeugt das Bild:
Es ist interessant, dass das Bild, obwohl es besser abschneidet, für mich etwas schlechter aussieht - mit all den zusätzlichen Ellipsen ist zu viel los, irgendwie ist es einfacher, mit dem einfacheren Bild visuell umzugehen.
Alte Ergebnisse
Nachdem ich Jamieguinans Antwort gesehen hatte , benutzte ich Ellipsen als Zeichenprimitiv, da ich in Perl Zugriff auf die GD-Bibliothek zum Zeichnen habe. Ich bin überhaupt kein Perl-Experte, daher wären alle Vorschläge hilfreich. Ich habe einen genetischen Algorithmus verwendet, der von meiner C ++ - Antwort modifiziert wurde .
Es scheint in Ordnung zu sein, aber ehrlich gesagt bin ich ein bisschen enttäuscht von der Punktzahl. Ich könnte es wahrscheinlich etwas länger laufen lassen, da Sie leicht sehen können, dass sich einige Ellipsen nicht in der optimalen Position befinden. Aber selbst jetzt sieht es für meine Augen besser aus als bei der rechteckbasierten Lösung.
quelle
Bash + Netpbm,
4558.54394.1UPDATE: Ich habe die Punktzahl durch die Verwendung von SPIHT anstelle von FIASCO verbessert.
SPIHT ist eine Abkürzung für Set Partitioning In Hierarchical Trees. Es ist ein hocheffizientes Wavelet-basiertes Bildkomprimierungsformat.
Ich wich die ursprüngliche PNG von Quartal, dann in PNM unter Verwendung
pngtopnm
von Netpbm v. 10.68, entfernt dann den Header und konvertierte die RAW - Daten mit bis zu SPIHTcodecolr in.raw out.spi 80 96 0.95
und bekam die 913-Byte - Bilddatei. Dann konvertierte ich es zurück in RAW mitdecdcolr -s out.spi out.raw 0.95
, konvertierte es als nächstes in das PNM-Format mitrawtoppm -bgr 96 80
,pamflip -tb
spiegelte es mit , skalierte es mit auf die ursprüngliche Größepamscale -xsize 386 -ysize 320 -filter sinc
und speicherte es in einer PNM-Datei, die von PIL gelesen wird. Hier ist mein Skript (1 KB):Hier ist das Ausgabe-PNG:
Unten ist meine bessere Antwort:
FIASCO ist eine Abkürzung für Fractal Image And Sequence COdec und eine hocheffiziente Implementierung der verlustbehafteten fraktalen Komprimierung .
Ich wich die ursprüngliche PNG von Quartal, dann in PNM unter Verwendung
pngtopnm
von Netpbm v. 10.68, dann umgewandelt mit Fiascopnmtofiasco -q=14 -z=3
und bekam die 969-Byte - Bilddatei. Dann habe ich es mit wieder in PNM konvertiertfiascotopnm
, mit auf Originalgröße hochskaliertpamscale -xyfill 386 320
und in einer PNM-Datei gespeichert, die von PIL gelesen wird. Hier ist mein Skript (1 KB):Eigentlich habe ich das zuerst in Windows gemacht
cmd
, aber das Skript passte nicht in 1 KB. Dann habe ich es umgeschriebenbash
. Hier ist das Ausgabe-PNG:quelle
Ruby, 7834,38
Das hat Spaß gemacht!
Ich habe ein Ruby-Generator-Programm verwendet, um ein Ruby-Skript wie folgt zu schreiben:
Während die generierte Ruby-Datei weniger als 1024 Bytes umfasst:
Beachten Sie, dass mein Bewertungsalgorithmus eine Reihe von Farben zufällig auswählt und diejenige auswählt, die den geringsten Unterschied zu ORIGINAL.png ergibt. Da dies wahrscheinlich ist, habe ich das Skript einige Male wiederholt und das Ergebnis mit der niedrigsten Punktzahl ausgewählt.
Hier ist mein bisher bestes Drehbuch:
Es wurde das folgende Bild generiert, das 7834 Punkte erzielte:
Um zu sehen, wie mein Algorithmus darauf gekommen ist, hier ein animiertes GIF, das zeigt, wie es Rechtecke aufteilt:
Mein Code ist auf GitHub unter https://github.com/jrotter/starry_night_contest verfügbar
quelle
Java, 9215.38294502
Das Bild wird als GIF mit einer Größe von 8 x 6 Pixel (!) Aus einer Base64-codierten Zeichenfolge (mit 368 Zeichen) gelesen und bilinear skaliert.
BEARBEITEN: Das Ergebnis, wie in den Kommentaren angefordert, ist in diesem Bild dargestellt:
quelle
Python 3, 5797.125628604383
Das Komprimierungsprogramm schneidet zuerst die Bits des Bildes ab und konvertiert dann die Basis 2 zur Basis 36.
Das Dekodierungsprogramm führt dies in umgekehrter Reihenfolge durch und ändert die Größe des Bildes.
quelle