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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2541481/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 00:49:19  来源:igfitidea点击:

Get average color of image via Javascript

javascriptimage-manipulation

提问by bgreater

Not sure this is possible, but looking to write a script that would return the average hexor rgbvalue for an image. I know it can be done in AS but looking to do it in JavaScript.

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

回答by James

AFAIK, the only way to do this is with <canvas/>...

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

DEMO V2: http://jsfiddle.net/xLF38/818/

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

Note, this will only work with images on the same domain and in browsers that support HTML5 canvas:

请注意,这仅适用于同一域中的图像以及支持 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;

}

For IE, check out excanvas.

对于 IE,请查看excanvas

回答by J. Chase

Figured I'd post a project I recently came across to get dominant color:

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

Color Thief

色贼

A script for grabbing the dominant color or a representative color palette from an image. Uses javascript and canvas.

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

The other solutions mentioning and suggesting dominant color never really answer the question in proper context ("in javascript"). Hopefully this project will help those who want to do just that.

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

回答by J. Chase

"Dominant Color" is tricky. What you want to do is compare the distance between each pixel and every other pixel in color space (Euclidean Distance), and then find the pixel whose color is closest to every other color. That pixel is the dominant color. The average color will usually be mud.

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

I wish I had MathML in here to show you Euclidean Distance. Google it.

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

I have accomplished the above execution in RGB color space using PHP/GD here: https://gist.github.com/cf23f8bddb307ad4abd8

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

This however is very computationally expensive. It will crash your system on large images, and will definitely crash your browser if you try it in the client. I have been working on refactoring my execution to: - store results in a lookup table for future use in the iteration over each pixel. - to divide large images into grids of 20px 20px for localized dominance. - to use the euclidean distance between x1y1 and x1y2 to figure out the distance between x1y1 and x1y3.

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

Please let me know if you make progress on this front. I would be happy to see it. I will do the same.

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

Canvas is definitely the best way to do this in the client. SVG is not, SVG is vector based. After I get the execution down, the next thing I want to do is get this running in the canvas (maybe with a webworker for each pixel's overall distance calculation).

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

Another thing to think about is that RGB is not a good color space for doing this in, because the euclidean distance between colors in RGB space is not very close to the visual distance. A better color space for doing this might be LUV, but I have not found a good library for this, or any algorythims for converting RGB to LUV.

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

An entirely different approach would be to sort your colors in a rainbow, and build a histogram with tolerance to account for varying shades of a color. I have not tried this, because sorting colors in a rainbow is hard, and so are color histograms. I might try this next. Again, let me know if you make any progress here.

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

回答by Andras Vass

First: it can be done without HTML5 Canvas or SVG.
Actually, someone just managed to generate client-side PNG files using JavaScript, withoutcanvas or SVG, using the data URI scheme.

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

Second: you might actually not need Canvas, SVG or any of the above at all.
If you only need to processimages on the client side, withoutmodifying them, all this is not needed.

第二:您实际上可能根本不需要 Canvas、SVG 或上述任何内容。
如果您只需要在客户端处理图像,而不对其进行修改,则不需要所有这些。

You can get the source address from the img tag on the page, make an XHRrequest for it - it will most probably come from the browser cache - and process it as a byte stream from Javascript.
You will need a good understanding of the image format. (The above generator is partially based on libpng sources and might provide a good starting point.)

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

回答by rnaud

I would say via the HTML canvas tag.

我会说通过 HTML 画布标签。

You can find herea post by @Georg talking about a small code by the Opera dev :

你可以在这里找到@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);

This invert the image by using the R, G and B value of each pixel. You could easily store the RGB values, then round up the Red, Green and Blue arrays, and finally converting them back into an HEX code.

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

回答by bgreater

I recently came across a jQuery plugin which does what I originally wanted https://github.com/briangonzalez/jquery.adaptive-backgrounds.jsin regards to getting a dominiate color from an image.

我最近遇到了一个 jQuery 插件,它完成了我最初想要的https://github.com/briangonzalez/jquery.adaptive-backgrounds.js关于从图像中获取主色调的功能。

回答by Joel Martinez

Javascript does not have access to an image's individual pixel color data. At least, not maybe until html5 ... at which point it stands to reason that you'll be able to draw an image to a canvas, and then inspect the canvas (maybe, I've never done it myself).

Javascript 无法访问图像的单个像素颜色数据。至少,也许直到 html5 ......在这一点上,您可以将图像绘制到画布上,然后检查画布(也许,我自己从未做过),这是有道理的。

回答by Grant Miller

All-In-One Solution

一站式解决方案

I would personally combine Color Thiefalong with this modified version of Name that Colorto obtain a more-than-sufficient array of dominant color results for images.

我个人会将Color ThiefName that Color 的这个修改版本结合起来以获得足够多的图像主色结果数组。

Example:

例子:

Consider the following image:

考虑下图:

enter image description here

在此处输入图片说明

You can use the following code to extract image data relating to the dominant color:

您可以使用以下代码提取与主色相关的图像数据:

let color_thief = new ColorThief();
let sample_image = new Image();

sample_image.onload = () => {
  let result = ntc.name('#' + color_thief.getColor(sample_image).map(x => {
    const hex = x.toString(16);
    return hex.length === 1 ? '0' + hex : hex;

  }).join(''));

  console.log(result[0]); // #f0c420     : Dominant HEX/RGB value of closest match
  console.log(result[1]); // Moon Yellow : Dominant specific color name of closest match
  console.log(result[2]); // #ffff00     : Dominant HEX/RGB value of shade of closest match
  console.log(result[3]); // Yellow      : Dominant color name of shade of closest match
  console.log(result[4]); // false       : True if exact color match
};

sample_image.crossOrigin = 'anonymous';
sample_image.src = document.getElementById('sample-image').src;

回答by dctalbot

As pointed out in other answers, often what you really want the dominant color as opposed to the average color which tends to be brown. I wrote a script that gets the most common color and posted it on this gist

正如其他答案中所指出的,通常您真正想要的是主色,而不是趋于棕色的平均颜色。我写了一个脚本来获取最常见的颜色并将其发布在这个要点上

回答by 350D

Less accurate but fastest way to get average color of the image with dataurisupport:

datauri支持下获得图像平均颜色的不太准确但最快的方法:

function get_average_rgb(img) {
    var context = document.createElement('canvas').getContext('2d');
    if (typeof img == 'string') {
        var src = img;
        img = new Image;
        img.setAttribute('crossOrigin', ''); 
        img.src = src;
    }
    context.imageSmoothingEnabled = true;
    context.drawImage(img, 0, 0, 1, 1);
    return context.getImageData(1, 1, 1, 1).data.slice(0,3);
}