使用所选颜色转换主色

时间:2016-09-28 20:58:18

标签: javascript jquery canvas html5-canvas

在使用画布工作/学习时间之后我已经设法获得图像克隆和它的像素现在我已经让用户从颜色specterm中选择颜色并且我在我的函数中有颜色十六进制:

move: function (color) {

 // 'color' is the value user selected

var img_id = jQuery(".selected_bg_img").attr("id");

alert(img_id);

var x = 0;
var y = 0;
var width = 409;
var height = 409;


var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
var img=document.getElementById(img_id);
ctx.drawImage(img,x,y,width,height);

var imageData = ctx.getImageData(0,0,width,height);

var data = imageData.data;

alert(data);

}

现在有两个任务正在进行中,
 1.我们如何从数据中提取最大颜色?
 2.我们如何将最大颜色转换为我们在功能中获得的颜色? 对于实时工作示例,我在结尾处给出了链接 注意:从产品图像的左侧选择图像(任何最后3个),当选择颜色时,它将图像克隆到下面的画布。
在这里,我尝试使用所选颜色的用户替换最大颜色来克隆图像 注意:最大颜色我的意思是(图像中的主色),例如http://lokeshdhakar.com/projects/color-thief/这个项目正在获得图像的主色,但它在节点上,我试图获得支配并在克隆之前改变颜色。

for (var i=0;i<imgData.data.length;i+=4)
{
  imgData.data[i]=255-imgData.data[i];
  imgData.data[i+1]=255-imgData.data[i+1];
  imgData.data[i+2]=255-imgData.data[i+2];
  imgData.data[i+3]=255;
  }

***** EDIT ***** 我的问题不是很复杂,我想我有这个形象 enter image description here

所以我们可以清楚地看到主色是灰色的,通过任何方法,我只是试图用我的函数move中的新颜色替换该颜色,并用新颜色绘制该图像。我拍摄的图像显示了另一个例子:
http://www.art.com/products/p14499522-sa-i3061806/pela-silverman-colorful-season-i.htm?sOrig=CAT&sOrigID=0&dimVals=729271&ui=573414C032AA44A693A641C8164EB595 在图像的左侧,当我们选择相似的图像时,它们在图像的底部中心具有选项“改变颜色”。这正是我想要做的
所以现在我尝试读取图像1x1,这是我登录时在控制台中得到的结果(特别是我已经显示的图像):

[166, 158, 152, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…]

所以它可能是从左上角开始的第一个开始,我想它需要在整个图像上进行迭代,这是我在迭代整个图像时得到的结果:

[110, 118, 124, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255…]

我用于迭代的循环是:

var imageData = ctx.getImageData(0,0,width,height);

var data = imageData.data;

for (var i=0;i<data.length;i+=4)
{
  data[i]=255-data[i];
  data[i+1]=255-data[i+1];
  data[i+2]=255-data[i+2];
  data[i+3]=255;
}
console.log(data);

这次迭代是对的吗?如果是的话,现在似乎是替换主色并且我在这里是空白的我们如何替换它并用替换的颜色写回图像还是还有更多的东西?
*************编辑***********
我现在在rgb中有用户值,需要查找应该放置该值的地方

1 个答案:

答案 0 :(得分:2)

这个答案可能是你想要的,因为它有点不清楚。

查找图像中的主色

我使用两种方法。还有很多其他方法可以做到,最好的方法取决于需求和质量要求。我将集中精力使用直方图来滤除无关的像素以获得结果。

简单易行。

创建一个1像素的画布。确保画布平滑处于打开状态。

ctx.imageSmoothingEnabled = true;    
ctx.mozImageSmoothingEnabled = true;

将图像绘制到1 x 1画布上

ctx.drawImage(image,0,0,1,1);

获取像素数据

var data = ctx.getImageData(0,0,1,1);

rgb值就是你所追求的。

r = data.data[0];
g = data.data[0];
b = data.data[0];

结果应用于下图。

enter image description here

很长的路

这种方法很长且有问题。你需要忽略直方图中rgb的低值和高值(忽略黑白值)和HSL忽略饱和度和值(亮度)0或100%,否则你会得到红色总是支配对比度很好的图像

在图像处理中,直方图是图像内图像属性(例如,红绿蓝)的分布图。由于数字图像具有离散值,直方图(条形图)将沿x轴绘制值,而y轴则绘制具有该值的像素数。

直方图的一个例子。请注意,此代码不会在此处运行,因为存在交叉原点限制。 (抱歉忘了我的浏览器禁用了它。)

/** CopyImage.js begin **/
// copies an image adding the 2d context
function copyImage(img){
    var image = document.createElement("canvas");  
    image.width = img.width;
    image.height = img.height; 
    image.ctx = image.getContext("2d"); 
    image.ctx.drawImage(img, 0, 0);
    return image;
}
function copyImageScale(img,scale){
    var image = document.createElement("canvas");  
    image.width = Math.floor(img.width * scale);
    image.height = Math.floor(img.height * scale); 
    image.ctx = image.getContext("2d"); 
    image.ctx.drawImage(img, 0, 0,image.width,image.height);
    return image;
}
/** CopyImage.js end **/
function getHistogram(img){  // create a histogram of rgb and Black and White
    var R,G,B,BW;
    R = [];
    G = [];
    B = [];
    BW = [];  // Black and white is just a mean of RGB
    for(var i=0; i < 256; i++){
       R[i] = 0;  
       G[i] = 0;  
       B[i] = 0;  
       BW[i] = 0;  
    }
    var max = 0;    // to normalise the values need max
    var maxBW = 0;   // Black and White will have much higher values so normalise seperatly
    var data = img.ctx.getImageData(0,0,img.width,img.height);
    var d = data.data;
    var r,g,b;
    i = 0;
    while(i < d.length){
        r = d[i++];  // get pixel rgb values
        g = d[i++];
        b = d[i++];
        i++; // skip alpha
        R[r] += 1;  // count each value
        G[g] += 1;
        B[b] += 1;
        BW[Math.floor((r+g+b)/3)] += 1;
    }
    // get max
    for(i = 0; i < 256; i++){
        max = Math.max(R[i],G[i],B[i],max);
        maxBW = Math.max(BW[i],maxBW);
    }
    // return the data    
    return {
        red : R,
        green : G,
        blue : B,
        gray : BW,
        rgbMax : max,
        grayMax : maxBW,
    };
}

function plotHistogram(data,ctx,sel){
    var w = ctx.canvas.width;
    var h = ctx.canvas.height;
    ctx.clearRect(0,0,w,h); // clear any existing data
    var d = data[sel];
    if(sel !== "gray"){
        ctx.fillStyle = sel;
    }
    var rw = 1 / d.length; // normalise bar width
    rw *= w; // scale to draw area;
    for(var i = 0; i < d.length; i++ ){
        var v = 1-(d[i]/data.rgbMax); // normalise and invert for plot
        v *= h; // scale to draw area;
        var x = i/d.length;  // normaise x axis
        x *= w; // scale to draw area
        if(sel === 'gray'){
            ctx.fillStyle = "rgb("+i+","+i+","+i+")";
        }
        ctx.fillRect(x,v,rw,h-v); // plot the bar
    }
}

var canMain = document.createElement("canvas");  
canMain.width = 512;
canMain.height = 512; 
canMain.ctx = canMain.getContext("2d"); 
document.body.appendChild(canMain);
var ctx = canMain.ctx;

var can = document.createElement("canvas");  
can.width = 512;
can.height = 512; 
can.ctx = can.getContext("2d"); 

// load image and display histogram
var image = new Image();
image.src = "http://i.stack.imgur.com/tjTTJ.jpg";
image.onload = function(){
    image = copyImage(this);
    var hist = getHistogram(image);
    // make background black
    ctx.fillStyle = "black"
    ctx.fillRect(0,0,ctx.canvas.width,ctx.canvas.height);
    
    // create and show each plot
    plotHistogram(hist,can.ctx,"red");
    document.body.appendChild(copyImageScale(can,0.5));
    ctx.drawImage(can,0,0,canvas.width,canvas.height);
    plotHistogram(hist,can.ctx,"green");
    document.body.appendChild(copyImageScale(can,0.5));
    ctx.globalCompositeOperation = "lighter"
    ctx.drawImage(can,0,0,canvas.width,canvas.height);
    plotHistogram(hist,can.ctx,"blue");
    document.body.appendChild(copyImageScale(can,0.5));
    ctx.globalCompositeOperation = "lighter"
    ctx.drawImage(can,0,0,canvas.width,canvas.height);
    plotHistogram(hist,can.ctx,"gray");
    document.body.appendChild(copyImageScale(can,0.5));
    ctx.globalCompositeOperation = "source-over"
    ctx.globalAlpha = 0.9;
    ctx.drawImage(can,0,0,canvas.width,canvas.height);
    ctx.globalAlpha = 1;
}

由于上面的代码需要托管图像,结果如下所示。

图片

enter image description here

RGB和灰色直方图作为上述代码的输出。

enter image description here

通过这个你可以看到主导频道和rgb在图像上的分布(请注意我删除了黑色,因为这个图像有很多黑色像素,其中像素数的其余部分缩小到无意义)< / p>

要找到主色,您可以对HSL值进行相同的操作。为此,您需要将RGB转换为HSL。 This answer具有执行此操作的功能。然后,只需计算每个HSL值并创建直方图。

下一个图像是上述样本图像的HSL直方图。

enter image description here

你可以看到有很多红色,然后是黄色,另一个是绿色。

但是,这仍然不会得到你想要的东西。第二个直方图(饱和度)在中心显示清晰的峰值。有很多颜色具有良好的饱和度,但这并不能告诉你它是什么颜色。

您需要将HSL值过滤到该峰值附近。

我所做的是将HSL值乘以f(s) = 1-Math.abs(s-50)/50 s饱和度范围0-100。这将放大饱和度最大的色调和值。生成的直方图看起来像

enter image description here

现在峰值色调(忽略红色)是橙色。色调值为~42。然后应用滤镜去除所有不在色调= 42附近的像素(您可能想要给出衰减)。您将此过滤器应用于最后一步之后获得的HSL值。下一个图像显示将此滤镜应用于原始

后生成的图像

enter image description here

然后得到所有剩余像素的R,G,B的总和。每个RGB值的平均值是常用颜色。

这种方法的常见颜色。

enter image description here

请注意,结果与您按照上述代码和上述代码应用此方法的结果不同。我使用自己的图像处理应用程序获取仪器步骤,它使用RGB值的真实对数光子计数,这将比线性插值更暗。最后一步将过滤后的像素图像扩展为一个过于复杂而无法在此描述的仪器步骤(在回答开始时对简单方法进行修改)。看起来像

enter image description here

此外,我将此应用于整个图像,对于大图像来说这可能非常慢,但如果您首先缩小图像的大小(必须在图像上平滑(大多数浏览器的默认设置)),它也会起作用。) 。 128 8 128是一个很好的尺寸,但你可以降低。它将取决于图像,它可以使它失败的程度。

相关问题