Jump to content

Coloring an image


ignace

Recommended Posts

Hi,

 

I am building a 2D car configurator and I need some help with the coloring. Currently I am using this technique to color the car:

http://jsfiddle.net/m1erickson/2d7ZN/

 

But now I am wondering how can I select a color using a color picker like this:

 

<form action="" method="post">
  <label for="color">Pick color</color>
  <input type="color" name="color" id="color">
</form>
And then transform the selected color to match the car's (thus keeping the reflection). I am not looking specifically for code more the name of the algorithm or technique to get me on my way.

 

I am guessing it's something with taking the RGB value of a pixel of the car and then somehow closely represent this color in the other color. Entering that in Google returns squat. Maybe one of you have experience in this sort of thing?

Link to comment
Share on other sites

That technique works well (for images that aren't too large, at least) but only works because it recolors by shifting the hue of each relevant pixel (it being much easier to do this using HSL than with RGB). It's not so much a mapping of blue to green but a mapping of a range of green colors of some size to a range of blue colors of the same size.

 

So you have to figure out two ranges: what you want to recolor from and what you want to recolor to. If all you have to work with is "blue" or "green" then you can guess by picking the midpoint of the hue range for that color and adding/subtracting roughly 60° *. Those will affect the if condition and the colorshift value, so it's probably best to make those all parameters.

function recolorPants(hueStart, hueEnd, colorshift) {
	// correct hueStart and hueEnd for out-of-range values, both <0 and >=360
	hueStart = (360 + (hueStart % 360)) % 360;
	hueEnd = (360 + (hueEnd % 360)) % 360;
if (hueStart < hueEnd && hue > hueStart && hue < hueEnd || hueStart > hueEnd && (hue > hueStart || hue < hueEnd)) {
- If the color you're starting with is RGB, convert it to HSL and use the hue value.

- I suggest "bold" colors for the color choices; you can convert hue=0..360°, saturation=100%, lightness=50% to get them.

 

* Hue ranges from 0 to 360°, and with 6 basic colors that's 60° per color and ±30°. But there's also overlap - consider how teal is greenish and blueish. So you bump that limit out to, say, 50-60° instead.

Link to comment
Share on other sites

Okay I changed the code a bit:

 

function changeColor(color) {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.drawImage(img, 0, 0);

    var imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    var data = imgData.data, red, green, blue, alpha;

    var rgb = HexToRGB(color);
    var hsl = rgbToHsl(rgb.R, rgb.G, rgb.B);

    for (var i = 0, l = data.length; i < l; i += 4) {
        red = data[i];
        green = data[i + 1];
        blue = data[i + 2];
        alpha = data[i + 3];

        if (alpha < 200) continue;

        var imgHsl = rgbToHsl(red, green, blue);

        var newRgb = hslToRgb(hsl.h, hsl.s, imgHsl.l);

        data[i] = newRgb.r;
        data[i + 1] = newRgb.g;
        data[i + 2] = newRgb.b;
        data[i + 3] = 255;
    }

    ctx.putImageData(imgData, 0, 0);
}
This works for some reason well, I can now create blackish and brownish cars. White however I can't get to work. Because I maintain the luminance of the original image (which is red) the black or brown also appears lighter, so I somehow would need to adjust the luminance of the car according to the color I selected. For dark colors, make it darker, for lighter colors make it lighter.

 

I also can't help but feel that this sort of thing has to be in some sort of game library but I tried EaselJS and THREE but none appear to have this feature.

Link to comment
Share on other sites

So being able to handle white makes things awkward: it's not a hue range but both a saturation (how much color bleeds in) and lightness (grayscale) range. Playing around, it looks like good ranges are

- White is S=[0.0,0.1] L=[0.9,1.0]

- Gray is S=[0.0,0.1] L=[0.1,0.9]

- Black is S=[0.0,0.1] L=[0.0,0.1]

 

I figure* the best approach would be deciding what HSL ranges constitute each color, then doing some quick math to convert each component between the current color's ranges and the desired color's ranges. For example, you might say that red is H=[330,15] (meaning both [330,360] and [0,15]) S=[0.1,1.0] (so not to overlap with the grayscale) L=[0.1,1.0]; mapping a value which you've determined to qualify as "red" onto "white" could be

h[white] = h[red] // hue unchanged
s[white] = (s[red] - S[red,min]) / (S[red,max] - S[red,min]) * (S[white,max] - S[white,min]) + S[white,min] // convert 0.1<s[red]<1.0 to 0.0<s[white]<0.1
l[white] = (l[red] - L[red,min]) / (L[red,max] - L[red,min]) * (L[white,max] - L[white,min]) + L[white,min] // convert 0.1<l[red]<1.0 to 0.9<l[white]<1.0
That's a linear transformation - something polynomial (eg, bell curve, sigmoid) would get different results but it would take more planning and math.

 

* I know math and the RGB and HSL colorspaces, but beyond that it's just educated guesswork.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.