Quixels - Quantum Pixels

35

10

Introduction

A quixel is a quantum pixel. Similar to a classical pixel, it is represented with 3 integer values (Red, Green, Blue). However, quixels are in a super position of these 3 states instead of a combination. This super position only lasts until the quixel is observed at which point it collapses to one of three classical pixels; RGB(255,0,0), RGB(0,255,0) and RGB(0,0,255).

Specification

  • Representation
    • Each quixel is represented as an array of 3 integers between 0 and 255, r, g and b respectively.
  • Super Positions
    • Each quixel is in a super position between the Red, Blue and Green states represented by R, G and B respectively.
  • Observation
    • When each quixel is observed it collapses into one of the three states. The probability of each classical state is R = (r + 1) / (r + g + b +3), G = (g + 1) / (r + g + b + 3) and B = (b + 1) / (r + g + b + 3). This way each classical state always as a non-zero probability of showing up.
  • Input
    • The function or program should take a image of quixels. How it does this is flexible. A filename, using a multi-dimensional array, etc are all acceptable.
  • Output
    • The function or program should produce an image of classical pixels. The data structure for this produced image is also flexible. Note that all of the pixels should be one of these three: RGB(255,0,0), RGB(0,255,0) and RGB(0,0,255)
    • The output should not be deterministic; these are quantum pixels! The same input should result in different outputs.
    • If your language has no way of generating a random number, you can take random bytes as input
  • Scoring

Images

Mona Lisa by Leonardo da Vinci Mona Lisa

Starry Night by Vincent van Gogh enter image description here

Persistence of Memory by Salvador Dali enter image description here

Teddy Roosevelt VS. Bigfoot by SharpWriter enter image description here

NonlinearFruit

Posted 2016-08-30T21:50:41.223

Reputation: 5 334

Can the image filename / URL be an input argument? – Luis Mendo – 2016-08-30T22:06:45.823

@LuisMendo Yes, you can read from a file (or URL) – NonlinearFruit – 2016-08-30T22:09:14.283

My question is, can the name of that file / URL be an input? As opposed to hard-coded. So it wouldn't be included in the byte count – Luis Mendo – 2016-08-30T22:12:28.383

@LuisMendo Sorry. Yes, that is what I meant – NonlinearFruit – 2016-08-30T22:35:26.287

2That JPEG image of the Mona Lisa is causing 16x16 prominent visual artefacts on the output images. – wizzwizz4 – 2016-08-31T08:14:41.437

Where the hell is Lena when you need her? – YSC – 2016-08-31T13:55:39.003

1@wizzwizz4 Actually it isn't. It is the downsized preview that has artefacts. Click an image to view it full-sized. I suspect it is the particular width of only that image that gives the effect. – Adám – 2016-08-31T14:43:14.187

@Adám Oh, my bad. Thanks for correcting me. – wizzwizz4 – 2016-08-31T15:54:37.057

2You'll get better (visual) results if your quantum space was RGBK, where K=255*3-R-G-B, then make your quantum pixels be any one of the 4. (If K is selected, display (0,0,0). Extend your RGB equations in the obvious way, changing 3s to 4s, adding K when you would add R+G+B, etc). A blur after doing this should reconstruct a pretty decent noisy copy of the original. (K stands for black or key, in case you wondered) – Yakk – 2016-08-31T19:18:23.900

If using a deterministic language (i.e. output = func(input)), is is alright if the input consists of the image followed by an infinite stream of random bytes? Some esolangs don't have a built-in RNG. Or are deterministic languages not allowed? – TLW – 2016-08-31T20:03:03.093

2@TLW If your language has no way of generating a random number, you can take random bytes as input – NonlinearFruit – 2016-09-01T02:17:05.443

@Yakk Have you tried it? Pure red (255,0,0) would give K=2×255, so a pure red picture would become two thirds black pixels and one third red. I.e. it would become very much darker. – Adám – 2016-09-01T23:39:13.150

@Adám You are right. The proper K is harder to calculate. Treating channels as values from 0 to 1 and ignoring the "+1 per channel" in the quantum equation as tiny, the average total pixel value ("brightness") after is (R^2 + B^2 + G^2)/(R+G+B), while before it was (R+G+B). To repair this we need to dim it by a factor of (R+G+B) / ( (R^2 + B^2 + G^2)/(R+G+B) ) = (R+G+B)^2/(R^2 + B^2 + G^2). Then scale that by (R+G+B). Sigh. – Yakk – 2016-09-02T00:51:17.173

Answers

13

Dyalog APL, 23 21 19 bytes

Takes table of (R, G, B) triplets.

Inspired by miles' algorithm

Returns table of indices into {(255, 0, 0), (0, 255, 0), (0, 0, 255)}. Horribly wasteful.

(?∘≢⊃⊢)¨(⊂⍳3)/¨⍨1+⊢

(
?∘≢ random index
selects
from
each of

(
the entire
⍳3 first three indices
)/¨⍨ replicated by each of

1+⊢ the incremented triplets

TryAPL!


Old version

Returns table of 0-based indices into {(255, 0, 0), (0, 255, 0), (0, 0, 255)}

{+/(?0)≥+\(1+⍵)÷3++/⍵}¨

{...}¨ for each quixel in the table, find the:

+/ the sum of (i.e. count of truths of)

(?0)≥ a random 0 < number < 1 being greater than or equal to

+\ the cumulative sum of

(1+⍵)÷ the incremented RGB values divided by

3+ three plus

+/⍵ the sum of the quixel

Note: Dyalog APL lets you chose between the Lehmer linear congruential generator, the Mersenne Twister, and the Operating System's RNG¹ ².

For example, the image:

┌──────────┬──────────┬───────────┬───────────┬─────────┐
│52 241 198│148 111 45│197 165 180│9 137 120  │46 62 75 │
├──────────┼──────────┼───────────┼───────────┼─────────┤
│81 218 104│0 0 255   │0 255 0    │181 202 116│122 89 76│
├──────────┼──────────┼───────────┼───────────┼─────────┤
│181 61 34 │84 7 27   │233 220 249│39 184 160 │255 0 0  │
└──────────┴──────────┴───────────┴───────────┴─────────┘

can give

┌─┬─┬─┬─┬─┐
│1│0│2│2│1│
├─┼─┼─┼─┼─┤
│2│2│1│1│2│
├─┼─┼─┼─┼─┤
│0│2│1│2│0│
└─┴─┴─┴─┴─┘

Notice how the three "pure" quixels collapsed to their respective colors.

TryAPL online!

Collapsed Mona Lisa

Adám

Posted 2016-08-30T21:50:41.223

Reputation: 37 779

8

Mathematica, 53 bytes

RandomChoice[255#+1->IdentityMatrix@3]&~ImageApply~#&

Anonymous function. Takes a Mathematica Image as input and returns an Image as output. Note that the input image must have an RGB color space.

LegionMammal978

Posted 2016-08-30T21:50:41.223

Reputation: 15 731

How does it work? – GreenAsJade – 2016-08-31T11:12:27.120

2@GreenAsJade <...>~ImageApply~# applies a function over all pixels in the image, and RandomChoice[255#+1->IdentityMatrix@3] uses some weighted RNG to produce a row of the 3×3 identity matrix (i.e. {1, 0, 0}, {0, 1, 0}, or {0, 0, 1}) which corresponds to red, green, or blue. – LegionMammal978 – 2016-08-31T11:33:47.740

5

C#, 366 243 bytes

Huge thanks to @TheLethalCoder for golfing this!

var r=new Random();c=>{double t=c.R+c.G+c.B+3,x=(c.R+1)/t,d=r.NextDouble();return d<=x?Color.Red:d<=x+(c.G+1)/t?Color.Lime:Color.Blue;};b=>{fo‌​r(int x=0,y;x<b.Width;x++)for(y=0;y<b.Height;y++)b.SetPixel(x,y,g(‌​b.GetPixel(x,y)));re‌​turn b;};

Basic idea:

using System;
using System.Drawing;
static Random r = new Random();

static Image f(Bitmap a) {
    for (int x = 0; x < a.Width; x++) {
        for (int y = 0; y < a.Height; y++) {
            a.SetPixel(x, y, g(a.GetPixel(x, y)));
        }
    }
    return a;
}

static Color g(Color c) {
    int a = c.R;
    int g = c.G;
    double t = a + g + c.B + 3;
    var x = (a + 1) / t;
    var y = x + (g + 1) / t;
    var d = r.NextDouble();
    return d <= x ? Color.Red : d <= y ? Color.Lime : Color.Blue;
}

Examples:

Mona Lisa

enter image description here

Starry Night

enter image description here

Persistence of Memory

enter image description here

Teddy Roosevelt VS. Bigfoot

enter image description here

Here's an updated imgur album with a few more examples, to show that this is nondeterministic.

ThreeFx

Posted 2016-08-30T21:50:41.223

Reputation: 1 435

6

Color.Lime is the pure green color. For future reference, here's the known color table.

– milk – 2016-08-30T23:15:55.250

1Heres a golfed version for 237 bytes: var r=new Random();c=>{double t=c.R+c.G+c.B+3,x=(c.R+1)/t,d=r.NextDouble();return d<=x?Color.Red:d<=x+(c.G+1)/t?Color.Lime:Color.Blue;};b=>{for(int x=0,y;x<b.Width;x++)for(y=0;y<b.Height;y++)b.SetPixel(x,y,g(b.GetPixel(x,y)));return b;}; And there are still improvements that can be made – TheLethalCoder – 2016-08-31T11:27:26.537

Its actually 237 bytes the extra bytes are invisible characters that are added in the code comment I believe – TheLethalCoder – 2016-09-01T07:56:24.637

4

Python 2, 172 166 162 bytes

The second and third indent levels are a raw tab and a raw tab plus a space, respectively; this plays really badly with Markdown, so the tabs have been replaced by two spaces.

from random import*
i=input()
E=enumerate
for a,y in E(i):
 for b,x in E(y):
  t=sum(x)+3.;n=random()
  for j,u in E(x):
   n-=-~u/t
   if n<0:i[a][b]=j;break
print i

Uses a similar input/output format to Adám's APL answer. Input is a 2D array of RGB tuples; output is a 2D array of 0, 1, or 2, representing red, green, and blue respectively. For example:

$ echo "[[(181,61,34),(39,184,160),(255,0,0)],[(84,7,27),(123,97,5),(12,24,88)]]" | python quixel.py
[[2, 2, 0], [0, 0, 0]]

Below is my older Python 3 answer using PIL.

Python 3 + PIL, 271 250 245 243 bytes

import random as a,PIL.Image as q
i=q.open(input())
w,h=i.size
for k in range(w*h):
 m=k//h,k%h;c=i.getpixel(m);t=sum(c)+3;n=a.random()
 for j,u in enumerate(c):
  n-=-~u/t
  if n<0:z=[0]*3;z[j]=255;i.putpixel(m,tuple(z));break
i.save('o.png')

Iterates over every pixel and applies the quixel function to it. Takes the filename as input and saves its output in o.png.

Here are some results:

$ echo mona-lisa.jpg | python quixel.py

Mona Lisa, quixelized

$ echo starry-night.jpg | python quixel.py

Starry Night, quixelized

$ echo persistence-of-memory.jpg | python quixel.py

Persistence of Memory, quixelized

$ echo roosevelt-vs-bigfoot.jpg | python quixel.py

Teddy Roosevelt vs Bigfoot, quixelized

Copper

Posted 2016-08-30T21:50:41.223

Reputation: 3 684

@Doddy Probably because it's a PRNG and not a cryptographically secure RNG. – someonewithpc – 2016-08-31T09:32:39.803

@someonewithpc Oh actually, I wrote that question when viewing on my phone, where the last image has a regular grid-like pattern on it, but now, viewing on a computer, it is the first image with this effect. – Doddy – 2016-08-31T09:37:45.283

@Doddy Oh, yeah! Try pressing on the image on your phone: the effects will toggle! I guess it is about image sampling... – someonewithpc – 2016-08-31T09:40:59.960

@Doddy Maybe delete your first question, so we don't think you're asking about the dense flag red stripes... – GreenAsJade – 2016-08-31T11:17:16.390

4

J, 20 18 17 bytes

(>:({~?@#)@##\)"1

The image is input as an array with dimensions h x w x 3 representing the RGB values as integers in the range 0 - 255. The output is a table with dimensions h x w where 1 is an rgb value of (255, 0, 0), 2 is (0, 255, 0), and 3 is (0, 0, 255).

Explanation

The ()"1 represents that this verb is to be applied to each array of rank 1 in the input, meaning that it will apply to each pixel.

>:({~?@#)@##\  Input: array [R G B]
>:             Increment each, gets [R+1, G+1, B+1]
           #\  Gets the length of each prefix of [R G B], forms [1 2 3]
          #    Make a new array with R+1 copies of 1, G+1 copies of 2,
               and B+1 copies of 3
  (     )@     Operate on that array
       #         Get the length of the array of copies, will be R+G+B+3
     ?@          Generate a random integer in the range [0, R+G+B+3)
   {~            Select the value at that index from the array of copies and return

Example

miles

Posted 2016-08-30T21:50:41.223

Reputation: 15 654

1Your Mona Lisa has a different colour scheme to the others. Are you sure it works right? – wizzwizz4 – 2016-08-31T08:16:20.453

@wizzwizz4 Thanks, when displaying the image, I had the rgb pixels in reverse order. – miles – 2016-08-31T09:29:05.603

4

R, 58 bytes

mapply(function(r,g,b)rmultinom(1,1,c(r+1,g+1,b+1)),r,g,b)

Input consists of three numeric vectors held in r, g and b respectively.

We don't need to normalise the probabilities to sum to one, that happens automatically in rmultinom.

Output is of the form

     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,]    0    0    0    0    0    0    0    0    0     0
[2,]    0    0    0    1    0    0    1    1    1     0
[3,]    1    1    1    0    1    1    0    0    0     1

Where there is a single 1 in each column. The 1 is in the first row for "R" pixels, the second row for "G" and the third row for "B".

JDL

Posted 2016-08-30T21:50:41.223

Reputation: 1 135

4

Jelly, 8 7 bytes

Jx‘Xµ€€

The input is a 3d list with dimensions h x w x 3. The output is a 2d list with dimensions h x w where 1 represents the rgb value (255, 0, 0), 2 is (0, 255, 0), and 3 is (0, 0, 255).

The sample input below is the top-left 4 x 4 region of the Mona Lisa image.

Try it online!

Explanation

Jx‘Xµ€€  Input: The 3d list of rgb pixels
    µ    Begin a monadic chain (Will operate on each pixel, input: [R, G, B])
J          Enumerate indices to get [1, 2, 3]
  ‘        Increment each to get [R+1, G+1, B+1]
 x         Make R+1 copies of 1, G+1 copies of 2, B+1 copies of 3
   X       Select a random value from that list of copies and return
     €€  Apply that monadic chain for each list inside each list

miles

Posted 2016-08-30T21:50:41.223

Reputation: 15 654

4

Pyth - 11 10 bytes

Takes RGB 2d bitmap and outputs bitmap with indexed 3-bit color.

mLOs.emkbk

That level of nesting is hurting my head.

Try it online here.

Maltysen

Posted 2016-08-30T21:50:41.223

Reputation: 25 023

3

Python 3, 119 bytes

Where m is the input taken as a 2-d array of pixels where each pixel is a list of the form [r,g,b]. At each pixel's position, returns 0,1,2 to represent (250,0,0), (0,250,0), and (0,0,250) respectively.

import random
lambda m:[map(lambda x:x.index(sum((((i+1)*[i])for i in x),[])[random.randint(0,sum(x)+2)]),i)for i in m]

gowrath

Posted 2016-08-30T21:50:41.223

Reputation: 885

I don't believe you are allowed to take input as a variable (when writing a full program in a language that supports normal IO). I think you have to use input or make this a function and take m as a parameter. – NonlinearFruit – 2016-09-04T02:18:10.897