Cubify This! Uma lição em escala de cinza ... er ... cor ... er ... tanto faz

27

Sendo um grande fã do cubo de Rubik e da arte legal, tenho trabalhado na combinação dos dois para fazer coisas realmente legais. Resolvendo basicamente os cubos de Rubik em miniatura para formar pixels rudimentares na formação da arte do cubo de Rubik. Exemplos dessa arte podem ser vistos neste link: http://google.com/search?q=rubik%27s+cube+art

Agora, o objetivo deste Code Golf é criar um código que aceite uma imagem como entrada e depois a converta da seguinte maneira:

A imagem é inicialmente reduzida para cores em escala de cinza seguras para a Web. A razão por trás disso é porque precisamos isolar a paleta de escala de cinza segura na Web (por exemplo, 000000, 333333, 666666, 999999, CCCCCC e FFFFFF). Um algoritmo sobre o método colorimétrico de conversão em escala de cinza está disponível em: http://en.wikipedia.org/wiki/Grayscale#Colorimetric_.28luminance-preserving.29_conversion_to_grayscale , caso você queira usá-lo como inspiração.

Um seria renderizar a escala de cinza para as cores apropriadas. Para dividir rapidamente: 000000 se refere ao azul de Rubik, 333333 se refere ao vermelho de Rubik, 666666 se refere ao verde de Rubik, 999999 se refere ao laranja de Rubik, </font> se refere ao laranja de Rubik, </font> se refere ao amarelo de Rubik e FFFFFF se refere ao branco de Rubik.

Prefiro que o código resultante possa renderizar da paleta da foto diretamente para as cores de Rubik. O método de dois estágios, da conversão para escala de cinza segura na Web e, em seguida, para a paleta correspondente do Rubik é apenas para lhe dar uma idéia da lógica por trás do processo, mas se for mais fácil fazer isso, faça isso de qualquer maneira.

Os valores RGB reais da paleta do Rubik devem corresponder ao seguinte:

  • Vermelho: # C41E3A
  • Verde: # 009E60
  • Azul: # 0051BA
  • Laranja: # FF5800
  • Amarelo: # FFD500
  • Branco: #FFFFFF

Para dar um exemplo, recortei a cabeça de Abraham Lincoln da seguinte figura: insira a descrição da imagem aquie renderizei o algoritmo para produzir o seguinte:

insira a descrição da imagem aqui

A grade está lá para que você possa ver como cada cubo de Rubik em miniatura individual precisaria ser configurado para compor a imagem. O tamanho real da imagem resultante é de 45 por 45 pixels, significando (45/3) * (45/3) = 15 * 15 = 225 os cubos de Rubik em miniatura seriam usados ​​para fazer essa imagem. Não estou esperando que você apresente a imagem resultante com uma grade como eu.

Portanto, é isso que é necessário:

  1. A imagem a ser processada por esse algoritmo deve ter x pixels de largura por y pixels de altura, de modo que x e y sejam múltiplos de 3. Isso ajuda a facilitar a renderização como parte do mosaico de cubos de Rubik. Se sua imagem for muito grande, é aconselhável reduzi-la para algo em torno de 45 x 45 a 75 x 75 ou em dimensões anteriores ao processamento. Lembre-se de que esse componente de redimensionamento é OPCIONAL.

  2. A imagem precisa ser convertida na paleta de cubos do Rubik, com cores sextadas, para criar o mosaico.

  3. A imagem resultante precisa ser um arquivo gráfico válido após o processamento. Para provar que seu código funciona, execute-o contra a imagem de um dos presidentes dos Estados Unidos da América ou de uma celebridade conhecida de Hollywood. Eu já usei Abraham Lincoln no meu exemplo, então esse presidente não pode mais ser usado. Certifique-se de fornecer o idioma que você usou, a contagem de bytes e o presidente / celebridade usado para testar seu código, incluindo fotos antes e depois ...

  4. Cada entrada deve ter um presidente / celebridade exclusivo como seu caso de teste. Não aceitarei duplicatas. Isso garantirá que resultados duplicados não sejam usados ​​para testar entradas de código diferentes. É muito bom dizer que seu código funciona, é outra coisa para provar isso.

5. O código mais curto vence.

Estou mudando isso para um concurso de popularidade ... Prefiro ver quem pode fazer isso sem ter que competir com a contagem de bytes ... Portanto, atribuirei isso juntamente com uma recompensa após o dia 28 de fevereiro de 2014.

WallyWest
fonte
4
Eu acho que seria melhor se você adicionasse os valores RGB do Rubik à postagem em vez de confiar em um link.
SztupY
" A imagem a ser processada deve ter x pixels de largura por y pixels de altura" significa que o redimensionamento faz parte do código ou que a imagem é pré-processada no tamanho necessário?
user2846289
Existem estados impossíveis de um cubo de Rubik se você restringir apenas uma face?
Nick T
1
@WallyWest Você adoraria meu aplicativo MineCam, ele faz isso, mas, em vez de fazer quadrados, usa blocos de minas, e também o faz 15 vezes por segundo com a câmera do iPhone em tempo real, convertendo assim o mundo inteiro ao seu redor em um universo artesanal de minas. itunes.apple.com/us/app/minecam/id675845303?mt=8 (Se só ele pode também gerar uma semente para a referida hahahaha mundo)
Albert Renshaw
2
@WallyWest: não se trata de preguiça. O problema deve fornecer todas as informações necessárias para você começar, mesmo se o resto da Internet estiver inativo. Em um ano ou dois, esse link poderá ser desativado e ninguém atualizará o link. Se você fornecer informações suficientes sobre como criar cores em tons de cinza web-safe (que não é necessário para resolver o problema) você poderia acabou facilmente adicionados uma mesa pequena de mapeamento, como #000000 => #0051BA, etc.
SztupY

Respostas:

16

Imagemagick (108)

Versão: ImageMagick 6.8.7-7 Q16 x86_64 2013-11-27

A seguinte chamada:

$ 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

onde inpute outputprecisa ser modificado para o nome do arquivo de entrada e saída.

Eu contei apenas os caracteres entre -resizee #FFF", se você acha que isso é inválido, sinta-se à vontade para comentar.

Eu usei Lenna como imagem (ela apareceu em uma Playboy, e qualquer pessoa que faça isso deve ser considerada uma celebridade de Hollywood, certo?)

Entrada:

Imagem de entrada

Saída:

$ 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

Imagem gerada

Saída ampliada:

Imagem ampliada

Observações: de acordo com os documentos imagemagick, você não pode ter mais de um operador condicional em uma instrução, mas a chamada ainda parece funcionar bem; portanto, provavelmente isso foi corrigido e os documentos não foram atualizados.

A execução de identificação na imagem resultante (para mostrar as cores são realmente boas):

$ 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
  (...)

Se você acha que Lenna não conta como uma celebridade adequada, aqui está Bruce Willis:

Bruce Original

Bruce Small

Bruce Large

SztupY
fonte
+1 Acho que sua resposta é quase imbatível (ou mesmo imbatível). Vou apenas sugerir que você tire uma foto inquestionável de celebridade de Hollywood ou presidente americano e acrescente a isso (não precisa remover Lenna, mantenha as duas). Caso contrário, algumas pessoas chatas podem reclamar e votar apenas por isso.
Victor Stafusa 16/02
@ Victor: Eu acho que o Mathematica, o Matlab ou o Octave podem superar isso facilmente, pois as condições dentro da fxpeça podem ser compactadas ainda mais em uma linguagem com melhor expressividade. E essas línguas também têm suporte de imagem nativa (por isso não caracteres são perdidos por terem de importação imagemagick / gd / etc.)
SztupY
@SztupY eu sei de Lenna muito bem ... Vou contar isso ... Bom trabalho com Bruce Willis também ...
Wally West
1
Lenna é fofa (r). Acima.
blabla999
+1 para usar a ferramenta certa para o trabalho. No meu entender, a maneira correta de usar o imagemagick é chamar a imagem primeiro, e não as opções, que o arquivo de saída.
CousinCocaine
14

Mathematica

Trabalharemos com uma região quadrada de um selo americano com Greta Garbo. Será referido como 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]]

A função f usa 3 parâmetros:

  • i que se refere à imagem
  • rs, o tamanho da varredura
  • m, uma variável booleana que indica se as linhas Mesh devem ser usadas. (A configuração padrão é True).

Usando tamanhos de varredura de 15, 30, 45 e 75:

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

4 garbos

Não consigo imaginar alguém fazendo um cubo de Rubrik com tantas peças! Exercício interessante, no entanto.


Brincando com cores

Isto é de uma entrada anterior. O código é um pouco diferente. Graphicsé usado em vez de ArrayPlot. Além disso, usamos o carimbo completo, mesmo que não seja quadrado.

Existem 6! = 720 permutações das cores do cubo Rubrik.

A seguir, é exibida a imagem central da linha superior (defina 6 imagens abaixo). Quando os valores da escala de cinza são organizados do mais escuro para o mais claro, as cores são {r, gr, b, o, y, w}. Outras variações, no entanto, funcionam.

i é a imagem original em escala de cinza.

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 é a imagem original em escala de cinza do carimbo completo do Greta Garbo.

Rasterize[garbo,RasterSize->75 rasteriza a imagem em uma matriz de 75 por 75.

ColorQuantize[<>, 6] reduz os valores da escala de cinza para um conjunto de 6.

ImageDatarecupera a matriz de dados da imagem; vem de cabeça para baixo.

Reverse vira a matriz de dados, daí a imagem, com o lado direito para cima.

garboColors são os 6 valores da escala de cinza na imagem quantizada.

Graphics[Raster exibe a imagem final.

rubrikColors são valores RGB das 6 cores do cubo Rubrik.

São fornecidas várias permutações de cores de vermelho, verde, azul, laranja, amarelo e branco.

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

E o código:

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

Aqui estão 72 (das 720) imagens de Greta Garbo que usam as 6 cores do cubo Rubrik. Algumas imagens funcionam melhor que outras, você não acha?

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

garbos em abundância

DavidC
fonte
Greta, oh Greta ... Isso acabou melhor do que eu esperava. @DavidCarraher, bom trabalho aqui ...
WallyWest
@WallyWest. Obrigado. Foi um desafio muito interessante.
DavidC
Eu tinha tanta certeza de que o Mathematica venceria o imagemagick, isso não pode ser jogado ainda mais? Todas essas funções são necessárias?
SztupY
1
@SztupY Metade do código é dedicada a acertar as cores. Reversepoderia ser eliminado, deixando a foto de cabeça para baixo, mas não vejo outras oportunidades. O Mathematica é expressivo, mas usa grandes palavras. Alguém especialista em imagens provavelmente poderia reduzir um pouco o tamanho do código, mas duvido que eles pudessem superar o código da imagemagick.
DavidC
1
Havia de fato algumas inconsistências no código. Espero que agora eles se foram. isegure a imagem original. grsignifica verde de Rubrik. grefere-se aos dados de imagem rasterizada e quantizada para a imagem em escala de cinza.
21814
6

Smalltalk (Smalltalk / X), 289139 *

entrada: i; saída: 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)]

entrada:

insira a descrição da imagem aqui

saída:

insira a descrição da imagem aqui

ampliado:

insira a descrição da imagem aqui

(para todos os jovens: NÃO é Madonna ;-)

[*] Não contei a ampliação para 75x75 (a primeira linha) - poderia ter usado um já redimensionado como entrada. Espero que esteja tudo bem com você.

blabla999
fonte
I adore Marilyn Monroe ... Grande escolha ... redimensionamento foi um recurso opcional ...
Wally West
4

Cores Postscript e TRUE Rubik! ;-)

Bem, esta solução é um pouco fora de tópico aqui, pois está restrita a uma esfera altamente especializada. Mas depois de muita frustração com, por exemplo, "pergunta sobre números estranhos" (não conseguindo produzir algo que praticamente funcionasse), decidi publicar algo e, então, puxei isso para fora da minha pilha de rabiscos meio acabados e o tornei apresentável.

A solução explora o fato de que a 1ª revisão desta pergunta define as cores necessárias por link para um site, que afirma claramente que as cores Pantone (R) devem ser usadas e as cores RGB são apenas aproximações. Então pensei: por que eu faria aproximações quando posso fazer cores genuínas? - :)

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

Este código deve ser salvo como, por exemplo, rubik.pse depois alimentado no Ghostscript com encantamento usual:

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

Em seguida, ele espera na próxima linha, a entrada do nome do arquivo JPG, por exemplo

kelly.jpg

e, se tudo correr bem, salva a saída em out.psdarquivo.

A entrada deve ser quadrada RGB JPEG (qualquer tamanho), a saída é PSD com canais de cores exatas. Você precisará do Photoshop para visualizar o arquivo. Mudar o dispositivo GS de psdcmykpara qualquer outra coisa não produzirá nada utilizável. JPEG como entrada - porque o intérprete postscript pode decodificar diretamente o fluxo de dados. Forma quadrada - porque o programa depende sqrtdo comprimento da string para encontrar a largura (e a altura) da imagem.

As primeiras linhas definem o tamanho da imagem de saída (pode ser alterada a partir do padrão 75) e a paleta de cores (as cores e seus números também podem ser alterados). Qualquer outra coisa não é codificada, eu acho.

O que está acontecendo? O fluxo de trigêmeos RGB é convertido em tempo real para a sequência de valores em escala de cinza (com fórmula simples); o dicionário de imagens contone de 8 bits é criado e usado para pintar 5 imagens idênticas umas sobre as outras em 5 Separationespaços de cores. O truque é aplicar funções de transferência antes de cada chamada do imageoperador. Por exemplo, para tinta amarela, essa função retorna 0 para valores de entrada em 0,167 .. 0,333 apenas na faixa e 1 em caso contrário.

Entrada:

insira a descrição da imagem aqui

Captura de tela da saída 75x75 aberta no Photoshop, ampliada em 800%:

insira a descrição da imagem aqui

E paleta de canais do Photoshop:

insira a descrição da imagem aqui

user2846289
fonte
1
+1 para usar Grace Kelly ... você tem o meu total respeito ...
Wally West
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;
    }
}

Você precisa executá-lo com 3 parâmetros:

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

Onde 75está max. width / height, d:\test.jpgé um arquivo de entrada e d:\out.pngé o arquivo de saída.

Saída para várias imagens deste concurso:

WallyWest SztupY 1 SztupY 2 blabla999

Minha própria celebridade:

Garth!

Saída:

Garth 75 Garth 225

No entanto, outros tamanhos (maiores que 75 x 75) resultam em melhores imagens:

150 300

E, se ficarmos com os presidentes:

DubbaYa 294 DubbaYa 75 DubbaYa 225

Como esse não é um codegolf (mais?), Não me preocupei em "minimizar" o código demais. Além disso, como as instruções não mencionavam especificamente a imagem tinha que ter a mesma largura que a altura (quadrado) que não me incomodei com o corte; I fazer , no entanto, certifique-se a imagem é um múltiplo de 3 pixels de largura / altura. Se você deseja imagens quadradas, use as entradas quadradas : PFinalmente; o algoritmo está longe de ser o ideal.

Um pouco mais (já que as pessoas votaram mais nas gostosas / heróis da internet : P)

Kari Byron 300 Kari Byron 75 Kari Byron 225 The Hoff 300 The Hoff 75 The Hoff 225

RobIII
fonte
3

Brainfuck

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

Isso requer um interpretador / compilador BF que tenha -1 como EOF e que tenha células maiores que 8 bits SE um dos pixels vermelhos for 255. Caso contrário, ele será interrompido prematuramente, pois não poderá diferir entre EOF e o valor 0xFF . Com o jitbf, você tem o tamanho da máquina com tamanho inteiro e pode fazer isso para forçar -1 como EOF:

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

O formato do arquivo de imagem renderizado é o arquivo RGB PNM (P6) completo, como opção no Gimp.

Ele usa apenas o canal verde (que é uma das muitas maneiras de converter uma imagem colorida em escala de cinza). Reduz o valor em 43 sem reduzir o valor abaixo de zero para descobrir qual cor de rubiks usar e ter uma opção que imprime a cor RBG correta que corresponde.

Imagem de Angelina Jolie de Hackers (1995) reduzida para 75x75 e processada com o aplicativo:

Angelina Jolie 75x75 / Uso Justo Angelina Jolie 75x75 em cores do cubo de Rubiks / uso justo Mesma escala 6x

Mesmo, apenas usei o tamanho original :

O mesmo apenas não diminuído primeiro / uso justo

E, como sou psíquica, aqui também é presidente:

Arnold Schwarzenegger CC da Wikipedia

Sylwester
fonte
Off topic, mas hoje XKCD também tem referências à Hackers (1995)
Sylwester
1
Este também faz: xkcd.com/1247
Shade
1

Objetivo-C

Eu vi esse desafio ontem à noite e tive um tempo um pouco confuso -[NSArray indexOfObject:inSortedRange:options:usingComparator:], daí o atraso.

- (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)];
}

Eu o executei no meu iPad assim:

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

Antes Danny DeVito Antes Depois Danny DeVito Depois

Antes Grace Kelly Antes Depois Grace Kelly Depois

Max Chuquimia
fonte
1

Python

Formato python rubik.py <input> <max_cubes> <output>.

Abrange pixel em escala de cinza usando o algoritmo sugerido.

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])

Entrada:

Sandro Pertini
(fonte: ilmamilio.it )

Saída com max_cubes = 25:

Sandro Pertini, Rubik'd 1

Saída com max_cubes = 75:

Sandro Pertini, Rubik'd 2

Saída com max_cubes = 225:

Sandro Pertini, Rubik'd 3

Oberon
fonte
Não está faltando a cor branca? E o mais escuro deve ser azul, mas, como vejo agora, esse também é o problema de algumas outras imagens.
precisa saber é o seguinte
@VAdimiR Whoops! Os mapeou na ordem errada. Quanto ao branco não aparecer, é por causa da precisão do FP (1.055 - 0.055 = 0.9999999999999999). Acho que terei que codificar o branco, o que não é difícil, pois ele apareceria apenas com o valor original de #FFFFFF.
Oberon
Sobre o branco, minha opinião era que o intervalo de 0..1 (leveza) é dividido em 6 partes e qualquer coisa de 0,83 a 1,00 é mapeado para branco, caso contrário não haverá muito sentido em fotografar 6 cores do cubo , mas é assim que eu leio.
precisa saber é o seguinte
@Oberon Escolha interessante usando Pertini ... Ele quase viveu até os 94 anos ... E um ótimo trabalho usando Python, e tenho que admitir que não é uma das linguagens mais fáceis que já encontrei, tão bem feita!
precisa saber é o seguinte