【发布时间】:2014-12-24 06:51:06
【问题描述】:
一位客户需要有关提取产品图片主色的程序的帮助。
我能够在 Javascript 中快速实现它;下面的算法仅对图像中 3x3 网格的中心正方形进行采样,以便快速估计图像中的 T 恤颜色。
var image = new Image();
image.onload = function() {
try {
// get dominant color by sampling the central square of a 3x3 grid on image
var dominantColor = getDominantColor();
// output color
$("#output").html(dominantColor);
}
catch(e) {
$("#output").html(e);
}
};
image.src = "sample_image.jpg";
function getDominantColor() {
// Copy image to canvas
var canvas = $("<canvas/>")[0];
canvas.width = image.width;
canvas.height = image.height;
canvas.getContext("2d").drawImage(image, 0, 0);
// get pixels from the central square of a 3x3 grid
var imageData = canvas.getContext("2d").getImageData(canvas.width/3, canvas.height/3, canvas.width/3, canvas.height/3).data;
var colorOccurrences = {};
var dominantColor = "";
var dominantColorOccurrence = 0;
for(var i = 0; i < imageData.length; i += 4) {
var red = imageData[i];
var green = imageData[i+1];
var blue = imageData[i+2];
//var alpha = imageData[i+3]; // not required for this task
var color = RGBtoHEX({"red": red, "green": green, "blue": blue});
if(colorOccurrences[color] == undefined) {
colorOccurrences[color] = 1;
}
else {
colorOccurrences[color] ++;
if(colorOccurrences[color] > dominantColorOccurrence) {
dominantColorOccurrence = colorOccurrences[color];
dominantColor = color;
}
}
}
return dominantColor;
}
function RGBtoHEX(rgb) {
var hexChars = "0123456789ABCDEF";
return "#"
+ (hexChars[~~(rgb.red/16)] + hexChars[rgb.red%16])
+ (hexChars[~~(rgb.green/16)] + hexChars[rgb.green%16])
+ (hexChars[~~(rgb.blue/16)] + hexChars[rgb.blue%16]);
}
有问题的图片是this(预览如下)。
但是,在上面的代码中处理此图像时的结果因机器/浏览器而异:#FF635E 是我在运行 Windows7 并使用 Firefox 32 的机器上看到的。我的客户端运行 Mac 会在 Safari 上获得 #FF474B 的结果,在 Firefox 33 上获得 #FF474C 的结果。
虽然结果很接近,但为什么它们在理想情况下并不完全相同?getImageData 确实因本地设置而异,还是 JPG 数据是在不同的机器上会有不同的解释?
编辑:这张图片不是一次性的。在客户要求处理的一系列图像中发现了这种颜色变化。我和我的客户对同一组图像获得了不同的结果。
【问题讨论】:
-
这与浏览器应用或不应用颜色配置文件有关,以及哪个。
-
不依赖于浏览器画布功能的第三方图像处理库可能会有所帮助。例如,this is a good library。
-
还有其他两种方法可以解决这个问题。一种是使用 WebGL 和 readPixels。 WebGL 可以在上传图片前通过调用
gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);关闭颜色校正。然后你会render it 并读回像素。另一种方法是使用ImageBitmapapi。不幸的是,看起来只有 Chrome 支持带有忽略颜色空间转换选项的完整规范。
标签: javascript canvas colors getimagedata