Cubify This! Une leçon de niveaux de gris ... euh ... couleur ... euh ... peu importe

27

Étant un grand fan du Rubik's cube et de l'art cool, j'ai travaillé sur la combinaison des deux pour faire des trucs vraiment cool. Fondamentalement, la résolution de cubes Rubik miniatures pour former des pixels rudimentaires dans la formation de l'art du cube Rubik. Des exemples d'un tel art peuvent être vus via ce lien: http://google.com/search?q=rubik%27s+cube+art

Maintenant, le but de ce Code Golf est de créer du code qui accepte une image en entrée, puis la convertit de la manière suivante:

L'image est initialement réduite à des couleurs de niveaux de gris adaptées au Web. Cela s'explique par le fait que nous devons isoler la palette de niveaux de gris sécurisée pour le Web (par exemple 000000, 333333, 666666, 999999, CCCCCC et FFFFFF). Un algorithme sur la méthode colorimétrique de conversion en niveaux de gris est disponible à: http://en.wikipedia.org/wiki/Grayscale#Colorimetric_.28luminance-preserving.29_conversion_to_grayscale , si vous souhaitez utiliser cela comme source d'inspiration.

On pourrait alors rendre l'échelle de gris aux couleurs appropriées. Pour le décomposer rapidement: 000000 fera référence au bleu Rubik, 333333 fera référence au rouge Rubik, 666666 fera référence au vert Rubik, 999999 fera référence à l'orange Rubik, CCCCCC fera référence au jaune Rubik et FFFFFF fera référence au blanc Rubik.

Je préférerais que votre code résultant puisse être rendu directement de la palette de la photo aux couleurs de Rubik. La méthode en deux étapes de conversion en niveaux de gris sécurisés pour le Web, puis dans la palette Rubik correspondante, est juste pour vous donner une idée de la logique derrière le processus, mais si cela est plus facile pour vous, faites-le par tous les moyens.

Les valeurs RVB réelles pour la palette de Rubik doivent correspondre à ce qui suit:

  • Rouge: # C41E3A
  • Vert: # 009E60
  • Bleu: # 0051BA
  • Orange: # FF5800
  • Jaune: # FFD500
  • Blanc: #FFFFFF

Pour vous donner un exemple, j'ai recadré la tête d'Abraham Lincoln à partir de l'image suivante:, entrez la description de l'image iciet rendu l'algorithme pour produire ce qui suit:

entrez la description de l'image ici

La grille est là pour que vous puissiez voir comment chaque cube Rubik miniature individuel devrait être configuré pour constituer l'image. La taille réelle de l'image résultante est de 45 pixels par 45 pixels, ce qui signifie que (45/3) * (45/3) = 15 * 15 = 225 cubes Rubik miniatures seraient utilisés pour créer cette image. Je ne m'attends pas à ce que vous présentiez l'image résultante avec une grille comme je l'ai fait.

Voici donc ce qui est requis:

  1. L'image à traiter par cet algorithme doit avoir une largeur de x pixels par une hauteur de y pixels, de telle sorte que x et y soient des multiples de 3. Ceci facilite la rendu dans le cadre d'une mosaïque de cubes Rubik. Si votre image est assez grande, il est conseillé de la réduire à environ 45 x 45 à 75 x 75 ou environ en dimensions avant le traitement. Gardez à l'esprit que ce composant de redimensionnement est FACULTATIF.

  2. L'image doit être convertie en la palette de cubes Rubik de sextacolored pour créer la mosaïque.

  3. L'image résultante doit être un fichier graphique valide après le traitement. Pour prouver que votre code fonctionne, exécutez-le contre une image de l'un des présidents des États-Unis d'Amérique ou d'une célébrité hollywoodienne bien connue. J'ai déjà utilisé Abraham Lincoln dans mon exemple, donc ce président ne peut plus être utilisé. Assurez-vous de fournir la langue que vous avez utilisée, le nombre d'octets ainsi que le président / célébrité utilisé pour tester votre code, y compris avant et après les prises de vue ...

  4. Chaque entrée doit avoir un président / célébrité unique comme cas de test. Je n'accepterai pas de doublons. Cela garantira que les résultats en double ne sont pas utilisés pour tester différentes entrées de code. C'est très bien de dire que votre code fonctionne, c'est une autre chose de le prouver.

5. Le code le plus court gagne.

Je change cela en un concours de popularité ... Je préfère voir qui peut le faire sans avoir à rivaliser sur le nombre d'octets ... Je vais donc l'attribuer avec une prime après le 28 février 2014.

WallyWest
la source
4
Je pense que ce serait mieux si vous ajoutiez les valeurs Rubik RGB au message au lieu de vous fier à un lien.
SztupY
Est-ce que «l'image à traiter doit avoir une largeur de x pixels par une hauteur de y pixels» signifie que le redimensionnement fait partie du code ou que l'image est prétraitée à la taille requise?
user2846289
Y a-t-il des états impossibles d'un Rubik's Cube si vous ne contraignez qu'une seule face?
Nick T
1
@WallyWest Vous AIMERIEZ mon application MineCam, elle le fait, mais plutôt que de créer des carrés, elle utilise des blocs artisanaux, et elle le fait également 15 fois par seconde avec la caméra iPhone en temps réel, convertissant ainsi le monde entier autour de vous en un mon univers artisanal. itunes.apple.com/us/app/minecam/id675845303?mt=8 (Si seulement cela pouvait aussi générer une graine pour ledit monde hahahaha)
Albert Renshaw
2
@WallyWest: il ne s'agit pas de paresse. Le problème devrait vous donner toutes les informations dont vous avez besoin pour commencer, même si le reste d'Internet est en panne. Dans un an ou deux, ce lien pourrait être supprimé et personne ne mettra à jour le lien. Si vous fournissez suffisamment d'informations sur la façon de créer des couleurs de niveaux de gris sécurisées pour le Web (ce qui n'est pas nécessaire pour résoudre le problème), vous auriez pu facilement ajouter une petite table de correspondance, comme #000000 => #0051BA, etc.
SztupY

Réponses:

16

Imagemagick (108)

Version: ImageMagick 6.8.7-7 Q16 x86_64 2013-11-27

L'appel suivant:

$ convert -resize 75x75 -fx "q=p.intensity;q<1/6?#0051BA:q<2/6?#C41E3A:q<3/6?#009e60:q<4/6?#ff5800:q<5/6?#FFD500:#FFF" input output

inputet outputdoivent être modifiés pour le nom de fichier d'entrée et de sortie.

Je n'ai compté que les caractères entre -resizeet #FFF", si vous pensez que cela n'est pas valide, n'hésitez pas à commenter.

J'ai utilisé Lenna comme image (elle est apparue dans un Playboy, et toute personne faisant cela devrait compter comme une célébrité hollywoodienne, non?)

Contribution:

Image d'entrée

Sortie:

$ convert -resize 75x75 -fx "q=p.intensity;q<1/6?#0051BA:q<2/6?#C41E3A:q<3/6?#009e60:q<4/6?#ff5800:q<5/6?#FFD500:#FFF" Lenna.png LennaRubik.png

Image générée

Sortie agrandie:

Image agrandie

Remarques: selon les documents imagemagick, vous ne pouvez pas avoir plus d'un opérateur conditionnel dans une instruction, mais l'appel semble toujours fonctionner correctement, donc cela a probablement été corrigé et les documents n'ont tout simplement pas été mis à jour.

En cours d'identification sur l'image du résultat (pour montrer que les couleurs sont bien fines):

$ identify -verbose LennaRubik.png
  (...)   
  Colors: 6
  Histogram:
       338: (  0, 81,186) #0051BA srgb(0,81,186)
      1652: (  0,158, 96) #009E60 srgb(0,158,96)
      1187: (196, 30, 58) #C41E3A srgb(196,30,58)
      1674: (255, 88,  0) #FF5800 srgb(255,88,0)
       706: (255,213,  0) #FFD500 srgb(255,213,0)
        68: (255,255,255) #FFFFFF white
  (...)

Si vous pensez que Lenna ne compte pas comme une véritable célébrité, voici Bruce Willis:

Bruce Original

Bruce Small

Bruce Large

SztupY
la source
+1 Je pense que votre réponse est presque imbattable (voire même imbattable). Je vais simplement suggérer que vous preniez incontestablement une photo de célébrité hollywoodienne ou de président américain et que vous ajoutiez à cela (pas besoin de supprimer Lenna, gardez les deux). Sinon, certaines personnes ennuyeuses pourraient se plaindre et dévaloriser simplement à cause de cela.
Victor Stafusa
@Victor: Je pense que Mathematica, Matlab ou Octave pourraient facilement battre cela, car les conditions à l'intérieur de la fxpièce peuvent être encore plus compressées dans un langage qui a une meilleure expressivité. Et ces langues ont également un support d'image natif (donc aucun caractère n'est perdu en ayant besoin d'importer imagemagick / gd / etc.)
SztupY
@SztupY Je connais très bien Lenna ... Je vais compter ça ... Beau travail avec Bruce Willis aussi ...
WallyWest
1
Lenna est mignonne (r). En haut.
blabla999
+1 pour l'utilisation du bon outil pour le travail. À ma connaissance, la bonne façon d'utiliser imagemagick est d'appeler d'abord l'image, puis les options, puis le fichier de sortie.
CousinCocaine
14

Mathematica

Nous travaillerons avec une région carrée à partir d'un timbre américain avec Greta Garbo. Il sera appelé j.

j

f[i_,rs_,m_:True]:=
Module[{(*rs=rastersize-4*)r={0.77,0.12,0.23},gr={0,0.62,0.38},b={0,0.32,0.73},o={1,0.35,0},y={1,0.84,0},w={1,1,1},
c1={r,gr,b,o,y,w},grayGreta,garboColors},
grayGreta=(*Reverse@*)ImageData[ColorQuantize[Rasterize[i,(*ImageResolution \[Rule]15*)RasterSize->rs+1,ImageSize->rs],6]];
garboColors=Union@Flatten[grayGreta,1];
ArrayPlot[grayGreta/.Thread[garboColors-> RGBColor@@@c1],
Mesh->If[m==True,{rs-1,rs-1},None],MeshStyle->Black]]

La fonction f prend 3 paramètres:

  • i qui fait référence à l'image
  • rs, la taille du raster
  • m, une variable booléenne qui indique si les lignes de maillage doivent être utilisées. (Le paramètre par défaut est True).

Utilisation de tailles de trame de 15, 30, 45 et 75:

GraphicsGrid[{{f[j, 15], f[j, 30]}, {f[j, 45], f[j, 75]}}, ImageSize -> 800]

4 garbos

Je ne peux pas imaginer quelqu'un faire un Rubrik's cube avec autant de pièces! Exercice intéressant néanmoins.


Jouer avec les couleurs

Ceci provient d'une entrée antérieure. Le code est légèrement différent. Graphicsest utilisé à la place de ArrayPlot. De plus, nous utilisons le tampon complet même s'il n'est pas carré.

Il existe 6! = 720 permutations des couleurs du cube Rubrik.

Ce qui suit affiche l'image centrale de la rangée supérieure (définissez 6 images ci-dessous). Lorsque les valeurs de niveaux de gris sont organisées du plus sombre au plus clair, les couleurs sont {r, gr, b, o, y, w}. D'autres variantes fonctionnent néanmoins.

i est l'image originale en niveaux de gris.

Graphics[Raster[(g=Reverse@ImageData[ColorQuantize[Rasterize[i,RasterSize->75],6]])
/.Thread[Union@Flatten[g,1]-> {{7,1,2},{0,6,4},{0,3,7},{10,4,0},{10,8,0},{10,10,10}}/10]]]

i est l'image originale en niveaux de gris du tampon Greta Garbo complet.

Rasterize[garbo,RasterSize->75 pixellise l'image dans un tableau 75 x 75.

ColorQuantize[<>, 6] réduit les valeurs de niveaux de gris à un ensemble de 6.

ImageDatarécupère le tableau de données de l'image; ça vient à l'envers.

Reverse retourne le tableau de données, d'où l'image, côté droit vers le haut.

garboColors sont les 6 valeurs de niveaux de gris dans l'image quantifiée.

Graphics[Raster affiche l'image finale.

rubrikColors sont les valeurs RVB des 6 couleurs du cube Rubrik.

Différentes permutations de couleur de rouge, vert, bleu, orange, jaune et blanc sont données.

r={0.77,0.12,0.23};gr={0,0.62,0.38};b={0,0.32,0.73};o={1,0.35,0};y={1,0.84,0};w={1,1,1};
c1={r,gr,b,o,y,w};
c2={r,b,gr,o,y,w};
c3={b,r,gr,o,y,w};
c4={gr,b,r,o,y,w};
c5={b,r,gr,y,o,w};

Et le code:

grayGreta=Reverse@ImageData[ColorQuantize[Rasterize[i,RasterSize->75],6]];
garboColors=Union@Flatten[grayGreta,1];
Grid[{{i,
Graphics[Raster[grayGreta/.Thread[garboColors-> c1]]],
Graphics[Raster[grayGreta/.Thread[garboColors-> c2]]]},
{Graphics[Raster[grayGreta/.Thread[garboColors-> c3]]],
Graphics[Raster[grayGreta/.Thread[garboColors-> c4]]],
Graphics[Raster[grayGreta/.Thread[garboColors-> c5]]]}}]

garbos


Garbos Galore

Voici 72 (sur 720) images de Greta Garbo qui utilisent les 6 couleurs du cube Rubrik. Certaines images fonctionnent mieux que d'autres, vous ne pensez pas?

GraphicsGrid@Partition[(Graphics[Raster[grayGreta /. Thread[garboColors -> #]]] & 
/@ Take[Permutations[{r, gr, b, o, y, w}, {6}], 72]), 12]

garbos à gogo

DavidC
la source
Greta, oh Greta ... Cela s'est avéré mieux que ce à quoi je m'attendais. @DavidCarraher, beau travail ici ...
WallyWest
@WallyWest. Merci. C'était un défi très intéressant.
DavidC
J'étais tellement sûr que Mathematica battrait imagemagick, ne peut-on pas jouer au golf encore plus loin? Toutes ces fonctions sont-elles requises?
SztupY
1
@SztupY La moitié du code est dédiée à obtenir les bonnes couleurs. Reversepourrait être éliminé, laissant l'image à l'envers, mais je ne vois pas d'autres opportunités. Mathematica est expressif mais utilise de gros mots. Quelqu'un adepte des images pourrait probablement réduire un peu la taille du code mais je doute qu'ils pourraient battre votre code imagemagick.
DavidC
1
Il y avait en effet quelques incohérences dans le code. J'espère qu'ils sont maintenant partis. itenir l'image d'origine. grreprésente le vert de Rubrik. gfait référence aux données d'image tramées et quantifiées pour l'image en niveaux de gris.
DavidC
6

Smalltalk (Smalltalk / X), 289 139 *

entrée: i; sortie: r

r:=i magnifiedTo:75@75.
r colorMapProcessing:[:c||b|b:=c brightness.Color rgbValue:(#(16r0051BA 16rC41E3A 16r009e60 16rff5800 16rFFD500 16rFFFFFF)at:(b*6)ceiling)]

contribution:

entrez la description de l'image ici

sortie:

entrez la description de l'image ici

agrandi:

entrez la description de l'image ici

(pour tous les jeunes: ce n'est PAS Madonna ;-)

[*] Je n'ai pas compté le grossissement jusqu'à 75x75 (la première ligne) - j'aurais pu utiliser un déjà redimensionné comme entrée. J'espère que cela vous convient.

blabla999
la source
J'adore Marilyn Monroe ... Excellent choix ... Le redimensionnement était une fonctionnalité optionnelle ...
WallyWest
4

Post-scriptum et VRAIES couleurs Rubik! ;-)

Eh bien, cette solution est un peu hors sujet ici, car elle se limite à une sphère quelque peu hautement spécialisée. Mais après beaucoup de frustration avec, par exemple, "la question des nombres étranges" (étant incapable de produire quelque chose qui fonctionne pratiquement), j'ai décidé de publier quelque chose et j'ai donc retiré cela de ma pile de gribouillis à moitié finis et je l'ai rendu présentable.

La solution exploite le fait que la première révision de cette question définit les couleurs requises par un lien vers un site, ce qui indique clairement que les couleurs Pantone (R) doivent être utilisées et que les couleurs RVB ne sont que des approximations. Alors j'ai pensé, pourquoi devrais-je faire des approximations, quand je peux faire de la vraie couleur? - :)

10 dict begin
/Size 75 def
/Names  [(PMS 012C) (PMS 021C) (PMS 347C)   (PMS 200C)    (PMS 293C)   ] def
/Colors [[0 .16 1 0][0 .65 1 0][1 0 .39 .38][0 .9 .72 .28][1 .56 0 .27]] def
<</PageSize [Size dup]>> setpagedevice
Size dup scale
true setoverprint
(%stdin) (r) file 100 string readline pop 
(r) file <</CloseSource true>>/DCTDecode filter
0 1000000 string 
dup <</CloseTarget true>>/NullEncode filter 
{
    3 index 3 string readstring
    {
        4 -1 roll 1 add 4 1 roll
        {} forall
        0.11 mul exch 0.59 mul add exch 0.3 mul add cvi
        1 index exch write
    } {pop exit} ifelse
} loop
closefile
0 3 -1 roll getinterval
exch closefile
/data exch def
/n data length sqrt cvi def
1 1 Names length {
    /N exch def
    { 
        dup N Names length 1 add div gt 
            {N 1 add Names length 1 add div gt 
                {1} {0} ifelse} 
            {pop 1} 
        ifelse
    } settransfer
    [/Separation Names N 1 sub get /DeviceCMYK {
        Colors N 1 sub get 
        { 1 index mul exch } forall pop
    }] setcolorspace
    <<
        /ImageType        1
        /Width            n
        /Height           n
        /ImageMatrix      [n 0 0 n neg 0 n]
        /BitsPerComponent 8
        /Decode           [0 1]
        /DataSource       data
    >> image
} for
showpage
end

Ce code doit être enregistré comme par exemple rubik.ps, puis envoyé à Ghostscript avec une incantation habituelle:

gs -q -sDEVICE=psdcmyk -o out.psd rubik.ps

Il vous attend ensuite sur la ligne suivante, pour la saisie du nom de fichier JPG par exemple

kelly.jpg

et, si tout se passe bien, enregistre la sortie dans un out.psdfichier.

L'entrée doit être RGB RVB carré (n'importe quelle taille), la sortie est PSD avec des canaux de couleurs d'accompagnement. Vous aurez besoin de Photoshop pour afficher le fichier. Le changement d'appareil GS de psdcmykn'importe quoi d'autre ne produira rien d'utile. JPEG en entrée - parce que l'interpréteur postscript peut décoder directement le flux de données. Forme carrée - car le programme s'appuie sur sqrtla longueur de la chaîne pour trouver la largeur (et la hauteur) de l'image.

Les premières lignes définissent la taille de l'image de sortie (peut être modifiée par rapport à 75 par défaut) et la palette de couleurs (les couleurs et leur nombre peuvent également être modifiés). Je pense que tout le reste n'est pas codé en dur.

Que se passe-t-il? Le flux de triplets RVB est converti à la volée en une chaîne de valeurs de niveaux de gris (avec une formule simple), un dictionnaire d'images de contone 8 bits habituel est construit et utilisé pour peindre 5 images identiques les unes sur les autres dans 5 Separationespaces colorimétriques. L'astuce consiste à appliquer des fonctions de transfert avant chaque appel d' imageopérateur. Par exemple, pour la peinture jaune, cette fonction renvoie 0 pour les valeurs d'entrée dans la plage 0,167 .. 0,333 uniquement, et 1 sinon.

Contribution:

entrez la description de l'image ici

Capture d'écran de la sortie 75x75 ouverte dans Photoshop, agrandie 800%:

entrez la description de l'image ici

Et la palette des canaux Photoshop:

entrez la description de l'image ici

user2846289
la source
1
+1 pour l'utilisation de Grace Kelly ... vous avez tout mon respect ...
WallyWest
3

C #

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;

class Program
{
    static void Main(string[] args)
    {
        unchecked
        {
            var t = new[] { 0xFFC41E3A, 0xFF009E60, 0xFF0051BA, 0xFFFF5800, 0xFFFFD500, 0xFFFFFFFF }.Select(v => Color.FromArgb((int)v)).ToArray();
            var o = new Bitmap(Bitmap.FromFile(args[1]));
            var m = double.Parse(args[0]);
            var r = Math.Min(m / o.Width, m / o.Height);
            var w = (int)(o.Width * r);
            var h = (int)(o.Height * r);

            o = new Bitmap(o, w - (w % 3), h - (h % 3));
            for (int y = 0; y < o.Height; y++)
                for (int x = 0; x < o.Width; x++)
                    o.SetPixel(x, y, N(o.GetPixel(x, y), t));
            o.Save(args[2], ImageFormat.Png);
        }
    }

    static Color N(Color c, Color[] t)
    {
        return t.OrderBy(v => Math.Abs(W(v) - W(c))).First();
    }

    static double W(Color c)
    {
        return .11 * c.B + .59 * c.G + .30 * c.R;
    }
}

Vous devez l'exécuter avec 3 paramètres:

foo.exe 75 d:\test.jpg d:\out.png

75est max. largeur / hauteur, d:\test.jpgest le fichier d'entrée et d:\out.pngle fichier de sortie.

Sortie pour différentes images dans ce concours:

WallyWest SztupY 1 SztupY 2 blabla999

Ma propre célébrité:

Garth!

Sortie:

Garth 75 Garth 225

Cependant, d'autres tailles (supérieures à 75x75) donnent de meilleures images:

150 300

Et, si nous nous en tenons aux présidents:

DubbaYa 294 DubbaYa 75 DubbaYa 225

Puisque ce n'est plus (plus?) Du codegolf, je n'ai pas pris la peine de "minimiser" trop le code. De plus, comme les instructions ne mentionnaient pas spécifiquement que l'image devait avoir la même largeur que la hauteur (carré), je ne me suis pas donné la peine de recadrer; Je fais cependant, assurez - vous que l'image est un multiple de 3 pixels de large / haut. Si vous voulez des images carrées, utilisez des entrées carrées : PEnfin; l'algorithme est loin d'être optimal.

Un peu plus (puisque les gens votent plus pour les poussins chauds / les héros Internet : P)

Kari Byron 300 Kari Byron 75 Kari Byron 225 Le Hoff 300 Le Hoff 75 Le Hoff 225

RobIII
la source
3

Brainfuck

++++[->+[,.----------]<]>>>>---->->++++++++++>>------------>+++>+++>--
--->++++++[->+++++<]---->+[-<+++++++<+++<+++++<+++<+++<++++++<++++++<+
<++>>>>>>>>>]<[<]<<,+[,<++++++>[>++++++[->+++++++<]>+[<<[->]>[<]>-]<<<
->]+<[-[-[-[-[[-].>>>>>>>>.<.<<<<<<-<]>[->>>>>[.<]<<]<]>[-.>>>[>]<<<.<
.[<]<<]<]>[--.+>>>[>]<<.[<].<<]<]>[--.+>>>[>]<.[<].<<]<]>[--...+],,+]

Cela nécessite un interpréteur / compilateur BF qui a -1 comme EOF et qui a plus de 8 cellules binaires SI l'un des pixels rouges est 255. Sinon, il s'arrêtera prématurément car il ne pourra pas différer entre EOF et la valeur 0xFF . Avec jitbf, vous avez tout ce que la machine a comme taille entière et pouvez le faire pour forcer -1 comme EOF:

jitbf --eof -1 rubiks.bf < angelina.pnm > angelina-rubix.pnm

Le format de fichier d'image rendu est le fichier PNM RVB complet (P6), brut en option dans Gimp.

Il utilise uniquement le canal vert (qui est l'une des nombreuses façons de convertir une image couleur en niveaux de gris). Il réduit la valeur de 43 sans réduire la valeur en dessous de zéro pour savoir quelle couleur rubiks utiliser et avoir un commutateur qui imprime la bonne couleur RBG qui correspond.

Image d'Angelina Jolie de Hackers (1995) réduite à 75x75 et traitée avec l'application:

Angelina Jolie 75x75 / Fair Use Angelina Jolie 75x75 en couleurs cube Rubiks / Fair Use Même échelle 6x

Pareil, seulement j'ai utilisé la taille d'origine :

Idem seulement non réduit en premier / Utilisation équitable

Et puisque je suis psychique, voici également un président:

Arnold Schwarzenegger CC de Wikipedia

Sylwester
la source
Hors sujet, mais xkcd a également des références à Hackers (1995)
Sylwester
1
Celui-ci fait aussi: xkcd.com/1247
Shade
1

Objectif c

J'ai vu ce défi la nuit dernière et j'ai eu un temps un peu déroutant -[NSArray indexOfObject:inSortedRange:options:usingComparator:], d'où le retard.

- (UIImage  *)rubiksImage:(UIImage *)inputImg
{
    //Thank you http://stackoverflow.com/a/11687434/1153630 for the greyscale code
    CGRect imageRect = CGRectMake(0, 0, inputImg.size.width, inputImg.size.height);

    int width = imageRect.size.width;
    int height = imageRect.size.height;

    uint32_t *pixels = (uint32_t*)malloc(width * height * sizeof(uint32_t));

    memset(pixels, 0, width * height * sizeof(uint32_t));

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(pixels, width, height, 8, width * sizeof(uint32_t), colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedLast);

    CGContextDrawImage(context, imageRect, [inputImg CGImage]);

    const int RED = 1;
    const int GREEN = 2;
    const int BLUE = 3;

    for (int y = 0; y < height; y++)
    {
        for (int x = 0; x < width; x++)
        {
            uint8_t* rgbaPixel = (uint8_t*)&pixels[y * width + x];
            uint32_t grayPixel = 0.3 * rgbaPixel[RED] + 0.59 * rgbaPixel[GREEN] + 0.11 * rgbaPixel[BLUE];

            NSArray *r = [self rubixColorFromGrey:grayPixel];

            rgbaPixel[RED] = [r[2] integerValue];
            rgbaPixel[GREEN] = [r[1] integerValue];
            rgbaPixel[BLUE] = [r[0] integerValue];
        }
    }

    CGImageRef newCGImage = CGBitmapContextCreateImage(context);

    CGContextRelease(context);
    CGColorSpaceRelease(colorSpace);
    free(pixels);

    UIImage* newUIImage = [UIImage imageWithCGImage:newCGImage];

    CGImageRelease(newCGImage);

    return newUIImage;
}

- (NSArray *)rubixColorFromGrey:(uint32_t)p
{
    NSArray *colors = @[@0, @51, @102, @153, @204, @255];

    NSUInteger index = [colors indexOfObject:@(p)
                               inSortedRange:NSMakeRange(0, colors.count)
                                     options:NSBinarySearchingInsertionIndex | NSBinarySearchingFirstEqual
                             usingComparator:^(id a, id b) {
                                return [a compare:b];
                             }];
    switch (index) {
        case 0:
            return rgb(0, 81, 186);
            break;
        case 1:
            return rgb(196, 30, 58);
            break;
        case 2:
            return rgb(0, 156, 96);
            break;
        case 3:
            return rgb(255, 82, 0);
            break;
        case 4:
            return rgb(255, 213, 0);
            break;
        case 5:
            return rgb(255, 255, 255);
            break;

        default:
            break;
    }

    return colors; //go wild
}

NSArray *rgb(int r, int g, int b)
{
    return @[@(r), @(g), @(b)];
}

Je l'ai exécuté sur mon iPad comme ceci:

UIImageView *img = [[UIImageView alloc] initWithImage:[self rubiksImage:[UIImage imageNamed:@"danny.png"]]];
[img setCenter:self.view.center];
[self.view addSubview:img];

Avant Danny DeVito avant Après Danny DeVito After

Avant Grace Kelly avant Après Grace Kelly After

Max Chuquimia
la source
1

Python

Format: python rubik.py <input> <max_cubes> <output>.

Couvre le pixel en niveaux de gris en utilisant l'algorithme suggéré.

import Image, sys

def rubik(x, max_cubes = 25):

    img = x
    max_cubes *= 3

    if x.size[0] > max_cubes or x.size[1] > max_cubes:

        print "Resizing image...",

        if x.size[0] > x.size[1]:
            img = x.resize((max_cubes, int(max_cubes * float(x.size[1]) / x.size[0])), Image.ANTIALIAS)
        else:
            img = x.resize((int((max_cubes * float(x.size[0]) / x.size[1])), max_cubes), Image.ANTIALIAS)

    if x.size[0] % 3 or x.size[1] % 3:
        print "Sizes aren't multiples of 3"
        return

    print "Image resized to %i x %i pixels" % img.size

    out = Image.new('RGB', img.size)

    print "Converting image...",

    for x in xrange(out.size[0]):
        for y in xrange(out.size[1]):
            r, g, b = img.getpixel((x, y))
            if r == g == b == 255:
                out.putpixel((x,y), (255, 255, 255))
            else:
                l = 0.2126 * r + 0.7152 * g + 0.0722 * b
                l /= 255
                out.putpixel((x,y), (
                        (0x00, 0x51, 0xBA),
                        (0xC4, 0x1E, 0x3A),
                        (0x00, 0x9E, 0x60),
                        (0xFF, 0x58, 0x00),
                        (0xFF, 0xD5, 0x00)
                    )[int(5 * (l <= 0.0031308 and 12.92 * l  or 1.055 * l ** (1/2.4) - 0.055))])

    print "Image converted successfully."

    print "Stats:"
    h, v = img.size[0] / 3, img.size[1] / 3
    print "   ", h, "horiz. Rubik cubes"
    print "   ", v, "vert. Rubik cubes"
    print "   ", h * v, "total Rubik cubes"

    return out.resize((out.size[0], out.size[1]))

if __name__ == "__main__":
    rubik(Image.open(sys.argv[1]).convert("RGB"), int(sys.argv[2])).save(sys.argv[3])

Contribution:

Sandro Pertini
(source: ilmamilio.it )

Sortie avec max_cubes = 25:

Sandro Pertini, Rubik'd 1

Sortie avec max_cubes = 75:

Sandro Pertini, Rubik'd 2

Sortie avec max_cubes = 225:

Sandro Pertini, Rubik'd 3

Oberon
la source
La couleur blanche n'est-elle pas manquante? Et le plus sombre devrait être bleu, mais, comme je le vois maintenant, c'est aussi le problème avec d'autres images.
user2846289
@VAdimiR Oups! Les a cartographiés dans le mauvais ordre. Quant au blanc qui n'apparaît pas, c'est à cause de la précision FP (1.055 - 0.055 = 0.9999999999999999). Je pense que je vais devoir coder en dur le blanc, ce qui n'est pas difficile, car il n'apparaîtrait qu'à une valeur originale de #FFFFFF de toute façon.
Oberon
À propos du blanc, mon opinion était que la plage 0..1 (légèreté) est divisée en 6 parties, et tout ce qui est 0.83..1.00 est mappé sur le blanc, sinon il n'y aura pas beaucoup de sens à faire une image de 6 couleurs du cube , mais c'est comme ça que je l'ai lu.
user2846289
@Oberon Choix intéressant en utilisant Pertini ... Il a presque vécu jusqu'à 94 ans ... Et un excellent travail en utilisant Python, et je dois admettre que ce n'est pas l'une des langues les plus faciles que j'ai rencontrées, donc bien fait!
WallyWest