Basé sur le très réussi défi d’encodage d’images Twitter de Stack Overflow.
Si une image vaut 1 000 mots, quelle taille d'image pouvez-vous contenir dans 114,97 octets?
Je vous mets au défi de proposer une méthode générique pour compresser les images dans un commentaire Twitter standard contenant uniquement du texte ASCII imprimable .
Règles:
- Vous devez écrire un programme pouvant prendre une image et générer le texte codé.
- Le texte créé par le programme doit comporter au maximum 140 caractères et uniquement des caractères dont les points de code sont compris entre 32 et 126 inclus.
- Vous devez écrire un programme (éventuellement le même programme) pouvant prendre le texte codé et générer une version décodée de la photo.
- Votre programme peut utiliser des bibliothèques et des fichiers externes, mais ne peut pas nécessiter une connexion Internet ou une connexion à d'autres ordinateurs.
- Le processus de décodage ne peut en aucun cas accéder aux images d'origine ni les contenir.
- Votre programme doit accepter les images dans au moins un de ces formats (pas nécessairement plus): Bitmap, JPEG, GIF, TIFF, PNG. Si certaines ou toutes les images exemples ne sont pas au format correct, vous pouvez les convertir vous-même avant la compression par votre programme.
Juger:
C'est un défi quelque peu subjectif, donc le gagnant sera (éventuellement) jugé par moi. Je concentrerai mon jugement sur deux facteurs importants, énumérés ci-dessous par ordre décroissant d'importance:
- Capacité à compresser une grande variété d’images, y compris celles qui ne figurent pas dans la liste en exemple
- Capacité à conserver les contours des principaux éléments d'une image
- Possibilité de compresser les couleurs des principaux éléments d'une image
- Capacité à conserver les contours et les couleurs des détails mineurs dans une image
- Temps de compression. Bien qu’ils ne soient pas aussi importants que la qualité de la compression d’une image, les programmes plus rapides sont meilleurs que les programmes plus lents qui font la même chose.
Votre soumission doit inclure les images obtenues après décompression, ainsi que le commentaire Twitter généré. Si possible, vous pouvez également donner un lien vers le code source.
Réponses:
J'ai amélioré ma méthode en ajoutant la compression réelle. Il fonctionne maintenant de manière itérative:
Réduire la taille de l'image en préservant les proportions (si l'image est en couleur, le chroma est échantillonné à 1/3 de la largeur et de la hauteur de la luminance)
Réduire la profondeur de bits à 4 bits par échantillon
Appliquer la prédiction médiane à l'image, rendant la distribution de l'échantillon plus uniforme
Appliquez une compression de plage adaptative à l'image.
Voir si la taille de l'image compressée est <= 112
La plus grande image contenue dans les 112 octets est ensuite utilisée comme image finale, les deux octets restants étant utilisés pour stocker la largeur et la hauteur de l'image compressée, ainsi qu'un drapeau indiquant si l'image est en couleur. Pour le décodage, le processus est inversé et l'image est mise à l'échelle. La plus petite dimension est donc 128.
Des améliorations sont possibles, à savoir que tous les octets disponibles ne sont pas tous utilisés de manière typique, mais j’estime que les rendements pour le sous-échantillonnage et la compression sans perte diminuent considérablement.
Source C ++ rapide et sale
Windows exe
Mona Lisa (luminance 13x20, 4x6 couleurs)
Hindenburg (luminance 21x13)
Montagnes (luminance 19x14, chrominance 6x4)
Formes 2D (luminance 21x15, chroma 7x5)
la source
Aller
Fonctionne en divisant l'image en régions de manière récursive. J'essaie de diviser les régions à fort contenu en informations et de choisir la ligne de division pour maximiser la différence de couleur entre les deux régions.
Chaque division est codée en utilisant quelques bits pour coder la ligne de division. Chaque région feuille est codée en une seule couleur.
La photo de Hindenburg est plutôt moche, mais les autres me plaisent.
la source
Python
L'encodage nécessite numpy , SciPy et scikit-image .
Le décodage ne nécessite que PIL .
Ceci est une méthode basée sur l'interpolation de superpixels. Pour commencer, chaque image est divisée en 70 régions de taille similaire et de couleur similaire. Par exemple, l'image de paysage est divisée de la manière suivante:
Le centre de gravité de chaque région est situé (jusqu'au point de trame le plus proche sur une grille ne contenant pas plus de 402 points), ainsi que sa couleur moyenne (à partir d'une palette de 216 couleurs), et chacune de ces régions est codée sous la forme d'un nombre de 0 à 86832 , capable d’être stockée dans 2,5 caractères ascii imprimables (en fait, 2 497 , laissant juste assez de place pour encoder un bit en niveaux de gris).
Si vous êtes attentif, vous avez peut-être remarqué que 140 / 2,5 = 56 régions et non pas 70 comme je l’ai dit plus tôt. Notez cependant que chacune de ces régions est un objet unique et comparable, qui peut être répertorié dans n'importe quel ordre. Pour cette raison, nous pouvons utiliser la permutation des 56 premières régions pour coder pour les 14 autres , tout en conservant quelques bits pour stocker le rapport de format.
Plus spécifiquement, chacune des 14 régions supplémentaires est convertie en un nombre, puis chacun de ces nombres est concaténé ensemble (en multipliant la valeur actuelle par 86832 et en ajoutant la suivante). Ce nombre (gigantesque) est ensuite converti en une permutation sur 56 objets.
Par exemple:
affichera:
La permutation résultante est ensuite appliquée aux 56 régions d'origine. Le nombre original (et donc les 14 régions supplémentaires ) peut également être extrait en convertissant la permutation des 56 régions codées en sa représentation numérique.
Lorsque l'
--greyscale
option est utilisée avec le codeur, 94 régions sont utilisées ( 70 , 24 séparées ), avec 558 points de trame et 16 nuances de gris.Lors du décodage, chacune de ces régions est traitée comme un cône 3D étendu à l'infini, avec son sommet au centre de la région, vu de dessus (diagramme de Voronoï). Les bordures sont ensuite mélangées pour créer le produit final.
Améliorations futures
Les dimensions de la Mona Lisa sont un peu décalées en raison de la façon dont je stocke les proportions. Je devrai utiliser un système différent.Corrigé, en supposant que le format d’aspect original se situe entre 1:21 et 21: 1, ce qui, à mon avis, est une hypothèse raisonnable.Le Hindenburg pourrait être beaucoup amélioré. La palette de couleurs que j'utilise ne contient que 6 nuances de gris. Si j'introduisais un mode avec niveaux de gris uniquement, je pourrais utiliser les informations supplémentaires pour augmenter la profondeur de couleur, le nombre de régions, le nombre de points raster ou toute combinaison des trois.J'ai ajouté une--greyscale
option à l'encodeur, qui fait les trois.Les formes 2D auraient probablement un meilleur aspect si le mélange était désactivé. Je vais probablement ajouter un drapeau pour cela.Ajout d'une option de codeur pour contrôler le taux de segmentation et d'une option de décodeur pour désactiver le mélange.et
Le second encodé avec l'
--greyscale
option.Encodé avec l'
--greyscale
option.Encodé avec
--ratio 60
et décodé avec des--no-blending
options.encoder.py
decoder.py
my_geom.py
la source
PHP
OK, ça m'a pris un moment, mais le voici. Toutes les images en niveaux de gris. Les couleurs ont pris trop de bits à encoder pour ma méthode: P
Mona Lisa
47 couleurs Chaîne de
101 octets monochrome .
Formes 2D
36 couleurs Chaîne monochrome de
105 octets.
Hindenburg
62 couleurs monochromes
112 caractères.
Montagnes
63 couleurs monochromes
122 caractères.
Ma méthode
Je code mon train de bits avec un type de codage base64. Avant qu’il ne soit encodé en texte lisible, voici ce qui se passe.
Je charge l'image source et la redimensionne à une hauteur ou une largeur maximale (selon l'orientation, portrait / paysage) de 20 pixels.
Ensuite, je recolore chaque pixel de la nouvelle image à sa correspondance la plus proche sur une palette en niveaux de gris à 6 couleurs.
Ensuite, je crée une chaîne avec chaque couleur de pixel représentée par les lettres [AF].
Je calcule ensuite la distribution des 6 lettres différentes dans la chaîne et sélectionne l’arbre binaire le plus optimisé pour l’encodage en fonction des fréquences des lettres. Il y a 15 arbres binaires possibles.
Je commence mon flux de bits avec un seul bit,
[1|0]
selon que l'image est haute ou large. J'utilise ensuite les 4 bits suivants du flux pour indiquer au décodeur quel arbre binaire doit être utilisé pour décoder l'image.Ce qui suit est le flux de bits représentant l'image. Chaque pixel et sa couleur sont représentés par 2 ou 3 bits. Cela me permet de stocker au moins 2 et 3 pixels d’informations pour chaque caractère ASCII imprimé. Voici un exemple d'arbre binaire
1110
utilisé par Mona Lisa:Les lettres E
00
et F10
sont les couleurs les plus courantes dans la Mona Lisa. A010
, B011
, C110
et D111
sont les moins fréquents.Les arbres binaires fonctionnent comme ceci: aller d’un bout à l’autre
0
signifie aller à gauche,1
aller à droite. Continuez jusqu'à ce que vous frappiez une feuille sur l'arbre ou une impasse. La feuille sur laquelle vous vous retrouvez est le personnage que vous voulez.Quoi qu'il en soit, je code la chaîne binaire en caractères base64. Lors du décodage de la chaîne, le processus est effectué en sens inverse, attribuant tous les pixels à la couleur appropriée, puis l'image est redimensionnée deux fois plus grande que la taille codée (40 pixels au maximum, soit X ou Y, selon la valeur la plus grande), puis une matrice de convolution appliqué à l'ensemble pour lisser les couleurs.
Quoi qu'il en soit, voici le code actuel: " pastebin link "
C'est moche, mais si tu vois des améliorations à apporter, fais-le-moi savoir. Je l'ai piraté comme je veux. J'ai beaucoup appris de ce défi. Merci OP pour le poster!
la source
Ma première tentative Cela peut encore être amélioré. Je pense que le format lui-même fonctionne réellement, le problème est dans le codeur. Cela, et il me manque des bits individuels dans ma sortie ... mon fichier (de qualité légèrement supérieure à celle ici) s'est terminé à 144 caractères, alors qu'il aurait dû en rester quelques-uns. (et j'espère vraiment qu'il y en a eu - les différences entre celles-ci et celles-ci sont perceptibles). J'ai cependant appris à ne jamais surestimer la taille de 140 caractères ...
Je l'ai ramenée à une version modifiée de la palette RISC-OS, car j'avais besoin d'une palette de 32 couleurs, ce qui semblait être un bon point de départ pour commencer. Cela pourrait faire avec certains changements aussi, je pense.
Je la décompose en plusieurs formes: et scinde l'image en blocs de palette (2x2 pixels) d'une couleur avant et d'une couleur arrière.
Résultats:
Voici les tweets, les originaux et comment le tweet est décodé
Je sais que les couleurs sont fausses, mais j'aime bien le Monalisa. Si j'ai supprimé le flou (ce qui ne serait pas trop difficile), c'est une impression cubiste raisonnable: p
J'ai besoin de travailler
Je vais lui donner un peu plus de travail plus tard pour essayer de les résoudre et améliorer l'encodeur. Ces 20 personnages supplémentaires font une énorme différence. Je les voudrais revenir.
La source et la palette de couleurs C # se trouvent à l' adresse https://dl.dropboxusercontent.com/u/46145976/Base96.zip - même si, avec le recul, elles ne fonctionnent pas parfaitement lorsqu'elles sont exécutées séparément (car les espaces dans les arguments des programmes ne le sont pas bien).
L'encodeur prend moins de quelques secondes sur ma machine plutôt moyenne.
la source
J'ai renoncé à essayer de conserver la couleur et je suis passé au noir et blanc, car tout ce que j'avais essayé avec la couleur était méconnaissable.
En gros, il divise les pixels en trois parties à peu près égales: noir, gris et blanc. Il ne conserve pas non plus la taille.
Hindenburg
Mona Lisa
Les montagnes
Formes
Voici le programme.
python compress.py -c img.png
compresseimg.png
et imprime le tweet.python compress.py -d img.png
prend le tweet de stdin et enregistre l'image dansimg.png
.la source
Ma modeste contribution en R:
L'idée est simplement de réduire le raster (le fichier doit être en png) à une matrice dont le nombre de cellules est inférieur à 140, les tweets sont alors une série de couleurs (en 64 couleurs) précédée de deux caractères indiquant le nombre de lignes et colonnes du raster.
la source
Pas une solution complète, il suffit de mettre la méthode en place. (Matlab)
J'ai utilisé une palette de 16 couleurs et 40 positions pour créer un diagramme de voronoï pondéré . Utiliser un algorithme génétique et un algorithme simple pour grimper une colline pour s’ajuster à l’image.
Album avec image originale et j'ai aussi une version 16 octets avec 4 couleurs et positions fixes. :)
(Puis-je redimensionner l'image ici?)
la source
C #
Mise à jour - version 2
J'ai fait une autre tentative en utilisant maintenant MagickImage.NET ( https://magick.codeplex.com/ ) pour coder les données JPEG. J'ai également écrit du code de base pour mieux traiter les données d'en-tête JPEG (comme suggéré par Primo), j'ai également GuassianBlur a été utilisé en sortie pour atténuer une partie de la compression JPEG. Comme la nouvelle version préforme mieux, j'ai mis à jour mon message pour refléter la nouvelle méthode.
Méthode
J'ai essayé quelque chose d'unique (j'espère) plutôt que d'essayer de manipuler la profondeur de couleur ou l'identification des contours, ou d'essayer d'utiliser différentes méthodes pour réduire la taille des images moi-même. J'ai utilisé l'algorithme JPEG à compression maximale sur les versions réduites de les images, puis en éliminant tout sauf le "StartOfScan" ( http://en.wikipedia.org/wiki/JPEG#Syntax_and_structure ) et quelques éléments d'en-tête clés, je suis en mesure de réduire la taille à un niveau acceptable. Les résultats sont en fait assez impressionnants pour 140 caractères, ce qui me donne un nouveau respect pour les JPEG:
Hindenburg
Les montagnes
Mona Lisa
Formes
Code
Version 2 - http://pastebin.com/Tgr8XZUQ
ReSharper + commence vraiment à me manquer. J'ai beaucoup de choses à améliorer, beaucoup de codage difficile à faire ici, intéressant de jouer avec (cependant, vous avez besoin de dll MagickImage pour que cela fonctionne dans VS).
Original (obsolète) - http://pastebin.com/BDPT0BKT
Encore un peu de gâchis.
la source
Python 3
Méthode
Ce que le programme fait en premier lieu, réduit la taille de l’image, ce qui diminue considérablement sa taille.
Deuxièmement, il convertit les valeurs rgb en binaires et coupe les derniers chiffres.
Ensuite, il convertit les données de base 2 en base 10, où il ajoute les dimensions de l'image.
Ensuite, il convertit les données de la base 10 en base 95, en utilisant tout ce que j'ai pu trouver. Cependant, je ne pouvais pas utiliser / x01, etc., à cause de sa capacité à annuler la fonction qui a écrit le fichier texte.
Et (pour plus d'ambiguïté), la fonction de décodage le fait à l'envers.
compress.py
decode.py
Le cri
Mona Lisa
Sphères
la source