分析图像并匹配最接近的调色板

时间:2014-09-01 09:16:51

标签: javascript image canvas

我有一定数量的调色板(8),每个调色板有5种颜色。目标是使用画布处理图像并确定哪个调色板最接近匹配。

当我从调色板获得平均RGB值时,在将光源转换为LAB并使用CIE1976计算色差之前对源图像执行相同操作。最接近的匹配是最小距离。

这在一定程度上起作用,但我测试的许多图像都匹配两个特定的调色板。有没有更好的方法来计算图像最相关的调色板?

所以我改变它以使用直方图。我将下面的一些代码放在下面,但基本上我是

  • 从所选图像创建3D RGB直方图,将rgb值拆分为8个库中的一个,(8 * 8 * 8),即512。
  • 展平直方图以创建单个512阵列。
  • 通过除以图像中的总像素来标准化值。
  • 我为调色板做同样的事情,创建一个平直的512直方图。
  • 计算两个直方图之间的卡方距离,以找到最接近的调色板。

我的调色板只有5种颜色,直方图很空。将直方图与卡方进行比较时,这是一个问题。

这就是我为要分析的图像创建平面直方图的方法。

            var canvas = document.createElement('canvas'),
                ctx = canvas.getContext('2d'),
                imgWidth = this.width,
                imgHeight = this.height,
                totalPixels = imgWidth * imgHeight;

            ctx.drawImage(this, 0, 0, this.width, this.height);

            var data = ctx.getImageData(0, 0, imgWidth, imgHeight).data;
            var x, y, z, histogram = new Float64Array(512);

            for(x=0; x<imgWidth; x++){
                for(y=0; y<imgHeight; y++){
                    var index = imgWidth * y + x;

                    var rgb = [data[index], data[index+1], data[index+2] ];

                    // put into relevant bank
                    var xbin = Math.floor((rgb[0]/255)*8)
                    var ybin = Math.floor((rgb[1]/255)*8)
                    var zbin = Math.floor((rgb[2]/255)*8)

                    histogram[ (ybin * 8 + xbin) * 8 + zbin ] ++;
                }
            }

            // normalize values.
            for(var i=0; i<512; i++) {
                histogram[i] /= totalPixels;
            }

这就是我为调色板创建直方图的方法。颜色只存储在RGB值数组中,每个调色板有5种颜色。

        var pals = [];

        palettes.forEach(function(palette){
            var paletteH = new Float64Array(512);
            palette.forEach(function(color){
                var xbin = Math.floor((color[0]/255)*8);
                var ybin = Math.floor((color[1]/255)*8);
                var zbin = Math.floor((color[2]/255)*8);
                paletteH[ (ybin * 8 + xbin) * 8 + zbin ] ++;
            });
            for(var i=0; i<512; i++) { paletteH[i] /= 5; }
            pals.push(paletteH);
        });

为了计算卡方距离,我循环通过每个调色板获得到图像直方图的距离。那么最小的应该是最相似的。

            for(var p = 0; p<pals.length; p++){
                var result = 0;
                for(var i=0; a = histogram[i], b = pals[p][i], i < 512; i++ ){
                    result += 0.5 * ( Math.pow(a-b,2) / (a + b + 1e-10));
                }
                console.log(result);
            }

这样可行,但结果似乎不对。例如,我将分析森林场景的图像,期望它产生绿色调色板,但它将返回另一个。我非常感谢任何指导。

1 个答案:

答案 0 :(得分:0)

您需要在调色板颜色和样本颜色之间使用最小二乘差异。

您还需要为每个频道R G B和可能的A。

执行此操作

它看起来像这样([...]中的伪代码):

var min = 999999;
var paletteMatch;

[loop sample colors] {
  [loop palette colors] {

    float lsd = (Math.pow(paletteR - sampleR, 2) + [greed] + [blue]) / 3;

    if (lsd < min) {
      min = lsd;
      paletteMatch = currentPaletteInThisLoop;
    }
  }
  [award a point for paletteMatch for this sample Color
}

[which palette has the most points?]