Remarque : Anders Kaseorg s'est vu attribuer l'acceptation pour le moment, afin d'attirer l'attention sur son excellente réponse, mais le défi n'est pas terminé! L'offre comporte toujours une prime de 400 points pour quiconque obtient le meilleur score sans utiliser la compression intégrée.
Ci-dessous, une 386x320
représentation au format png de La nuit étoilée de van Gogh.
Votre objectif est de reproduire cette image aussi fidèlement que possible, en 1024 octets maximum de code. Pour les besoins de ce défi, la proximité des images est mesurée par les différences au carré des valeurs de pixels RVB, comme expliqué ci-dessous.
C'est un défi de code . Les scores sont calculés à l'aide du script de validation ci-dessous. Le score le plus bas gagne.
Votre code doit obéir aux restrictions suivantes:
- Ce doit être un programme complet
- Il doit sortir une image dans un format lisible par le script de validation ci-dessous, exécuté sur ma machine. Le script utilise la bibliothèque PIL de Python, qui peut charger une grande variété de formats de fichiers , notamment les formats png, jpg et bmp.
- Il doit être complètement autonome, ne prendre aucune entrée et ne charger aucun fichier (autre que l'importation de bibliothèques, ce qui est autorisé)
- Si votre langue ou votre bibliothèque inclut une fonction générant Starry Night, vous n'êtes pas autorisé à utiliser cette fonction.
- Il devrait fonctionner de manière déterministe, produisant le même résultat à chaque fois.
- Les dimensions de l'image de sortie doivent être
386x320
- Pour éviter tout doute, les réponses valables doivent utiliser des langages de programmation conformément aux règles habituelles du PPCG . Ce doit être un programme qui sort une image, pas seulement un fichier image.
Il est probable que certaines soumissions seront elles-mêmes générées par du code. Si tel est le cas, veuillez inclure dans votre réponse le code qui a été utilisé pour produire votre soumission et expliquer comment cela fonctionne. Les restrictions ci-dessus s'appliquent uniquement au programme de génération d'images de 1 Ko que vous avez soumis. ils ne s'appliquent à aucun code utilisé pour le générer.
Notation
Pour calculer votre score, prenez votre image de sortie et l'original ci-dessus et convertissez les valeurs des pixels RVB en nombres à virgule flottante allant de 0 à 1. Le score d'un pixel est égal à (orig_r-img_r)^2 +(orig_g-img_g)^2 + (orig_b-img_b)^2
la distance au carré dans l'espace RVB entre les deux images. Le score d'une image est la somme des scores de ses pixels.
Vous trouverez ci-dessous un script Python qui effectue ce calcul - en cas d'incohérence ou d'ambiguïté, le score définitif est celui calculé par l'exécution de ce script sur ma machine.
Notez que le score est calculé en fonction de l'image de sortie, donc si vous utilisez un format avec perte qui affectera le score.
Plus le score est bas, mieux c'est. L'image Starry Night originale aurait un score de 0. Dans l'éventualité d'une égalité astronomique, la réponse avec le plus de votes déterminera le gagnant.
Objectifs bonus
Les solutions utilisant la compression intégrée étant dominées par les réponses, j'ai attribué une série de primes aux réponses utilisant d'autres techniques. La prochaine sera une prime de 400 points , à attribuer si et quand une réponse qui n’utilise pas la compression intégrée prend la première place.
Les primes bonus précédemment attribuées étaient les suivantes:
Une récompense de 100 points a été attribuée à la réponse de nneonneo, considérée comme la réponse ayant obtenu le meilleur score sans utiliser la compression intégrée à l’époque. Il avait 4852,87 points au moment où il a été attribué. Des mentions honorables vont à 2012rcampion, qui a fait une vaillante tentative de battre nneonneo en utilisant une approche basée sur la tesselation de Voronoï , marquant 5076 points, et à Sleafar, dont la réponse était en tête jusqu’à la fin, avec 5052 points, en utilisant une méthode similaire. nneonneo.
Une prime de 200 points a été attribuée à l'entrée de Strawdog . Cette stratégie a été récompensée pour être une stratégie basée sur l'optimisation qui a pris la tête des solutions de compression non intégrées et l'a conservée pendant une semaine. Il a marqué 4749,88 points en utilisant une méthode impressionnante.
Scoring / script de validation
Le script Python suivant doit être placé dans le même dossier que l'image ci-dessus (qui doit être nommé ORIGINAL.png
) et être exécuté à l'aide d'une commande du formulaire 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)
Note technique: Les mesures objectives de la similarité des images sont une tâche délicate. Dans ce cas, j'ai opté pour une solution facile à mettre en œuvre pour tout le monde, sachant qu'il existe de bien meilleures mesures.
Classement
la source
pip unistall PIL
, puispip install pillow
) et de changer la première ligne enfrom PIL import Image
.Réponses:
Pyth (pas de compression
intégrée), score4695.074656.034444.82La seule fonctionnalité liée aux images de Pyth est la possibilité intégrée d'écrire une matrice de triplets RVB sous forme de fichier image. L’idée folle est donc de former un petit réseau de neurones profonds sur la fonction ( x , y ) ( r , g , b ) qui représente l’image et de l’exécuter sur les coordonnées de chaque pixel.
Le plan
Le réseau actuel est construit à partir de 45 neurones sigmoïdes, chaque neurone étant connecté aux entrées x , y et à chaque neurone précédent, les trois derniers neurones étant interprétés comme suit : r , g , b . Il est formé à l'aide de l' algorithme Adam sans traitement par lots. Les paramètres de pondération des 1125 connexions sont quantifiés à une gamme de 93 valeurs possibles ( à l' exception des termes constants, qui ont des 93 deux valeurs possibles) en utilisant une variante de quantification stochastique , la variation primaire étant que nous avons établi le gradient pour les paramètres quantifiés à zéro.
Le résultat
Le code
1023 octets, codés avec
xxd
(décoder avecxxd -r
). J'ai utilisé la version 2016-01-22 de Pyth qui était actuelle lors de la publication de ce défi. Vous pouvez exécuter le code directement en Pyth, mais Pyth dans PyPy3 (pypy3 pyth starry.pyth
) l'exécute neuf fois plus rapidement, en environ 3 minutes. L'image de sortie est écrite danso.png
.Comment ça fonctionne
Entraînement
Au cours de ma dernière formation, j’ai utilisé un programme de quantification beaucoup plus lent et j’ai manipulé de manière interactive le taux d’apprentissage, mais le code que j’ai utilisé était à peu près le suivant.
Visualisation
Cette image montre les activations des 45 neurones en fonction des coordonnées x , y . Cliquez pour agrandir.
la source
Mathematica, score 14125.71333
Enregistre cette image:
à
a.png
.la source
Java, 7399.80678201
Cela m'a rappelé un projet que j'avais dans ma classe de calcul numérique quelques semestres en arrière, qui consistait à dessiner une silhouette du mont Everest en utilisant une interpolation polynomiale. Cela a été fait dans MATLAB, mais je n’aime pas beaucoup MATLAB, j’ai donc décidé de travailler en Java. L'idée de base est que j'ai choisi des points "intelligents" (ici "aléatoires") pour l'interpolation polynomiale. Avec les quelques octets qui me restaient, j'ai créé un moyen de dessiner les étoiles, ce qui se passe avant le dessin de la montagne. Il peut être possible de condenser le code et d'ajouter un autre polynôme pour le bas afin d'améliorer le score.
Edit: J'ai ajouté et modifié certains polynômes et ajouté toutes les étoiles. Mon score précédent était de 9807.7168935, alors comme vous pouvez le constater, il s’agit d’une très grande amélioration. Malheureusement, la lisibilité du code en a pris un coup, car j'ai dû extraire les derniers octets pour obtenir toutes les étoiles et leur donner des groupes.
9807.7168935 points: 7399.80678201 points:
la source
Python3.4 +, 4697.26
J'ai utilisé la même méthode que dans ma réponse ImageMagick, mais avec les paramètres suivants:
En utilisant ces paramètres, j'ai généré le programme Python de 1003 octets suivant (je n'ai trouvé aucune amélioration par rapport à la méthode de sortie de @ kennytm):
Ce qui à son tour génère cette image:
la source
1
delatin1
et enregistrer un des espaces deimport *
, au moins. Mais jouer au golf n'était pas une priorité (moins de 1024 octets).Python 3, score 5701.31
Il suffit de redimensionner une image au format PNG 18 × 13.
la source
Java, 8748.95
Une autre approche:
J'ai créé une classe qui calcule un diagramme de Voronoï à partir d'un ensemble de points donné. Cet ensemble de points est utilisé en tant que jeu de paramètres servant d’entrée pour le Apache BOBYQAOptimizer . La fonction d'évaluation de l'optimiseur prend les points et en crée un diagramme de voronoï. Les régions de voronoï sont colorées avec la couleur moyenne de la région correspondante de l'image d'origine.
Le processus d'optimisation est montré ici:
L'image finale est celle-ci:
qui réalise un score de 8748.95
(Cela a été mesuré avec ma propre fonction, mais devrait être identique à celui du script d'évaluation)
Le résultat de ce processus est seulement un ensemble de 8 points et les couleurs correspondantes. (Un nombre plus élevé de points a entraîné de moins bons résultats, mais je n'ai pas vraiment essayé cela beaucoup).
Le code obtenu est affiché ici (désolé, je devais jouer un peu au golf pour le faire entrer dans la limite de 1 Ko):
(Je sais, il y a des façons simples qui auraient pu donner de meilleurs résultats, mais ... c'était amusant en quelque sorte ...)
En réponse au commentaire, concernant le style artistique d’une telle image voronoï avec un plus grand nombre de points: cela semble effectivement intéressant, et certains outils d’imagerie l’offrent en tant que "filtre mosaïque" - par exemple, le filtre mosaïque dans GIMP ( bien que cela offre des options pour souligner les bords, etc.).
Voici un exemple d’image Starry Night, avec 256 points. (Ceux-ci sont sélectionnés de manière aléatoire, mais avec un plus grand nombre de points, l'amélioration qui pourrait être obtenue par une optimisation disparaîtra).
Cela ne fait pas partie du concours (car il ne rentre pas dans 1 Ko), juste pour les curieux:
la source
import java.util.*;
En fait, remplacez toutes les classes d'importation par des astérisques.AutoIt ,
9183.257882.53MISE À JOUR
Il s'avère donc que redessiner l'image comme un bambin (ivre) est plus efficace que de stocker une version de l'image. (Plus efficace que mon ancienne solution quand même).
Chaque ligne qui dessine un élément est cruciale pour réduire le score. Je pense que ce programme est capable d’atteindre des scores bien inférieurs à 7 000 avec des modifications très mineures, car chaque changement a des effets énormes (~ 20 à 100 points) sur le score. Le programme utilise ma
processing
bibliothèque graphique qui fournit des noms de fonction abrégés pour dessiner avec GDI.Comme cette solution implique un caractère aléatoire, nous ensemencons le PRNG en utilisant la valeur constante en
0
utilisantSRandom(0)
. Pourquoi 0? Parce que c'est jusqu'à 50 points mieux que tous les autres quen<=100
j'ai essayés.La toile commence comme un blanc
#587092
.Générer le sol
La partie inférieure de l'image (qui commence à exactement 233px [à nouveau, à cause des points]) est remplie avec exactement des
int(1e4*2.9)
ellipses. Changer le facteur ici (ou une décimale du facteur) peut réduire et augmenter le score par centaines de points. Je me suis installé pour 2,9 après quelques essais. Naturellement, cela prendra du temps (quelques secondes).Une palette de cinq couleurs est fournie:
Blobs sur le sol
Quatre ellipses sont utilisées pour définir des accents contrastés à l'intérieur de la surface de plancher (
$4
un pointeur de fonction surellipse()
):Générer des accents dans le ciel
Certaines lignes sont tracées à l'aide d'un stylo plus épais pour représenter des zones de couleur significatives dans le ciel trop étirées pour les ellipses:
Peser les pixels
Après ce qui précède, tout est rincé et répété jusqu’à épuisement des octets. Ensuite, un flou est appliqué pour tromper la méthode de validation. Par force brute, il a été déterminé qu’un rayon de 20 exactement fournit le meilleur résultat. Cela améliore le score d'environ 1,5k (!).
Image finale
Code, 985 octets
ANCIENNE REPONSE
Ceci stocke 80 valeurs de couleurs qui constituent une image 10x8 px. Cette image brute a un score de 10291. Etant donné que 10x8 est un facteur de pixelisation de 40 pixels, un flou gaussien est appliqué à l'aide d'un rayon de 40 pixels pour réduire le score. Voici comment le script réalise 9183.25.
Ce sont les données stockées:
Le fichier produit est True.png:
Le programme est long de 998 octets :
la source
1e4*2.9
égal à29e3
?Fichier BAT Windows, score 4458.854
La taille du programme est de 1024 octets.
Convertit une image BPG encodée en base64 en PNG.
Utilise certutil.exe (utilitaire Windows standard) et bpgdec.exe le décodeur d’image tant que bibliothèques.
Compression:
la source
C ++ 11,
7441.681261056997.654348335198.16107651Plus de mises à jour
J'ai tellement aimé les ellipses de Perl que j'ai dû les essayer en C ++ 11. J'ai utilisé la chaîne brute pour y insérer des octets, mais pendant un moment, j'ai eu une légère différence avec le score que j'attendais et le code généré. Il s'avère que vous ne pouvez pas réellement mettre un 0x0d brut (retour à la ligne), car g ++ le convertira en 0x0a (nouvelle ligne). Honnêtement, je ne suis pas sûr de la légitimité de cette source générée, mais elle compile et fonctionne sur quelques machines.
J'ai aussi essayé un autre algorithme, Adaptive Dimensional Search, après que l'AG semblait bloqué, juste pour essayer d'éliminer le minimum local et peut-être avoir de la chance et tomber dans un autre puits.
Avec cela, C ++ 11 donne un score étonnamment compétitif (bien meilleur que ce que j’aurais deviné au départ) ... Je suis assez surpris qu’il puisse le faire avec fstream comme seul inclus.
Texte (oui, les nouvelles lignes sont dans la source réelle ... je suppose que je pourrais les supprimer):
Hexdump:
Cette réponse combine plusieurs approches des réponses précédentes, ce que je vais expliquer ci-dessous. Malheureusement, j’ai finalement dû jouer un peu au programme pour tenir dans
944949 caractères (selonwc -c
), donc cela ne ressemble plus beaucoup à C ++ (excuses si c'est contre les règles du challenge, je vais essayer quelques améliorations sous peu). Je n'avais pas prévu cela au début, donc ce n'est toujours pas complètement indéchiffrable et il y a encore beaucoup de fruits à portée de main.Résultats mis à jour
Le simple fait d’utiliser plus longtemps l’algorithme génétique a produit un résultat légèrement meilleur; Cependant, étant donné que la convergence a ralenti de manière significative, je dirais que cette méthode particulière commence probablement à faire son chemin (ou je suis tombé dans un minimum local profond). J'ai joué un peu plus au programme final pour insérer quelques rectangles de plus (le générateur reste le même, sauf que la taille maximale du génome a été augmentée).
Mettre en œuvre le croisement entre individus aidera si le problème est un minimum local profond, mais étant donné qu'il est resté dans la même plage pendant un moment, je commence à penser que c'est à peu près aussi bon que le nombre de rectangles.
Version Voronoï, 7331.92407536, 989 caractères
J'ai utilisé Voronoi Idea de Marco13 avec mon code GA. Cela n'a pas fonctionné aussi bien que je l'espérais. Je ne pouvais insérer que quelques points de plus que des rectangles. Je pense que la nature potentiellement disjointe des rectangles due au chevauchement aide un peu la partition. Quoiqu'il en soit, j'aime bien la façon dont cela semble nettement mieux, malgré le score similaire à celui de ma première participation.
Anciens résultats, 7441.68126105, 944 caractères
Comme certaines des autres entrées, le programme ne dessine que des rectangles qui se chevauchent. Il utilise PPM binaire puisque le format est simple (la sortie l'est
a.ppm
, mais j'ai téléchargé une version png puisque SE n'aimait pas le PPM) et est complètement déterministe.Explication
Générer le PPM a pris une bonne partie du code standard, ce qui signifie que je ne pouvais pas avoir trop de rectangles, même après avoir joué au golf un peu. Un peu plus peut probablement être pressé ici pour améliorer le score.
La vraie magie est la liste des rectangles. Semblable à la réponse de Wolfgang, j'ai utilisé un algorithme génétique pour les trouver. En réalité, la mise en œuvre est en grande partie incomplète, car la recombinaison entre les individus n’a pas encore lieu, mais des mutations ont encore lieu et le classement en forme de tournoi par fitness maintient les meilleurs organismes lors du prochain tour. L'élitisme est également utilisé, car une copie du meilleur individu du dernier tour est conservée dans le prochain tour, de sorte que l'organisme le plus en forme est toujours au moins aussi en forme que lors du tour précédent.
Je n’ai pas trop regardé le code de Wolfgang puisque j’avais commencé cela hier, mais il semble qu’il permette à la couleur de varier également, ce qui peut expliquer la différence de score.
Pour réduire la taille de l’espace de recherche, j’ai seulement regardé la position du rectangle; la couleur est calculée par la moyenne par canal des pixels visibles de ce rectangle puisque nous avons l'image source (je ne pense pas que nous puissions faire mieux que cela pour ce rectangle particulier car cela minimise la distance au carré).
Si je continue à travailler sur ce dossier, je vais mettre en place un référentiel github lors des deux prochaines éditions, mais pour l'instant, le code (fichier unique) est sur pastebin . Compilez-le en mode C ++ 11, (note de côté, je suis assez gêné de voir à quel point c'est désordonné, même pour un événement ponctuel).
Vous aurez également besoin d’une image P3 PPM de la nuit étoilée nommée
ORIGINAL.ppm
pour que cela fonctionne. Vous pouvez télécharger le fichier à partir de ce GitHub Gist .la source
i r,g,b
au lieu de séparément, et beaucoup d'espaces peuvent être supprimés). Je ne savais pas si le programme devait générer le fichier directement ou si la tuyauterie vers stdout / stderr était correcte.#include <fstream>
? En outre, déposez les nouvelles lignes et mettez le tout sur une seule ligne, car le C ++ a de toute façon besoin de points-virgulesImageMagick, 4551.71
Utilise le langage de programmation ImageMagick, en utilisant les options suivantes (vous devrez peut-être échapper à la
!
):En supposant que le fichier source suivant de 968 octets (donné comme hexdump):
Produire cette image:
Vous vous demandez probablement comment j'ai généré le fichier d'entrée, et la réponse est plutôt simple. Redimensionnez à 48x40 avec le filtre Lanczos, utilisez une palette de 20 couleurs indexées et optimisez le fichier PNG obtenu.
Utilise
convert
,pngquant
,optipng
etadvdef
.la source
=(tail +2 $0)
truc de ma réponse , vous pouvez créer un script ZSH unique qui contient à la fois le script ImageMagick et le fichier d’entrée PNG.Python 2, 4749.88
1018 octets
Tout le monde a probablement déjà oublié ce problème, sauf moi ....
Ce problème m'intéressait beaucoup trop, d'autant plus qu'il est rapidement devenu évident que les approches utilisant des algorithmes de compression d'images étaient définitivement en tête, mais néanmoins insatisfaisantes du point de vue esthétique. Les approches basées sur l'optimisation d'un ensemble de primitives de dessin étaient en quelque sorte plus agréables d'un point de vue esthétique du code, mais semblaient bloquées juste au-dessus de la note de 5000.
La méthode de nneonneo qui n'utilisait pas de compression d'image standard bat la marque 5000, mais le fait en codant une image minuscule et en la redimensionnant.
Voici un programme qui utilise uniquement des primitives de dessin, est généré automatiquement par une méthode d'optimisation et parvient à obtenir un score de 4749,88.
qui ressemble à ceci:
et l'hexdump du code:
Il utilise un certain nombre de trucs utilisés précédemment ici:
En tant que première primitive, je place une ligne d'horizon, divisant l'image en deux blocs de couleurs différentes. Ensuite, en tant que primitive de base, j'ai utilisé un cercle glissé entre deux points. Cela ressemblait vaguement à un coup de pinceau pour moi, mais pouvait être exprimé en 7 octets. Pour le processus de recherche, j'ai utilisé une recherche de modèle guidée. Il procède ensuite en ajoutant une primitive et en optimisant ses paramètres. La primitive est ajoutée au point où l'erreur de signature floue est la plus grande. Les paramètres sont optimisés par une optimisation exhaustive des lignes sur un petit domaine, les uns après les autres. Quarante à cinquante primitives sont ajoutées et optimisées individuellement. Ensuite, la liste des primitives est taillée à la taille en jetant les primitives qui aident le moins à marquer.
Cela ne bat toujours pas le score de Nneonneo. Pour battre ce score, une deuxième étape d’optimisation s’imposait. Elle consiste ensuite à ajouter des primitives à chacun des niveaux de filtrage et à les jeter pour réduire le programme généré à la taille voulue. Ce qui était vraiment intéressant pour moi, c’était l’idée de l’appliquer à d’autres images. Je l'ai appliqué à quelques autres images et j'ai fourni plus de détails et une animation des primitives dessinées dans mon blog ici .
Les deux programmes utilisés pour générer cela ne rentrent pas dans l'espace autorisé sur les publications Stack Exchange, mais ils se trouvent sur github: https://github.com/str4w/starrynight/tree/StackExchange
starrynight est exécuté en premier, suivi de stage2optimization. Le programme résultant est également là, dans le même répertoire.
la source
Matlab, score 5388.3
Sans aucune compression intégrée. La profondeur de couleur est réduite de sorte que chaque pixel puisse être représenté par un caractère imprimable. Et la résolution est réduite. Ceci est ensuite codé en dur en tant que chaîne. Le code lui-même inverse l'ensemble du processus. Le redimensionnement utilise un noyau d’interpolation Lanczos 3.
la source
zsh + bpgdec, 4159.061760861207
Oui, une autre solution BPG. Je pense que cela sert essentiellement à prouver que BPG est le meilleur utilitaire de compression d'image actuellement disponible. Considérez cela comme une amélioration par rapport à rapport à la solution BPG originale de yallie .
Le fichier a une longueur de 1024 octets, juste à la limite. Il se compose de la ligne
suivi de la sortie brute de BPG de
En hex, voici le script:
Le fichier résultant est
out.png
(l'bpgdec
emplacement par défaut), ce qui ressemble à ceci:Je trouve ça plutôt étonnant que
bpg
996 octets seulement, nous ayons reconstitué avec précision les contours nets de l’arbre, à gauche, et des collines, à droite. Il a même une approximation passable pour le clocher de l'église! Le niveau de détail est très impressionnant (pour moi) pour la petite taille de fichier. Bien sûr,bpgdec
n’est pas un petit programme en soi, mais j’ai bien compris que BPG est un ordre de grandeur supérieur à JPEG pour la compression d’images.Parce que cela utilise
bpgdec
, cette réponse n'est évidemment pas éligible à la prime.EDITED: Ajout d'un
-n
argument pourtail
le rendre compatible avec GNUtail
.la source
tail: cannot open ‘+2’ for reading
. Sur Ubuntu, il faut-n +2
, ce qui le met à 1025 octets = /-n+2
ce qui le met exactement à 1024 octets - essayez-le et laissez-moi savoir si cela fonctionne. Je vais changer ma réponse pour la compatibilité.C, 6641
999 octets, en utilisant seulement
stdio.h
etmath.h
.J'ai créé une fonction de cercle rempli
d()
qui dessine des cercles de couleur RVB concentriques sur les valeurs de rayon r..0. 21 cercles sont utilisés ici. Je pourrais en insérer un peu plus si je réduisais davantage les espaces, mais j'aime la lisibilité relative telle quelle.J'ai compris le placement approximatif du cercle en utilisant les calques Gimp en
Difference
mode. Cherchez les points lumineux, ajoutez un cercle, répétez. OutilHistogram
utilisé lors de la sélection pour déterminer les couleurs initiales à utiliser.J'ai obtenu un score d'environ 7700 en utilisant ce qui précède, mais je me suis dit que je pourrais faire mieux en modifiant les valeurs de couleur et de rayon. rendu, en exécutant le validateur (que j'ai réécrit en C pour la vitesse) et en sauvegardant la valeur qui a généré le score le plus bas. À la fin, il vide le tableau de valeurs que je réinsère dans le code et le recompile. J'ai fait quelques passes et cela a réduit le score d'environ 1000. Ensuite, j'ai effacé le code d'échafaudage.
Code,
la source
((x-xo)*(x-xo) + (y-yo)*(y-yo)) <= (r*r)
) semble être plus courte et supprimer la dépendancemath.h
. Avec cette taille d'image, je ne pense pas que rien ait une chance de déborder non plus.Python 3, score 5390.25, 998 octets
J'ai utilisé un programme de recuit simulé pour ajuster les rectangles à la forme de Starry Night. Il utilise ensuite un flou gaussien pour lisser les bords rectangulaires droits.
Pour sauvegarder quelques octets, j'ai compressé les données du rectangle en base 94.
la source
Python 2, 5238.59 points
Il est probablement temps de poster ma propre réponse. Voici l'image
Le code ressemble à ceci
Ou comme une décharge hexagonale:
Il décompresse simplement cette longue chaîne dans les paramètres permettant de dessiner 95 ellipses translucides.
Comme beaucoup d'autres réponses, le code est généré à l'aide d'un algorithme génétique. Il utilise un type particulier d'algorithme génétique que j'ai inventé, que j'appelle un "algorithme de pool de gènes", bien qu'il soit tout à fait possible que quelqu'un d'autre l'ait également inventé et lui ait donné un nom différent. Au lieu d'avoir une population d'individus, nous avons 95 "pools de gènes", un pour chaque gène. Chaque pool de gènes contient 10000 versions différentes du gène. Un gène contient les paramètres d'une ellipse (position, forme, couleur, alpha et sa place dans l'ordre z). À chaque itération, nous créons deux images en sélectionnant un gène dans chacun des 95 pools. Les gènes de l'image la moins performante remplacent les gènes de l'image la moins performante, avec une petite mutation.
Je l'ai utilisé jusqu'à la 378 000e édition environ, ce qui a pris quelques jours. À ce stade, le score était toujours en train de baisser, mais très très lentement, je doute donc que les choses iront beaucoup mieux sans quelques modifications de l'algorithme.
Voici le code de l'algorithme génétique:
Enfin, voici une animation montrant l’algorithme au travail. Il montre la meilleure image générée jusqu'ici toutes les 1000 itérations. (Le fichier gif était beaucoup trop volumineux pour être intégré à ce message.)
Il peut probablement être amélioré en (1) utilisant l'astuce de codage de nneonneo pour stocker davantage de données dans la chaîne; (2) l'ajout d'un flou gaussien à la fin du code de rendu (mais cela le ralentira) et (3) l'amélioration de l'algorithme. Pour le moment, il atteint très rapidement un score décent, mais il change ensuite très lentement. Si je ralentis la convergence initiale d'une manière ou d'une autre, le résultat final pourrait être meilleur. Peut-être que je vais mettre en œuvre ces choses à un moment donné.
la source
Étoilé ,
11428.189450210904.307927710874.1307958Starry n'est peut-être pas le meilleur langage pour le faire, mais c'est certainement le plus approprié.
Vous pouvez l' essayer en ligne, mais il semble que la sortie soit tronquée afin que vous n'ayez pas l'image complète.
Ce programme génère des fichiers ppm non compressés vers la sortie standard.
Voici la sortie du programme:
Explication
Afin de faire en sorte que le programme produise tous les 123 520 pixels requis, j'ai divisé l'image en 8 bandes horizontales et créé 7 boucles, les 6 premières boucles imprimant une bande tandis que la dernière imprimait deux bandes de la même couleur. Le code consiste en un en-tête, qui indique au fichier ppm comment se formater et aux 7 boucles susmentionnées.
la source
Python 2, 4684.46
1021 octets.
Cela utilise une méthode de décodage très similaire à quelques autres réponses, mais comme il s’agit de Python 2, il s’agit de données codées en base64 au lieu de base85.
Les données encodées sont une image au format WebP 64x48.
Voici le code que j'ai utilisé pour trouver les meilleurs paramètres de taille et de qualité d'image. J'ai limité l'espace de recherche afin que l'exécution ne prenne que quelques minutes.
la source
Python 2,
5098.245080.044869.154852.874755.88589004Aucune décompression intégrée utilisée! Tout l'utilitaire de redimensionnement de PIL et une image 16 couleurs décodée manuellement. Par conséquent, il devrait être éligible à la prime.
Le programme contient des caractères incorporés non-ASCII. Il a une longueur de 1024 octets et ressemble à ceci:
et en hex:
et génère cette image:
Ce programme abuse du fait que vous pouvez fondamentalement transférer des octets bruts dans le code source Python aussi longtemps que vous échappez à NUL et à des barres obliques inverses.
Le programme lui-même consiste en une palette de 16 entrées (la
|
chaîne séparée) et une image 40 x 41 en 16 couleurs (codée à 4 bits par pixel et décodée par abus.encode('hex')
). L'image est redimensionnée à la taille appropriée avec un filtre bicubique, et c'est tout.L'image réelle a été générée avec ImageMagick:
et les données de la palette et de l'image ont été extraites du fichier BMP résultant. (Notez que nous demandons 18 couleurs à ImageMagick, car IM insère automatiquement certaines entrées inutilisées).
La palette a été légèrement réorganisée pour réduire le nombre de caractères échappés dans les données binaires et les données binaires finales ont été éditées un peu à la main pour que tout le contenu puisse tenir dans 1024 octets.
EDITED: Golfé le code un peu, et amélioré la précision en demandant 17 couleurs à ImageMagick.
EDITED: La désactivation du dithering a entraîné une amélioration considérable du score. Il atteint maintenant bien moins de 5 000 points et devient concurrentiel avec les algorithmes de compression du commerce!
ÉDITÉ: L’ajout
-filter Cosine
apporte une autre amélioration importante. Le golf agressif, grâce à @primo pour le tour de UTF-8 BOM, m'a permis de clouer une autre rangée sur la photo, améliorant encore le score.la source
!
est flanquée des deux côtés de caractères non imprimables. La couleur complète est#1d211e
gris foncé légèrement bleuâtre.#coding:latin
ligne peut être remplacée par une marque d'ordre d'octet UTF-8:
(0xEF, 0xBB, 0xBF).zsh + FLIF + ImageMagick, 4358.14
Avec BPG sous les feux des projecteurs en tant que codec avec perte, j'ai affiné mon approche haut de gamme sans perte consistant à utiliser FLIF au lieu de PNG, en utilisant le tour de passe de @ nneonneo. ImageMagick est uniquement utilisé ici comme upscaler.
L'hexdump (cette fois avec
xxd
, je n'avais pas réalisé que cehexdump
n'était pas standard dans ma dernière réponse):J'ai généré le script en utilisant ... un autre script:
la source
Mathematica, 5076.54
Pesant exactement 1024 octets, j’ai finalement réussi à battre le score de nneonneo ... jusqu’à ce qu’il l’ait amélioré il ya une heure = (
N'utilise aucun algorithme de compression "standard".
(Meilleure description plus tard)
la source
HTML / JavaScript,
10855.838000.55 (± ~ 5, basé sur le navigateur)Les scores peuvent varier légèrement en raison des différences de navigateur ou de processeur graphique.
Vous devez cliquer avec le bouton droit de la souris sur> Enregistrer l'image sous pour enregistrer les données de la zone de dessin en tant qu'image, mais c'est la seule interaction requise.
J'ai utilisé GIMP pour sélectionner certaines zones et trouver leur moyenne. En particulier, l'outil de sélection de couleur et la fonctionnalité "différence de couche" ont été très utiles.
Tentative n ° 1 (10855.83)
Tentative n ° 2 (8000.55)
la source
Scala, 6003.56
993 caractères. Une importation est la bibliothèque d’images scala . La seconde importation est un encodeur base 91 .
Ce sont les données base91:
la source
Java, score 12251.19
Basé sur cette réponse de Mathematica , mais avec plus de rectangles. Je vais probablement continuer à modifier cela plus tard.
Résultats:
Quelques versions précédentes:
la source
Python 2 (pas de compression intégrée), score 4497.730
Ceci utilise la même approche d’image 16 couleurs décodée manuellement que ma réponse précédente , mais cette fois j’ai effectivement appliqué une stratégie d’optimisation de la descente sur gradient de manière significative. améliorer le score. La soumission précédente affichait 4755,886 points, alors que la nouvelle soumission dépassait de plus de 250 points, dépassant ainsi de nombreuses approches de compression intégrées.
Comme auparavant, le programme final a exactement 1024 octets. En fait, la sortie brute de l’algorithme d’optimisation contenait quatre octets échappés (
\0
) et que je devais "fudge" afin de réduire le nombre d'octets à 1024 octets. Sans le fudge, le programme de 1028 octets aurait un score de 4490,685, soit 7 points de mieux.L'idée de base est d'optimiser la palette et les données conjointement. En une seule itération, je recherche parmi tous les réglages de la palette (en gros, chaque palette modifiée qui diffère de 1 dans certains composants de couleur) et sélectionne la palette modifiée qui améliore le mieux le score. Ensuite, je recherche dans tous les réglages de données (chaque tableau d’index modifié dans lequel un pixel est remplacé par une autre entrée de palette) et choisis une modification qui réduit le score (ici, je ne me soucie pas de mieux, parce que vouloir chercher dans l’espace plein de plus de 25 000 modifications à chaque itération).
Enfin, lors de la génération de la sortie du programme final, je lance une autre passe d'optimisation qui réorganise la palette afin de minimiser le nombre de barres obliques inverses requises dans la sortie finale (par exemple, pour le programme présenté ci-dessous, la palette a été réorganisée à l'aide du tableau hexadécimal "0e3428916b7df5ca").
Cette approche a apporté une amélioration numérique et perceptuelle significative par rapport à la précédente approche naïve d'ImageMagick. Sortie précédente de la soumission:
Et nouvelle sortie de soumission:
La nouvelle approche basée sur l'optimisation offre beaucoup plus de détails et une reproduction précise des couleurs.
Voici l'hexdump du programme final:
Il y a encore de la place pour s'améliorer. Par exemple, un simple histogramme montre que certaines couleurs sont à peine utilisées:
Cela suggère qu'une palette rééquilibrée pourrait améliorer l'efficacité, peut-être suffisamment pour rattraper la solution à la 5ème place du GPB. Cependant, je doute fort que cette approche d'optimisation (ou, en réalité, tout ce qui n'implique pas la machinerie extraordinaire de H.265) puisse attraper la mise en œuvre BPG en premier lieu.
la source
Perl,
5955.968781245149.56218378En regardant l'approche du «charabia non imprimable», j'ai décidé que je pourrais aussi essayer cela en Perl. Encore une fois, je ne connais pas vraiment Perl, donc je suis sûr que cela peut être amélioré (en fait, l’amélioration la plus évidente, la réduction à 7 octets par ellipse en omettant le canal alpha, a déjà été implémentée pour la prochaine version, mais j’ai Je travaille toujours sur d’autres parties de ce code, je pense aussi que l’ensemble de la pop / push business peut être joué davantage).
Je ne pense pas que cela fonctionnera réellement sur les machines Windows (je ne peux pas tester), car je ne pouvais pas trouver un moyen facile d'ouvrir la section DATA en mode binaire - mais cela a fonctionné sur mes machines Linux.
J'ai pu continuer à utiliser mon même code GA pour créer:
Où la sortie xxd est:
Qui génère l'image:
Il est intéressant de noter que même si les résultats sont meilleurs, l'image me semble un peu moins bonne - il y a trop de choses avec toutes les ellipses supplémentaires, mais l'image la plus simple est plus facile à gérer visuellement.
Anciens résultats
Après avoir vu la réponse de jamieguinan , j'ai utilisé les ellipses comme primitive de dessin car, dans Perl, j'ai accès à la bibliothèque GD pour dessiner. Je ne suis pas du tout un expert Perl, donc toute suggestion serait utile. J'ai utilisé un algorithme génétique qui a été modifié à partir de ma réponse C ++ .
Cela semble fonctionner correctement, mais honnêtement, je suis un peu déçu du score. Je pourrais probablement le laisser courir un peu plus longtemps car vous pouvez facilement voir que quelques ellipses ne sont pas dans des positions optimales. Cependant, même maintenant, cela semble plus agréable à mes yeux par rapport à la solution basée sur un rectangle.
la source
Bash + Netpbm,
4558.54394.1MISE À JOUR: J'ai amélioré le score en utilisant SPIHT au lieu de FIASCO.
SPIHT est un acronyme pour Set Partitioning In Tier Hierarchical Arbres. C'est un format de compression d'image très efficace basé sur les ondelettes.
J'ai rétréci le fichier PNG d'origine par trimestre, puis converti au format PNM à l'aide
pngtopnm
de Netpbm v. 10.68, puis j'ai supprimé l'en-tête et converti les données RAW en SPIHT aveccodecolr in.raw out.spi 80 96 0.95
un fichier image de 913 octets. Ensuite, je l'ai reconverti en RAW en utilisantdecdcolr -s out.spi out.raw 0.95
, ensuite converti au format PNM en utilisantrawtoppm -bgr 96 80
, inversé en utilisantpamflip -tb
, en utilisant la conversion ascendante à la taille d'origine en utilisantpamscale -xsize 386 -ysize 320 -filter sinc
et enregistré dans un fichier PNM, qui est lu par PIL. Voici mon script (1KB):Voici la sortie PNG:
Vous trouverez ci-dessous ma réponse précédente:
FIASCO est un acronyme pour Fractal Image And Sequence COdec. Il s'agit d'une implémentation extrêmement efficace de la compression fractale avec pertes.
J'ai rétréci le fichier PNG d'origine par trimestre, puis converti en PNM à l'aide
pngtopnm
de Netpbm v. 10.68, puis converti en FIASCO avecpnmtofiasco -q=14 -z=3
un fichier image de 969 octets. Ensuite, je l'ai reconvertifiascotopnm
au format PNM en utilisant , mis à l'échelle vers la taille d'origine en utilisantpamscale -xyfill 386 320
et enregistré dans un fichier PNM, qui est lu par PIL. Voici mon script (1KB):En fait, je l'ai d'abord fait sous Windows
cmd
, mais le script ne correspondait pas à 1 Ko. Puis je l'ai réécrit dansbash
. Voici la sortie PNG:la source
Ruby, 7834.38
C'était amusant!
J'ai utilisé un programme générateur de ruby pour écrire un script ruby comme suit:
Bien que le fichier ruby généré soit inférieur à 1024 octets:
Notez que mon algorithme de notation échantillonne de manière aléatoire un groupe de couleurs et choisit celle qui entraîne la plus petite différence avec ORIGINAL.png. Comme il est probabiliste, j’ai relu le script plusieurs fois et choisi le résultat le plus faible.
Voici mon meilleur script à ce jour:
Il a généré l'image suivante, qui a marqué 7834 points:
Pour voir comment mon algorithme a abouti à cela, voici un GIF animé montrant comment il divise des rectangles:
Mon code est accessible sur GitHub à l' adresse https://github.com/jrotter/starry_night_contest.
la source
Java, 9215.38294502
Lecture de l'image au format GIF d'une taille de 8x6 pixels (!) À partir d'une chaîne codée en Base64 (contenant 368 caractères), puis redimensionnée de manière bilinéaire.
EDIT: Le résultat, tel que demandé dans les commentaires, est affiché dans cette image:
la source
Python 3, 5797.125628604383
Le programme de compression tronque d’abord les bits de l’image, puis convertit la base 2 en base 36.
Le programme de décodage le fait en sens inverse et redimensionne l'image.
la source