Color change by SKAction? - sprite

I want to change the color of an SKSpriteNode by score.
Its color should change smoothly so I tried to use an SKAction.
But, the color doesn't change.
if (score > 20) {
SKAction *changeColor = [SKAction colorizeWithColor:self.color colorBlendFactor:0 duration:3];
[self.sprite runAction:changeColor];
return;
}

[SKAction colorizeWithColor:self.color colorBlendFactor:0 duration:3];
A colorBlendFactor of 0 means that the color takes no effect, ie the color values are multiplied with colorBlendFactor to compute the actual amount of color applied to each pixel. Change colorBlendFactor to 1 and you'll see the sprite being colorized.

Related

Calculate a colour in a linear gradient

I'd like to implement something like the powerpoint image below. A gradient that goes between three values.
It starts at A (-1), the mid point is B (0), and the end is C (1).
I have realised that I can save some effort by calculating the 'start' as a-to-b, and the 'end' as b-to-c. I can do as 2 sets of 2 gradients, instead of 1 gradient with three values.
But I'm stumped (despite googling) on how to get from one colour to another - ideally in the RGB colour space.
I'd like to be able to have something like this -
const colourSpace = (value, startColor, endColor) => {...}
colorSpace(-0.25, red, yellow) // some sort of orangey color
colorSpace(1, yellow, green) // fully green
colorSpace(0.8, yellow, green) // mostly green
This isn't a front-end application, so no CSS gradients - which is what google was mostly referencing.
Thanks all,
Ollie
If you aren't too worried about being perceptually consistent across the color space (you would need to work in something like LAB mode to do that), you can just take the linear interpolation in RGB space. Basically you take a distance (between 0 and 1), multiply it by the different in the coordinates, and add it to the first one. This will allow you to find arbitrary points (i.e colors) along the line between any two colors.
For example between red and yellow:
let canvas = document.getElementById('canvas')
var ctx = canvas.getContext('2d');
let rgb1 = [255, 0, 0] // red
let rgb2 = [255, 255, 0] // yellow
function getPoint(d, a1, a2) {
// find a color d% between a1 and a2
return a1.map((p, i) => Math.floor(a1[i] + d * (a2[i] - a1[i])))
}
// for demo purposes fill a canvas
for (let i = 0, j = 0; i < 1; i += .002, j++) {
let rgb = getPoint(i, rgb1, rgb2)
ctx.fillStyle = `rgba(${rgb.join(",")}, 1)`
ctx.fillRect(j, 0, 1, 200);
}
<canvas id="canvas" width="500"></canvas>
You can repeat this to get multiple 'stops' in the gradient.
I ended up using Chroma for converting between colour spaces.

Setting color variable

I need to compare colors. I want to set a color into a variable and then compare that it a value obtained using getPixel.
However, the following does not work. It seems like ImageJ does not know that the value in basecolor is a color.
basecolor = 0xFFFFFF;
rightpixel = getPixel(x, y);
if (rightpixel == basecolor) count++;
Your problem is in getPixel which does not yield a color written in hex.
I present to you your best friend on ImageJ : the built-in macro functions code
https://imagej.nih.gov/ij/developer/macro/functions.html
which documents built-in pixel functions such as getPixel().
For getPixel(), it is stated "Note that pixels in RGB images contain red, green and blue components that need to be extracted using shifting and masking. See the Color Picker Tool macro for an example that shows how to do this. ", and the Color Picker Tool macro tells us how to go from color "bits" to RGB.
So if you wish to compare colors, you do :
basecolor=newArray(0,0,0);
rightpixel = getPixel(x,y);
//from the Color Picker Tool macro
//converts what getPixel returns into RGB (values red, green and blue)
if (bitDepth==24) {
red = (v>>16)&0xff; // extract red byte (bits 23-17)
green = (v>>8)&0xff; // extract green byte (bits 15-8)
blue = v&0xff; // extract blue byte (bits 7-0)
}
//compare the color with your color
if(red==basecolor[0] && green==basecolor[1] && blue==basecolor[2]){
print("Same Color");
count++;
}
//you can also work with hex by converting the rgb to hex and then
//comparing the strings like you did

d3 color scale - linear with multiple colors?

I'm trying to create something a little like a quantize scale, but act like a linear color scale?
When I try to put multiple colors into a linear scale, it seems to only scale between the first two colors.
I'd like multiple colors like a quantize scale, but fade between those colors. I'm unsure if this is possible.
//red and green works ok
var color = d3.scale.linear()
.range(['red','green']);
//doesn't work - only red and green show
var color = d3.scale.linear()
.range(['red','green', 'blue']);
//red green and blue show, however it doesn't fade between the colors
var color = d3.scale.quantize()
.range(['red','green', 'blue']);
You have to use domain 'pivot' value like:
d3.scale.linear()
.domain([0, pivot, max])
.range(['red', 'green', 'blue']);
From the documentation for continuous scale domains:
Although continuous scales typically have two values each in their domain and range, specifying more than two values produces a piecewise scale. For example, to create a diverging color scale that interpolates between white and red for negative values, and white and green for positive values, say:
var color = d3.scaleLinear()
.domain([-1, 0, 1])
.range(["red", "white", "green"]);
color(-0.5); // "rgb(255, 128, 128)"
color(+0.5); // "rgb(128, 192, 128)"
Anto's solution works great if you want to blend 3 colors. In my case, I needed a way to blend an arbitrary number of colors. For me, the trick was to set up the domain correctly. Take for example, the following array of colors:
var colors = ['#084594', '#2171b5', '#4292c6', '#6baed6', '#9ecae1', '#c6dbef', '#eff3ff'];
You can create a domain array with values from -1 to +1 like this:
var domain = [-1];
var increment = 2/(colors.length-1);
for (var i=0; i<colors.length-2; i++){
var previous = domain[domain.length-1];
domain.push(previous+increment);
}
domain.push(1);
Once the domain array is created, you can create a color function like this:
var getColor = d3.scaleLinear()
.domain(domain)
.range(colors);
If you want to get color values at specific percentages (like chroma does), you can do something like this:
var p = 0.25; //Valid range for p is 0.0-1.0
var x = (p*2)-1;
var color = d3.color(getColor(x));
console.log(color.formatHex());

How to calculate Hue, Saturation and Lightness values from a chosen color by input distance

Given a starting hex code, I would like to know the maths to calculate the linear values of lightness in ascending and descending order. Same for Hue and Saturation.
It's kinda difficult for me to describe exactly what i want, forutnately i've found this page which make use of the exact algorithms i need:
http://www.workwithcolor.com/hsl-color-schemer-01.htm
If you checked the page you noticed that the last 3 redio buttons read: Linear by Hue, Linear by Saturation, Linear by Lightness. Each, gives you a list of hex codes in ascending order that correspond to the original hex code.
For example, for the lightness they give the following list (from color FFCE2E):
FFCE2E FFDA61 FFE694 FFF2C7 FFFEFA
I need the formulas, please.
Thanks in advance.
You can mash this up from multiple places. In a nutshell you need:
The HSL value of your picked color. Maybe this is obtained by converting an RGB to HSL (How do you get the hue of a #xxxxxx colour?) or on the website you just pick it on a palette
Now you have the 3 component (H, S, and L) and depending on which checkbox you choose, you start to decrement the component by the % value given in the edit box.
You'll obtain a list of values during this decrement and you'll now do a reverse conversion from the HSL value to the RGB (HSL to RGB color conversion).
// I gonna use rgbToHsl and hslToRgb from https://stackoverflow.com/questions/2353211/hsl-to-rgb-color-conversion
var initialRGB = [ir, ig, ib];
var initialHSL = rgbToHsl(initialRGB[0], initialRGB[1], initialRGB[2]);
var howManyVariants = 4;
var decrementPercent = 0.1; // 10%
// This example is for hue change
var decrement = initialHSL[0] * decrementPercent;
for (var i = 0; i < howManyVariants; i++) {
// Linear decrementation
var nextHue = initialHSL[0] - i * decrement;
var nextColor = hslToRgb(nextHue, initialHSL[1], initialHSL[2]);
// visualize somehow
}
Similarly, if you want to have a set of variation by saturation then you decrement only the second parameter/component, and if you want vary luminescence, you vary the 3rd parameter.
Hope this is clear.

RGB range for cold and warm colors?

What are ranges of cold and warm colors (http://www.diy-bathroom-remodel.com/images/color_wheel.gif) in RGB?
Taking the image you linked to as a reference of what is "warm" and "cold", we get the following.
The hottest colour is completely red (R=255, G=0, B=0).
The coldest colour is completely blue (R=0, G=0, B=255).
So the more R you have, the warmer the colour, and the more B you have, the cooler the colour. The G takes you through shades of turquoise, green, and yellow, each being increasingly warmer. When G is zero, you move in the lower left diagonal of the circle when R and B change. As G approaches 255, you cross over the upper right diagonal when R and B change.
However, the adjacent warm and cool colours have a different amount of green in them. The red immediately below the diagonal line has less green than the red immediately above it. The blue immediately below the diagonal line has less green than the blue immediately above it. This colour wheel looks like it doesn't represent the RGB space all that well especially in the blue end of the spectrum.
Ultimately, what you perceive as warm and cold depends on your monitor settings and light conditions. A lot of it is also your perception and cognition – what you think is warm or cold. In an image, the colour contrasts will affect your judgement. An "in-between" colour next to a clearly cool colour will look warm, but if the same colour is next to a clearly warm colour, it will look cool. Take a look at this colour wheel:
Here, every single 24-bit colour is shown (8 bits for each of R, G, and B), and the RGB values for the top, right, bottom, and left colours are shown. To my eye, there are more "cool" colours than "warm". Hope this helps you decide what the RGB values are for what you perceive as cool and warm colours.
Bonus: In the image above, you can also see the colours expressed in the hue, saturation, and value (HSV) colour model. Hue basically encodes the colour. Saturation encodes how "full" the colour is – less saturation makes it more "bleak", ie. white. Value encodes how dark it is – less value makes it more black, and also makes the white of the saturation more grey. Hue goes from 0 to 360 and corresponds to the angle of a circle, with 0 being totally red, 90 being a sort of neon green, 180 being bright blue, 270 being bluish purple, and 360 going back to red again. S and V go from 0 to 100 and will influence the exact shade – these examples are with S=V=100.
To my eye, H values in the ranges 0-80 and 330-360 are warm while H>80 and H<330 are cold (approximately).
You may want to open the colour selector in your favourite paint program. They can usually show HSV and RGB side by side and let you play with a colour wheel and see the effects on the HSV and RGB numbers. If you don't already have one, I would suggest GIMP. It has the colour wheel I've been using to get the numbers for this answer.
Bonus 2: All of the above assumes a subjective assessment of what is warm and what is cool. I think the only way to make an objective measurement of colour temperature is to measure it and express it on a temperature scale. Often Kelvin seems to be used. This measure takes into account not only shade of the colour, but its brightness (or how much light it emits) too. If you have a modern monitor, it probably has a temperature setting with some Kelvin values to choose from. It is possible to calculate the temperature of each RGB colour on your display, as long as you know the temperature of your white (the white balance). However, this calculation is very complex and I don't know how to do it. You may find Bruce Lindbloom a good source for further information, or any book on colour science. But I guess this is more than you bargained for with your question... ;-)
Looks to me like
if (B>R) {
color=cool
} else {
color=warm
}
is a pretty good approximation. You can check this out on your color wheel using:
http://www.colorzilla.com/firefox/
already answered but need to add this:
If you are interested in physical temperature and color dependencies then this is the scale you are looking for:
It is the color of light emitting from blackbody of given temperature. In astronomy is this used for star color classification (like BV color index).
It also can be used for indirect temperature measurements.
I've found these parameters satisfactory
For Warm color :
R from 128 to 255
G from 0 to 128
B from 0 to R
For Cold color :
R from 0 to B
G from 0 to 255
B from 128 to 255
Note that high green makes the color more cold (in my view but that's debatable ^^), that's why it's restricted for warm colors but not for cold ones.
Warm colors have more red,
and cool colors have more blue.
In RGB:
red = 0
blue = 0
if (red > blue) {
isWarmColor = true
isCoolColor = false
}
else if (red < blue) {
isWarmColor = false
isCoolColor = true
}
else {
isWarmColor = false
isCoolColor = false
}
In HSL:
hueAngle = 0
if (hueAngle < 0 || hueAngle > 360 || hueAngle == 90 || hueAngle == 270) {
isWarmColor = false
isCoolColor = false
}
else if (hueAngle > 90 && hueAngle < 270) {
isWarmColor = false
isCoolColor = true
}
else if (hueAngle < 90 && hueAngle > 270) {
isWarmColor = true
isCoolColor = false
}
Simple and accurate:
def is_hot(a):
return (a[..., 'RED'] > 128)
where 'RED' stands for the index of the red channel in the array a.
This works -- you can see for yourself by: (a) looking at the second wheel by Fabian Fagerholm and/or (b) go to the following link and move the bar up and down towards the two warm ends.
https://www.colorspire.com/rgb-color-wheel/
For me below calculation, with the inclusion of saturation, gives a better result. Since fully desaturated colors like Black, White and Gray are considered neutral colors.
if (hueAngle == 90 || hueAngle == 270 || (hueAngle == 0 && saturation == 0))
{
isWarmColor = false;
isCoolColor = false;
}
else if (hueAngle > 90 && hueAngle < 270)
{
isWarmColor = false;
isCoolColor = true;
}
else
{
isWarmColor = true;
isCoolColor = false;
}

Resources