It may come as no surprise that our name, Grue & Bleen, is a play on the words Blue & Green. Swap “Gr” and the “Bl” and you’ve got us. It also refers to a linguistic and philosophical theory related to the Riddle of Induction, which states that something as fundamental as our perception of color could change dramatically in the future.
Article Contents (click to expand)
Technology & Perception
The colors we currently perceive as green and blue, then, can be more accurately called “grue” and “bleen”, somewhere in between the two that allows room for this eventual perceptual shift. Some historians even believe that ancient civilizations may not have been able to distinguish between the color green and blue, and it was only once we (the Egyptians) were able to manufacture the color that we made any distinction at all between the two. This is a great example of how deeply the technologies we create can change us, even on the most basic perceptual levels.
I, for one, accept our Grue & Bleen demon overlords.
Let’s Experiment with Javascript Color Manipulation
Let’s make a perceptual leap ourselves! What if we woke up and everything green was blue? Let’s dive into some simple video color manipulation using Javascript to get a taste of the post-blue-green-shift world. We’re going to take a video our favorite amphibious singing puppet and make him blue!
Sample output. Maybe it’ll be easier on our friend Kermit than being green (or bleen!).
A Brief Intro to HSL Color: Degrees Above the Rest
The HTML canvas object uses the (perhaps more familiar) RGB system to manipulate color, but for our purposes, HSL color will be more useful. HSL stands for hue, saturation, and luminosity. We want to select a range of hue, in our case green, and easily shift the hue in that range to another, without changing the saturation or luminosity. HSL works on a degree sale, from 0 to 360, so it will make this shift easy.
HSL Color Wheel: hue is a value from 0 to 360. We’ll say that the green range is approximately between 55 and 185 degrees. We’ll take colors in the green range (say, 55 degrees to 185 degrees), and add a set number of degrees to shift it into the blue range (around 185 to 270 degrees). This is not an exact science, but will be fine for our purposes.
The Markup
This is the code that will sit in a file called ‘index.html’. It consists of a video and two canvases. When the video plays, it will be copied frame by frame to the first canvas, and then we will manipulate the output onto the second canvas. We’ll hide the first canvas, since it’s really only there as an intermediate step between the video and our altered copy.
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
In the javascript, we’ll grab each frame from the video, and manipulate the color to our heart’s content, frame by frame and pixel by pixel. Explanation follows.
var frame = this.ctx1.getImageData(0, 0, this.width, this.height);
var l = frame.data.length / 4;
for (var i = 0; i < l; i++) {
var r = frame.data[i * 4 + 0];
var g = frame.data[i * 4 + 1];
var b = frame.data[i * 4 + 2];
var hsl=this.rgbToHsl(r,g,b);
var hue=hsl.h*360;
// green to blue
if (hue > 55 && hue < 185){
var newRgb=this.hslToRgb(hsl.h+.35,hsl.s,hsl.l);
frame.data[i * 4 + 0] = newRgb.r;
frame.data[i * 4 + 1] = newRgb.g;
frame.data[i * 4 + 2] = newRgb.b;
frame.data[i * 4 + 3] = 255;
}
// blue to green
if (hue >= 185 && hue < 270){
var newRgb=this.hslToRgb(hsl.h-.25,hsl.s,hsl.l);
frame.data[i * 4 + 0] = newRgb.r;
frame.data[i * 4 + 1] = newRgb.g;
frame.data[i * 4 + 2] = newRgb.b;
frame.data[i * 4 + 3] = 255;
}
}
this.ctx2.putImageData(frame, 0, 0);
return;
},
////////////////////////
// Helper functions
//
rgbToHsl: function(r, g, b){
r /= 255, g /= 255, b /= 255;
var max = Math.max(r, g, b), min = Math.min(r, g, b);
var h, s, l = (max + min) / 2;
if(max == min){
h = s = 0; // achromatic
}else{
var d = max – min;
s = l > 0.5 ? d / (2 – max – min) : d / (max + min);
switch(max){
case r: h = (g – b) / d + (g < b ? 6 : 0); break;
case g: h = (b – r) / d + 2; break;
case b: h = (r – g) / d + 4; break;
}
h /= 6;
}
return({ h:h, s:s, l:l });
},
hslToRgb: function(h, s, l){
var r, g, b;
if(s == 0){
r = g = b = l; // achromatic
}else{
function hue2rgb(p, q, t){
if(t < 0) t += 1;
if(t > 1) t -= 1;
if(t < 1/6) return p + (q – p) * 6 * t;
if(t < 1/2) return q;
if(t < 2/3) return p + (q – p) * (2/3 – t) * 6;
return p;
}
var q = l < 0.5 ? l * (1 + s) : l + s – l * s;
var p = 2 * l – q;
r = hue2rgb(p, q, h + 1/3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h – 1/3);
}
return({
r:Math.round(r * 255),
g:Math.round(g * 255),
b:Math.round(b * 255),
});
}
};
The Explanation
We have just a few functions we’re working with:
doLoad
This function does all of our setup. It gets a reference to the video and the first and second canvas, along with their contexts. It then adds an event listener to the video, so that when it plays it calls timerPlayback to begin processing the frames.
timerCallback
If the video is paused or stopped, return. Otherwise, call computeFrame then recursively call timerCallback to continue processing frames.
computeFrame
This is where most of the magic happens.
We draw the current frame onto the first canvas
?Then we grab the image data from the first canvas, for us to play with
?Then we loop through every pixel in that frame, one by one
We get the r, g, and b channels of the current pixel, and then use a helper function to convert the rgb value to an HSL value
If the value is in the green range (between 55 and 185), we add .35 to the value to bump it into the blue range
?If it’s in the blue range, we subtract .25 to lower it into the green range
Then, we push the altered image data onto the second canvas
rgbToHsl & hslToRgb
These are helper functions to convert between RGB and HSL.
See it in action!
Right here: It’s not easy being Bleen! Eventually, we want to make an augmented reality app that flips your color perception. Stay tuned for that!
Dan is Great Big’s techy ambivert, overseeing all web and software development as well as technical strategy. He's a full stack developer but the front end has his heart. He finds great satisfaction in building systems that solve real-world problems, and is interested in making technology more accessible and intuitive for everyone.
Great Big Digital Agency is one of Philadelphia's most innovative digital marketing agencies. Backed by the power of analytics, Great Big builds super-creative digital marketing & website solutions to energize, inspire and push your brand to bigger, greater, heights.