问题
I have product images and each image has two configurable areas as below: 1. background 2. Foreground
I have to develop a feature where customer can change the color of both areas and save the design.
My problem is, i am traversing the image to read old pixel value and change it with new selected color.
Bit old pixel values are not consistent. There is textured effect on the image, which is causing the pixel value to be changed at every pixel.
How can i achieve the desired the functionality?
or, if you can suggest me any other approach, that will be great.
sample image link: http://developersbench.com/canvas/img/design_2.jpg
回答1:
If i guess right, what you want is to change the pixels that are 'near' from a given color to be changed into another color.
Easiest way i see is to use h,s,l color space : in this 'natural' color space, colors that have a similar hue will be similarly perceived by the eye. And you can just 'shift' the hue, while keeping same saturation (== color 'strength'), and lightness.
So process your image point by point :
• Convert point r, g, b to hue, saturation, lightness
• ? Is the current hue near enough from sourceHue ?
---->> shift it to newHue (keeping same saturation / lightness)
fiddle is here :
http://jsfiddle.net/9GLNP/
You can play around with parameters. The texture you provided has 18 avg hue, so if the source hue is too far from 18, no changes will be done. 8-10 seems a good tolerance.
// Provides a new canvas containing [img] where
// all pixels having a hue less than [tolerance]
// distant from [tgtHue] will be replaced by [newHue]
function shiftHue(img, tgtHue, newHue, tolerance) {
// normalize inputs
var normalizedTargetHue = tgtHue / 360;
var normalizedNewHue = newHue / 360;
var normalizedTolerance = tolerance / 360;
// create output canvas
var cv2 = document.createElement('canvas');
cv2.width = img.width;
cv2.height = img.height;
var ctx2 = cv2.getContext('2d');
ctx2.drawImage(img, 0, 0);
// get canvad img data
var imgData = ctx2.getImageData(0, 0, img.width, img.height);
var data = imgData.data;
var lastIndex = img.width * img.height * 4;
var rgb = [0, 0, 0];
var hsv = [0.0, 0.0, 0.0];
// loop on all pixels
for (var i = 0; i < lastIndex; i += 4) {
// retrieve r,g,b (! ignoring alpha !)
var r = data[i];
var g = data[i + 1];
var b = data[i + 2];
// convert to hsv
RGB2HSV(r, g, b, hsv);
// change color if hue near enough from tgtHue
var hueDelta = hsv[0] - normalizedTargetHue;
if (Math.abs(hueDelta) < normalizedTolerance) {
// adjust hue
// ??? or do not add the delta ???
hsv[0] = normalizedNewHue //+ hueDelta;
// convert back to rgb
hsvToRgb(rgb, hsv);
// store
data[i] = rgb[0];
data[i + 1] = rgb[1];
data[i + 2] = rgb[2];
}
}
ctx2.putImageData(imgData, 0, 0);
return cv2;
}
EDIT :
To get the hue, i consoled.log the hues... ;-) But many (if not all)
image software have a color picker that shows hsl.
For hsl, i have no specific links. google it, and also play with
it within a graphic software.
To avoid coding nightmare, i guess you have to decide of a convention
on the textures you use, like they are 60 +/- 5 hue or like. So then you only
have to decide of the final hue in your game. Detection might be tricky.
回答2:
I'm assuming you already know how to do context.getImageData
to get the RGBA pixel data of your images.
The RGBA format that html5 canvas uses by default is not very useful when changing colors. Two visually similar colors often have very different RGB values.
Instead, convert these RGBA colors to HSL format. The "H" in HSL is "hue" which is what we think of as color. You will find similar colored pixels will have similar HSL "Hue" values.
Then you can let the user recolor the image by "shifting" the existing hue values by a constant offset.
A Demo: http://jsfiddle.net/m1erickson/326yc/
来源:https://stackoverflow.com/questions/24218783/javascript-canvas-pixel-manipulation