All 16,777,216 RGB colours (2005)
davidnaylor.org
davidnaylor.org
If you zoom in further, you'd soon realize your screen is nothing but pure red, green and blue subpixels at varying intensities.
Because RGB is not a perceptual color space.
With RGB, a lot of values are wasted encoding colors that are perceptually very similar. Many colors that are “interesting” to humans are encoded in a narrow slice of the RGB cube. Much of the cube is a deep ocean of indistinguishable bluish shades.
Video traditionally uses various luminance+chroma color spaces, which are more perpetually effective than RGB and allow for easy subsampling to save bandwidth on the less important color data.
I want to do a kind of bubble sort on the pixels and see what it looks like.
To be specific, let's say we take two pixels at random and compare each to their 8 neighbors. If they are closer to the surrounding pixels when swapped, then swap them. Repeat.
I may try this, but I'm lazy, so in case someone else wants to...
That said, I bet there's some other criterion that would have the desired effect.
It'd also take a ridiculous number of iterations to really notice the noise being added. Perhaps unfeasibly many if you're wanting to go deep and truly rely on random comparisons.
Each of those smaller squares is made by having red at 0 and blue at 0 at the top left corner, then increasing each along one of the x/y axes until you have red 255 and blue 255 at the bottom right corner. The "green" value is constant for each square, and just increases by one for each subsequent square packed in. At distant/normal viewing you're not going to resolve all those individual colors but more see the averages (to say nothing of the computer itself averaging things to make a zoomed out view or a smaller-dimension rendering).
So you basically have subsquares that start, on average, as "purple" (or let's say magenta). They have no or very little green and mostly are mixtures of red and blue. As you go toward the bottom, green increasingly dominates as what were once the darkest parts of each sub-square become just green and what were the magenta parts tend toward white. Blur your vision a little and the image just looks like a magenta-to-green gradient.
You would be able to construct this image so it would still contain "all the RGB colors" but looked from afar instead like "yellow and blue squares" or "cyan and red squares" instead, just by changing your method for constructing/organizing it. There'll be variation in how well these different variants "blend" and so on just based on how we perceive the different colors, of course.
In terms of that perceptual variation, take for example this: https://allrgb.com/thingy , in particular the little preview in the left. This is what would be the "yellow to blue" kind of ordering, but it doesn't really "blend" as much. The bottom subsquares in particular read as "cyan/magenta/blue" combinations rather than just "blue", and in the top "yellow" isn't really as dominant either. Blur your vision again though and it's a yellow-to-blue gradient.
If you just think about it as a cube of colour with redness (0-255) on one axis, same with green and blue on the others and then taking 256 slices of that cube it all makes sense intuitively.
Color selector where you pick the color from the randomized image with an eyedropper tool.
The colors are all in there, what's there to complain about?
Lots of interesting imagery, with source included.
My background, I took a bit of liberty with the colors: https://imgur.com/a/OFcsjZn
And an animated version: https://youtu.be/mO7VuqLNK1w
Fun use case to play around with Octrees to try and speed it all up.
JPEG uses a very different technology; it breaks the image into 8x8 blocks, and tries to fit the resulting 64 pixels to a gradient (yes, I know I'm simplifying). So pixels that tend to be "smooth" and "gradient-like" will compress much better than random noise.
I feel it's very much spot on, and true to the math within.
I'll see if I can come up with a clever way do it without having to resort to tricks that move the goalposts (such as having repeated colors).
Okay I think I got pretty close. The png export doesn't have 16.7 million colors, so there must be some error in my logic.
1370 bytes as a human readable plaintext file.
711 bytes as a 7-zip.
658 bytes as a usable compressed svgz file.
159936 bytes as a png.
<?xml version="1.0" encoding="UTF-8"?>
<svg width="256" height="65536" version="1.1" viewBox="0 0 256 65536" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<defs>
<linearGradient id="a" x2="256" y1="32768" y2="32768" gradientUnits="userSpaceOnUse">
<stop stop-color="#f00" offset="0"/>
<stop stop-color="#ff0" offset=".166666667"/>
<stop stop-color="#0f0" offset=".333333333"/>
<stop stop-color="#0ff" offset=".5"/>
<stop stop-color="#00f" offset=".666666667"/>
<stop stop-color="#f0f" offset=".833333333"/>
<stop stop-color="#f00" offset="1"/>
</linearGradient>
<linearGradient id="b" x1="128" x2="128" y1="0" y2="65536" gradientUnits="userSpaceOnUse">
<stop offset="0"/>
<stop stop-color="#808080" stop-opacity="0" offset=".5"/>
<stop stop-color="#fff" offset="1"/>
</linearGradient>
</defs>
<metadata>
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
</cc:Work>
</rdf:RDF>
</metadata>
<rect width="256" height="65536" fill="url(#a)" stroke-width="24" style="mix-blend-mode:normal"/>
<rect width="256" height="65536" fill="url(#b)" stroke-width="24" style="mix-blend-mode:normal"/>
</svg> <svg width="4096" height="16384" version="1.1" viewBox="0 0 4096 16384" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient id="a" x2="4096" y1="8192" y2="8192" gradientUnits="userSpaceOnUse">
<stop stop-color="#f00" offset="0"/>
<stop stop-color="#ff0" offset=".125"/>
<stop stop-color="#0f0" offset=".25"/>
<stop stop-color="#0ff" offset=".375"/>
<stop stop-color="#00f" offset=".5"/>
<stop stop-color="#f0f" offset=".625"/>
<stop stop-color="#f00" offset=".75"/>
<stop stop-color="#000" offset=".875"/>
<stop stop-color="#fff" offset="1"/>
</linearGradient>
<linearGradient id="b" x1="2048" x2="2048" y2="16384" gradientUnits="userSpaceOnUse" xlink:href="#a">
<stop stop-color="#808080" offset="0"/>
<stop stop-color="#808080" stop-opacity="0" offset=".25"/>
<stop stop-color="#fff" offset=".5"/>
<stop stop-color="#fff" stop-opacity="0" offset=".75"/>
<stop offset="1"/>
</linearGradient>
</defs>
<rect width="4096" height="16384" fill="url(#a)" stroke-width="24" style="mix-blend-mode:normal"/>
<rect width="4096" height="16384" fill="url(#b)" stroke-width="24" style="mix-blend-mode:normal"/>
</svg>An image with the same pixels but randomly arranged cannot really be compressed.
When you save in image in JPG, it's compressed using an algorithm that gets it "pretty close" to the source image. The software doing the JPG decoding (browser, image viewer, etc.) basically reverses this algorithm to display the image back to you. For JPG, this compression is "lossy" and so you've lost detail from the original source image.
PNG is a lossless image format, but it basically works the same way without sacrificing the source image's quality.
The "standard" for an image format dictates how an encoder creates the image and how a decoder displays the image. Since everyone is "on the same page," the individual image files only need to contain what they need to -- basically, "this pixel = RGB(0,1,2)".
Hope this makes sense and helps.
Gotta ask. Has anyone worked on image compression using machine learning? (that sounds like an obvious thing to do). It would be funny to end up with an algorithm no one understands.
Given both the financial value of image compression (given the amount of video shoved down the net) and the asymmetry of codec (it's OK to use resources to compress, not so much for decompress), I'd expect some real money to be spent in this area.
Dunno about the state of the art, but pretty much every ml tutorial has a section titled "Image Compression Using Autoencoders" right at the beginning. It's the Hello World of ml. The perceptual quality vs file size curve for such a simple network is pretty mediocre, but I'm sure you could do better if that was your goal.
Tangentially related is the crash bandicoot game on the playstation. The developers figured out that untextured polygons were way faster to draw than textured polygons, and so they made the player character model out of tons of tiny colored polygons rather than fewer larger textured polygons. The result was a significantly better looking graphic for the same rendering time.
Now your question is basically reduced to "how can text files with same number of bytes, each having ALL the ascii codes, compress to files of such different size". The answer is that it MUST necessarily be so. You can't have a one-to-one map from [2]^N to [2]^K where K < N.
Except that you've already noted that JPG is a lossy compression scheme, so it doesn't matter that a one-to-one map isn't possible.
For the ordered image: "Make a 16 by 16 grid of boxes, each getting redder from left to right and top to down. Inside each box make a 16x16 grid of boxes getting greener, and inside each of those boxes make a 16x16 grid of pixels getting bluer". Done.
Vs. the random image: "Make a blueish red pixel with a bit of green. Then make a reddish blue pixel with a a moderate amount of green. Then make a brownish pixel. Then make a greenish pixel..." That will go on for about 16 million sentences!
Image compression is simply coming up with a language that's good for describing images, and then an algorithm for writing succinct descriptions in that language. Rather than being human friendly languages (a modest number of complex words made from an alphabet), they are computer friendly languages (a ton of simple words made from 0s and 1s.)
JPEG compression separates out the image into "component" images. One component is brightness, another is hue, and a third is saturation. Each of those components map nicely to how human vision works. In particular, brightness needs high resolution and precision. Hue needs high precision but resolution doesn't matter. Saturation doesn't need high resolution or precision. Therefore, each component can be compressed differently and independently from each other. The component images are further broken up into a grid of 8x8 boxes, and then each of those boxes are approximated via a weighted sum of reference box images (the encoder and decoder have a dictionary of reference boxes they both agree to use.) For each box, only the weights are saved. The weights themselves can have varying precision, and that's basically you're controlling when you set the "jpeg quality". Higher quality jpegs have more precision in their weights, and lower quality jpegs have less precision in their weights.
PNG works like this. You can run each horizontal row through any one of a variety of delta encoders that are suitable for different situations. The goal is to minimize the range of values and maximize the repetition before you pass the encoded deltas through a dictionary based compressor. Pictures like this are near optimal for this approach.
It uses simulated annealing to arrange the colours smoothly.
This is hard to believe. An already compressed PNG can be substantially re-compressed by a generic lossless process?
If I'm not mistaken, this would be `(2^24) permutation (2^24)`, aka `(2^24)!`, an unbelievably large number!
Edit: Yes: https://allrgb.com (should have googled)
I was trying to figure out how it's possible to store 16 million separate colors in 58,000 bytes. Looks like it's storing information about the gradient patterns, and not each individual color.
This should match the level of grey which the image appears to be if you view it at full resolution. It will only match the zoomed out image if your computer also uses the correct averaging formula.
So each pixel in the small version is going to actually be an averaging of a 16x16 block of original pixels. Because they're randomly distributed, mostly that averaging is going to result in medium gray. Zooming out is going to do something similar (though the exact effect would depend on how the zoom algorithm works).
Plus, your eyes/brain are going to do some smoothing/averaging of their own even where the screen is able to display individual 1:1 source pixels (consider for example that every pixel on what's probably an LCD you're viewing the image on is itself some combination of red, green and blue subpixels).
I was bummed to realize that the api and the zip file only expose the top name for any color at one time. It’d be cool to have access to all the data.
all16777216rgb-scrambled.png: PNG image data, 4096 x 4096, 8-bit/color RGB, interlacedThe image data is stored such that downloading the first section of the file gets you enough information to display a low-resolution version of the image, and continuing the download allows for progressive refinement of the image.
For png, you end up with a variety of settings all the way from "very weak" up to "weak".
A rectangle of 256*256 pixels can display all possible combinations for two color channels, with the third one held constant. If you step through every possible value of the third channel, you end up with 256 of those pictures, which can be arranged neatly in a 16*16 grid (16*16 = 256).
Because each image has 256*256 pixels, and we have 16*16 of them, we end up with a 4096*4096 pixel image (because 16*256 = 4096), which now holds every possible combination of the 3 color channels.
Because this systematic approach creates neatly ascending rows of color values, the resulting image compresses quite well.
The 3 colours are 100% on one surface and 0% on the opposite. The cube being 256x256x256 pixels in size.
Then in that image you’re showing slices of that cube.
Turns out, it’s also the way everyone else likes to visualise colours. That’s why it’s called a colour space I guess.