通过Javascript获取图像的平均颜色

IT技术 javascript image-manipulation
2021-01-23 20:47:55

不确定这是否可行,但希望编写一个脚本来返回图像的平均值hexrgb值。我知道它可以在 AS 中完成,但希望在 JavaScript 中完成。

6个回答

AFAIK,做到这一点的唯一方法是<canvas/>...

演示 V2http : //jsfiddle.net/xLF38/818/

请注意,这仅适用于同一域中的图像以及支持 HTML5 画布的浏览器:

function getAverageRGB(imgEl) {

    var blockSize = 5, // only visit every 5 pixels
        defaultRGB = {r:0,g:0,b:0}, // for non-supporting envs
        canvas = document.createElement('canvas'),
        context = canvas.getContext && canvas.getContext('2d'),
        data, width, height,
        i = -4,
        length,
        rgb = {r:0,g:0,b:0},
        count = 0;

    if (!context) {
        return defaultRGB;
    }

    height = canvas.height = imgEl.naturalHeight || imgEl.offsetHeight || imgEl.height;
    width = canvas.width = imgEl.naturalWidth || imgEl.offsetWidth || imgEl.width;

    context.drawImage(imgEl, 0, 0);

    try {
        data = context.getImageData(0, 0, width, height);
    } catch(e) {
        /* security error, img on diff domain */
        return defaultRGB;
    }

    length = data.data.length;

    while ( (i += blockSize * 4) < length ) {
        ++count;
        rgb.r += data.data[i];
        rgb.g += data.data[i+1];
        rgb.b += data.data[i+2];
    }

    // ~~ used to floor values
    rgb.r = ~~(rgb.r/count);
    rgb.g = ~~(rgb.g/count);
    rgb.b = ~~(rgb.b/count);

    return rgb;

}

对于 IE,请查看excanvas

无需数数,因为count === length / 4 / blockSize;)
2021-03-18 20:47:55
Dan:我认为如果您尝试访问来自另一个域的图像上的图像数据,就会遇到跨域限制。这是一个无赖。
2021-04-01 20:47:55
找到了一个很好的跨域限制解决方法:只需img.crossOrigin = '';在设置src属性之前添加发现于:coderwall.com/p/pa-2uw
2021-04-03 20:47:55
我认为蓝色和绿色值的位置令人担忧,你写的'rgb('+rgb.r+','+rgb.b+','+rgb.g+')'应该是'rgb('+rgb.r+','+rgb.g+','+rgb.b+')'当主色是蓝色但结果是绿色时,这很奇怪:)。
2021-04-07 20:47:55
有没有办法获得位于不同域上的图像的颜色直方图?
2021-04-09 20:47:55

我想我会发布一个我最近遇到的项目以获得主色:

色贼

用于从图像中获取主色或代表性调色板的脚本。使用 javascript 和画布。

提到和建议主色的其他解决方案从未真正在适当的上下文中回答问题(“在 javascript 中”)。希望这个项目能帮助那些想要这样做的人。

“主色”很棘手。你想要做的是比较颜色空间中每个像素和每隔一个像素的距离(欧氏距离),然后找到颜色最接近每个其他颜色的像素。该像素是主色。平均颜色通常是泥。

我希望我在这里有 MathML 来向您展示欧几里得距离。去谷歌上查询。

我在这里使用 PHP/GD 在 RGB 颜色空间中完成了上述执行:https : //gist.github.com/cf23f8bddb307ad4abd8

然而,这在计算上非常昂贵。它会在大图像上使您的系统崩溃,并且如果您在客户端中尝试它肯定会使您的浏览器崩溃。我一直致力于将我的执行重构为: - 将结果存储在查找表中,以备将来在每个像素的迭代中使用。- 将大图像划分为 20px 20px 的网格以实现局部优势。- 使用 x1y1 和 x1y2 之间的欧几里德距离来计算 x1y1 和 x1y3 之间的距离。

如果您在这方面取得进展,请告诉我。我会很高兴看到它。我也会这样做。

Canvas 绝对是在客户端执行此操作的最佳方式。SVG 不是,SVG 是基于矢量的。在我停止执行之后,我要做的下一件事就是让它在画布中运行(也许每个像素的总距离计算都有一个网络工作者)。

另一件要考虑的事情是 RGB 不是一个很好的颜色空间,因为 RGB 空间中颜色之间的欧几里得距离不是很接近视觉距离。一个更好的颜色空间可能是 LUV,但我还没有找到一个好的库,或者任何将 RGB 转换为 LUV 的算法。

一种完全不同的方法是在彩虹中对颜色进行排序,并构建一个具有容差的直方图,以说明颜色的不同深浅。我没有尝试过这个,因为在彩虹中排序颜色很困难,颜色直方图也是如此。我接下来可能会尝试这个。再次,如果您在这里取得任何进展,请告诉我。

这是一个很好的答案。我写了几个节点module,不是在 LUV 中,而是在 L a b* 颜色空间中进行欧几里得距离计算参见github.com/zeke/color-namergithub.com/zeke/euclidean-distance
2021-03-14 20:47:55
@user:我只是想知道:在大图像上,例如 1% 的样本是否足以加快计算速度?
2021-03-15 20:47:55
这是我希望我能做的不仅仅是 +1 的那些答案之一:-)
2021-03-19 20:47:55
听起来像几何中位数。也许这会有所帮助? stackoverflow.com/questions/12934213 /... 如果您要寻找的点必须存在于原始集合中: en.m.wikipedia.org/wiki/Medoid#Algorithms_to_compute_medoids
2021-03-24 20:47:55
即使没有给出明确的解决方案,答案也很好。这将帮助我决定下一步...
2021-04-09 20:47:55

第一:它可以在没有 HTML5 Canvas 或 SVG 的情况下完成。
实际上,有人只是设法使用 JavaScript 生成客户端 PNG 文件而不使用画布或 SVG,使用数据 URI 方案

编辑:您可以简单地创建一个 PNG document.getElementById("canvas").toDataURL("image/png", 1.0)

第二:您实际上可能根本不需要 Canvas、SVG 或上述任何内容。
如果您只需要在客户端处理图像,而不需要修改它们,那么这一切都不需要。

您可以从页面上的 img 标签获取源地址,为其发出XHR请求——它很可能来自浏览器缓存——并将其作为来自 Javascript 的字节流进行处理。
您需要很好地理解图像格式。(上面的生成器部分基于 libpng 源,可能提供了一个很好的起点。)

+1 用于字节流解决方案。如果唯一的选择是在客户端应用程序上创建它,这是一个很好的选择。
2021-03-16 20:47:55

我会说通过 HTML 画布标签。

你可以在这里找到@Georg 的一篇关于 Opera 开发人员的小代码的帖子:

// Get the CanvasPixelArray from the given coordinates and dimensions.
var imgd = context.getImageData(x, y, width, height);
var pix = imgd.data;

// Loop over each pixel and invert the color.
for (var i = 0, n = pix.length; i < n; i += 4) {
    pix[i  ] = 255 - pix[i  ]; // red
    pix[i+1] = 255 - pix[i+1]; // green
    pix[i+2] = 255 - pix[i+2]; // blue
    // i+3 is alpha (the fourth element)
}

// Draw the ImageData at the given (x,y) coordinates.
context.putImageData(imgd, x, y);

这通过使用每个像素的 R、G 和 B 值来反转图像。您可以轻松存储 RGB 值,然后将红色、绿色和蓝色数组四舍五入,最后将它们转换回十六进制代码。

有没有可能有一个 IE 替代画布解决方案?
2021-04-04 20:47:55
@Ben4Himv:有 IE9 平台预览版 ;-) 但说真的,恐怕没有。
2021-04-09 20:47:55