Cubify esto! Una lección de escala de grises ... er ... color ... er ... lo que sea

27

Siendo un gran admirador del cubo de Rubik y del arte genial, he estado trabajando en combinar los dos para hacer algunas cosas realmente geniales. Básicamente resolviendo cubos de Rubik en miniatura para formar píxeles rudimentarios en la formación del arte del cubo de Rubik. Se pueden ver ejemplos de este tipo de arte a través de este enlace: http://google.com/search?q=rubik%27s+cube+art

Ahora, el propósito de este Code Golf es crear código que acepte una imagen como entrada y luego la convierta de la siguiente manera:

La imagen se reduce inicialmente a colores de escala de grises seguros para la web. La razón detrás de esto es porque necesitamos aislar la paleta de escala de grises segura para la web (es decir, 000000, 333333, 666666, 999999, CCCCCC y FFFFFF). Un algoritmo sobre el método colorimétrico de conversión a escala de grises está disponible en: http://en.wikipedia.org/wiki/Grayscale#Colorimetric_.28luminance-preserving.29_conversion_to_grayscale , si desea utilizar eso como inspiración.

Entonces se representaría la escala de grises a los colores apropiados. Para descomponerlo rápidamente: 000000 se referirá al azul de Rubik, 333333 se referirá al rojo de Rubik, 666666 se referirá al verde de Rubik, 999999 se referirá al naranja de Rubik, CCCCCC se referirá al amarillo de Rubik y FFFFFF se referirá al blanco de Rubik.

Prefiero que el código resultante se pueda procesar desde la paleta de fotos directamente a los colores de Rubik. El método de dos etapas, desde la conversión a escala de grises segura para la web y luego a la paleta de Rubik correspondiente, es solo para darle una idea sobre la lógica detrás del proceso, pero si es más fácil para usted hacerlo, hágalo de todos modos.

Los valores RGB reales para la paleta de Rubik deben corresponder a lo siguiente:

  • Rojo: # C41E3A
  • Verde: # 009E60
  • Azul: # 0051BA
  • Naranja: # FF5800
  • Amarillo: # FFD500
  • Blanco: #FFFFFF

Para darle un ejemplo, recorté la cabeza de Abraham Lincoln de la siguiente imagen: ingrese la descripción de la imagen aquíy rendericé el algoritmo para producir lo siguiente:

ingrese la descripción de la imagen aquí

La cuadrícula está allí para que pueda ver cómo cada cubo individual de Rubik en miniatura tendría que configurarse para formar la imagen. El tamaño real de la imagen resultante es de 45 píxeles por 45 píxeles, lo que significa que (45/3) * (45/3) = 15 * 15 = 225 cubos de Rubik en miniatura se utilizarían para hacer esta imagen. No espero que presente la imagen resultante con una cuadrícula como yo.

Entonces esto es lo que se requiere:

  1. La imagen a ser procesada por este algoritmo debe tener x píxeles de ancho por y píxeles de alto, de modo que x e y sean múltiplos de 3. Esto es para ayudar con la facilidad de renderizado como parte de un mosaico de cubos de Rubik. Si su imagen es bastante grande, se recomienda reducirla a alrededor de 45 x 45 a 75 x 75 o más o menos en dimensiones antes del procesamiento. Tenga en cuenta que este componente de cambio de tamaño es OPCIONAL.

  2. La imagen debe convertirse a la paleta de cubos de Rubik sextacolored para crear el mosaico.

  3. La imagen resultante debe ser un archivo gráfico válido después del procesamiento. Para probar que su código funciona, ejecútelo contra una imagen de uno de los presidentes de los Estados Unidos de América o una conocida celebridad de Hollywood. Ya he usado a Abraham Lincoln en mi ejemplo, por lo que este presidente ya no puede ser usado. Asegúrese de proporcionar el idioma que ha utilizado, el recuento de bytes y el presidente / celebridad utilizado para probar su código, incluso antes y después de los disparos ...

  4. Cada entrada debe tener un presidente / celebridad único como su caso de prueba. No aceptaré duplicados. Esto asegurará que los resultados duplicados no se usen para probar diferentes entradas de código. Está muy bien decir que su código funciona, otra cosa es probarlo.

5. El código más corto gana.

Estoy cambiando esto a un concurso de popularidad ... Prefiero ver quién puede hacer esto sin tener que competir en el conteo de bytes ... Así que otorgaré esto junto con una recompensa después del 28 de febrero de 2014.

WallyWest
fuente
44
Creo que sería mejor si agregaras los valores Rubik RGB a la publicación en lugar de depender de un enlace.
SztupY
¿ "La imagen a procesar debe tener x píxeles de ancho por y píxeles de alto" significa que el cambio de tamaño es parte del código o que la imagen se procesa previamente al tamaño requerido?
user2846289
¿Hay estados imposibles de un cubo de Rubik si solo restringe una cara?
Nick T
1
@WallyWest Te ENCANTARÍA mi aplicación MineCam, hace esto, pero en lugar de hacer cuadrados, usa bloques de minería, y también lo hace 15 veces por segundo con la cámara del iPhone en tiempo real, convirtiendo así todo el mundo a tu alrededor en un universo de artesanía mía. itunes.apple.com/us/app/minecam/id675845303?mt=8 (Si solo pudiera generar una semilla para dicho mundo jajajaja)
Albert Renshaw
2
@WallyWest: no se trata de pereza. El problema debería proporcionarle toda la información que necesita para comenzar, incluso si el resto de Internet no funciona. En un año o dos, ese enlace podría desactivarse y nadie lo actualizará. Si usted proporciona suficiente información acerca de cómo crear colores en escala de grises con Web (que no es necesario resolver el problema) que podría haber acaba de agregar fácilmente una pequeña tabla de asignación, como #000000 => #0051BA, etc
SztupY

Respuestas:

16

Imagemagick (108)

Versión: ImageMagick 6.8.7-7 Q16 x86_64 2013-11-27

La siguiente llamada:

$ 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

donde inputy outputtienen que modificarse para el nombre de archivo de entrada y salida.

Solo conté los caracteres entre -resizey #FFF", si crees que esto no es válido, no dudes en comentar.

Usé a Lenna como imagen (apareció en un Playboy, y cualquiera que lo haga debería considerarse una celebridad de Hollywood, ¿verdad?)

Entrada:

Imagen de entrada

Salida:

$ 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

Imagen generada

Salida ampliada:

Imagen ampliada

Notas: de acuerdo con los documentos de imagemagick, no puede tener más de un operador condicional en una declaración, pero la llamada todavía parece funcionar bien, por lo que probablemente esto se solucionó y los documentos simplemente no se actualizaron.

Ejecutar Identificar en la imagen del resultado (para mostrar que los colores están bien):

$ 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 crees que Lenna no cuenta como una celebridad adecuada, aquí está Bruce Willis:

Bruce Original

Bruce Small

Bruce grande

SztupY
fuente
+1 Creo que tu respuesta es casi inmejorable (o incluso imbatible). Solo sugeriré que tome una foto incuestionable de una celebridad de Hollywood o un presidente estadounidense y agregue a esto (no es necesario que elimine a Lenna, conserve ambas). De lo contrario, algunas personas aburridas podrían quejarse y rechazar solo por eso.
Victor Stafusa
@Victor: Creo que Mathematica, Matlab u Octave podrían superar esto fácilmente, ya que las condiciones dentro de la fxpieza pueden comprimirse aún más en un lenguaje que tenga una mejor expresividad. Y esos idiomas también tienen soporte de imagen nativa (por lo que no se pierden caracteres al tener que importar imagemagick / gd / etc.)
SztupY
@SztupY Sé muy bien de Lenna ... Lo contaré ... Buen trabajo con Bruce Willis también ...
WallyWest
1
Lenna es linda (r). Arriba.
blabla999
+1 por usar la herramienta adecuada para el trabajo. Según tengo entendido, la forma correcta de usar imagemagick es llamar primero a la imagen, que a las opciones, que al archivo de salida.
CousinCocaine
14

Mathematica

Trabajaremos con una región cuadrada de un sello estadounidense con 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]]

La función f toma 3 parámetros:

  • i que se refiere a la imagen
  • rs, el tamaño de la trama
  • m, una variable booleana que indica si se deben usar líneas de malla. (La configuración predeterminada es True).

Usando tamaños de trama de 15, 30, 45 y 75:

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

4 garbos

¡No puedo imaginar a nadie haciendo un cubo de Rubrik con tantas piezas! Interesante ejercicio, no obstante.


Jugando con colores

Esto es de una entrada anterior. El código es ligeramente diferente. Graphicsse usa en lugar de ArrayPlot. Además, utilizamos el sello completo aunque no sea cuadrado.

Hay 6! = 720 permutaciones de los colores del cubo Rubrik.

A continuación se muestra la imagen central de la fila superior (establezca 6 imágenes a continuación). Cuando los valores de escala de grises se ordenan del más oscuro al más claro, los colores son {r, gr, b, o, y, w}. Sin embargo, otras variaciones funcionan.

i es la imagen original en escala de grises.

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 es la imagen original en escala de grises del sello completo de Greta Garbo.

Rasterize[garbo,RasterSize->75 rasteriza la imagen en una matriz de 75 por 75.

ColorQuantize[<>, 6] reduce los valores de escala de grises a un conjunto de 6.

ImageDatarecupera la matriz de datos de la imagen; Viene al revés.

Reverse voltea la matriz de datos, de ahí la imagen, con el lado derecho hacia arriba.

garboColors son los 6 valores de escala de grises en la imagen cuantificada.

Graphics[Raster Muestra la imagen final.

rubrikColors son valores RGB de los 6 colores del cubo Rubrik.

Se dan varias permutaciones de color rojo, verde, azul, naranja, amarillo y blanco.

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

Y el codigo:

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 en abundancia

Aquí hay 72 (de las 720) imágenes de Greta Garbo que usan los 6 colores del cubo Rubrik. Algunas imágenes funcionan mejor que otras, ¿no te parece?

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

garbos en abundancia

DavidC
fuente
Greta, oh Greta ... Esto resultó mejor de lo que esperaba. @DavidCarraher, buen trabajo aquí ...
WallyWest
@WallyWest. Gracias. Fue un desafío muy interesante.
DavidC
Estaba tan seguro de que Mathematica superaría a imagemagick, ¿no se puede jugar aún más? ¿Se requieren todas esas funciones?
SztupY
1
@SztupY La mitad del código está dedicado a obtener los colores correctos. Reversepodría eliminarse, dejando la imagen al revés, pero no veo ninguna otra oportunidad. Mathematica es expresivo pero usa palabras grandes. Alguien experto en imágenes probablemente podría reducir un poco el tamaño del código, pero dudo que pueda superar su código de imagen mágica.
DavidC
1
De hecho, hubo algunas inconsistencias en el código. Espero que ahora se hayan ido. iSostenga la imagen original. grrepresenta el verde de Rubrik. gse refiere a los datos de imagen rasterizada y cuantificada para la imagen en escala de grises.
DavidC
6

Smalltalk (Smalltalk / X), 289 139 *

entrada: i; salida: 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:

ingrese la descripción de la imagen aquí

salida:

ingrese la descripción de la imagen aquí

engrandecido:

ingrese la descripción de la imagen aquí

(para todos los jóvenes: esto NO es Madonna ;-)

[*] No he contado el aumento a 75x75 (la primera línea), podría haber usado un tamaño ya modificado como entrada. Espero que estés bien contigo.

blabla999
fuente
Adoro a Marilyn Monroe ... Gran elección ... Cambiar el tamaño era una característica opcional ...
WallyWest
4

¡Postdata y colores VERDADEROS de Rubik! ;-)

Bueno, esta solución es un poco fuera de tema aquí, ya que está restringida a una esfera altamente especializada. Pero después de mucha frustración con, por ejemplo, la "pregunta de números raros" (al no poder producir algo que funcionara prácticamente) decidí publicar algo y así saqué esto de mi montón de garabatos a medio terminar y lo hice presentable.

La solución explota el hecho de que la primera revisión de esta pregunta define los colores requeridos por enlace a un sitio, que establece claramente que los colores Pantone (R) deben usarse, y los colores RGB son solo aproximaciones. Entonces pensé, ¿por qué haría aproximaciones, cuando puedo hacer un color genuino? - :)

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 se guardará como, por ejemplo, rubik.psy luego se enviará a Ghostscript con el encantamiento habitual:

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

Luego lo espera en la siguiente línea, para ingresar el nombre del archivo JPG, por ejemplo

kelly.jpg

y, si todo va bien, guarda la salida en el out.psdarchivo.

La entrada debe ser RGB JPEG cuadrada (cualquier tamaño), la salida es PSD con canales de color directo. Necesitará Photoshop para ver el archivo. Cambiar el dispositivo GS de psdcmykotra cosa no producirá nada utilizable. JPEG como entrada, porque el intérprete PostScript puede decodificar el flujo de datos directamente. Forma cuadrada: porque el programa se basa en la sqrtlongitud de la cadena para encontrar el ancho (y la altura) de la imagen.

Las primeras líneas definen el tamaño de la imagen de salida (se puede cambiar del valor predeterminado 75) y la paleta de colores (los colores y su número también se pueden cambiar). Cualquier otra cosa no está codificada, creo.

¿Que esta pasando? La secuencia de tripletes RGB se convierte sobre la marcha en la cadena de valores de escala de grises (con fórmula simple), se construye un diccionario de imágenes de tonos continuos de 8 bits y se usa para pintar 5 imágenes idénticas una encima de la otra en 5 Separationespacios de color. El truco consiste en aplicar funciones de transferencia antes de cada invocación del imageoperador. Por ejemplo, para pintura amarilla, esta función devuelve 0 para valores de entrada en 0.167 .. 0.333 solo rango, y 1 en caso contrario.

Entrada:

ingrese la descripción de la imagen aquí

Captura de pantalla de salida 75x75 abierta en Photoshop, ampliada 800%:

ingrese la descripción de la imagen aquí

Y paleta de canales de Photoshop:

ingrese la descripción de la imagen aquí

usuario2846289
fuente
1
+1 por usar Grace Kelly ... tienes mi respeto total ...
WallyWest
3

DO#

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

Necesita ejecutarlo con 3 parámetros:

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

Donde 75es max. ancho / alto, d:\test.jpges el archivo de entrada y d:\out.pnges el archivo de salida.

Salida para varias imágenes en este concurso:

WallyWest SztupY 1 SztupY 2 blabla999

Mi propia celebridad:

Garth!

Salida:

Garth 75 Garth 225

Sin embargo, otros tamaños (mayores de 75x75) resultan en mejores imágenes:

150 300

Y, si nos quedamos con los presidentes:

DubbaYa 294 DubbaYa 75 DubbaYa 225

Como este no es un codegolf (¿ya no?), No me molesté en "minimizar" demasiado el código. Además, como las instrucciones no mencionaban específicamente que la imagen tenía que tener el mismo ancho que la altura (cuadrado), no me molesté en recortar; Yo hago , sin embargo, asegúrese de que la imagen es un múltiplo de 3 píxeles de ancho / alto. Si desea imágenes cuadradas, use entradas cuadradas :PAGSFinalmente; El algoritmo está lejos de ser óptimo.

Unos cuantos más (ya que las personas votan más por chicas calientes / héroes de Internet más :PAGS)

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

RobIII
fuente
3

Brainfuck

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

Esto requiere un intérprete / compilador BF que tenga -1 como EOF y que tenga celdas superiores a 8 bits SI uno de los píxeles rojos es 255. De lo contrario, se detendrá prematuramente ya que no podrá diferir entre EOF y el valor 0xFF . Con jitbf tiene lo que la máquina tiene como tamaño entero y puede hacer esto para forzar -1 como EOF:

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

El formato de archivo de imagen representado es el archivo RGB PNM completo (P6), sin formato como opción en Gimp.

Utiliza solo el canal verde (que es una de las muchas formas de convertir una imagen en color a escala de grises). Reduce el valor en 43 sin reducir el valor por debajo de cero para averiguar qué color de rubik usar y tiene un interruptor que imprime el color RBG correcto que corresponde.

Imagen de Angelina Jolie de Hackers (1995) reducida a 75x75 y procesada con la aplicación:

Angelina Jolie 75x75 / Uso justo Angelina Jolie 75x75 en colores cubo Rubik / Uso justo Misma escala 6x

Igual, solo usé el tamaño original :

Lo mismo no se redujo primero / Uso justo

Y como soy psíquico, aquí también hay un presidente:

Arnold Schwarzenegger CC de Wikipedia

Sylwester
fuente
Fuera de tema, pero xkcd de hoy también tiene referencias a Hackers (1995)
Sylwester
1
Este también lo hace: xkcd.com/1247
Sombra
1

C objetivo

Anoche vi este desafío y tuve un momento un tanto confuso -[NSArray indexOfObject:inSortedRange:options:usingComparator:], de ahí el retraso.

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

Lo ejecuté en mi iPad así:

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

Antes Danny DeVito Antes después Danny DeVito Después

Antes Grace Kelly Antes después Grace Kelly después

Max Chuquimia
fuente
1

Pitón

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

Convierte píxeles a escala de grises utilizando el 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
(fuente: ilmamilio.it )

Salida con max_cubes = 25:

Sandro Pertini, Rubik'd 1

Salida con max_cubes = 75:

Sandro Pertini, Rubik'd 2

Salida con max_cubes = 225:

Sandro Pertini, Rubik'd 3

Oberon
fuente
¿No falta el color blanco? Y el más oscuro debería ser azul, pero, como veo ahora, ese es el problema con algunas otras imágenes también.
user2846289
@VAdimiR ¡Vaya! Los mapeó en el orden incorrecto. En cuanto al blanco que no aparece, se debe a la precisión de FP (1.055 - 0.055 = 0.9999999999999999). Creo que tendré que codificar el blanco, lo cual no es difícil, ya que de todos modos solo aparecería con un valor original de #FFFFFF.
Oberon
Sobre el blanco, mi opinión fue que el rango 0..1 (luminosidad) se divide en 6 partes, y que nada 0.83..1.00 se asigna al blanco, o de lo contrario no tendrá mucho sentido hacer una imagen de 6 colores del cubo , pero así es como lo leo.
user2846289
@Oberon Interesante elección usando Pertini ... Casi vivió hasta los 94 años ... Y un gran trabajo usando Python, y debo admitir que no es uno de los idiomas más fáciles que he encontrado, ¡muy bien hecho!
WallyWest