30

有谁知道是否有一个脚本可用于使用客户端脚本检测图像中的暗度/亮度(包括 HTML)?

我基本上希望能够检测背景中使用的图像的亮度(暗/亮),并让 CSS/HTML/jQuery/JS 根据暗或亮(真或假)的变量调整页面。

我知道有可用的服务器端脚本,但不能用于这个特定的开发项目。

4

6 回答 6

62

此函数会将每种颜色转换为灰度并返回所有像素的平均值,因此最终值将介于 0(最暗)和 255(最亮)之间

function getImageLightness(imageSrc,callback) {
    var img = document.createElement("img");
    img.src = imageSrc;
    img.style.display = "none";
    document.body.appendChild(img);

    var colorSum = 0;

    img.onload = function() {
        // create canvas
        var canvas = document.createElement("canvas");
        canvas.width = this.width;
        canvas.height = this.height;

        var ctx = canvas.getContext("2d");
        ctx.drawImage(this,0,0);

        var imageData = ctx.getImageData(0,0,canvas.width,canvas.height);
        var data = imageData.data;
        var r,g,b,avg;

        for(var x = 0, len = data.length; x < len; x+=4) {
            r = data[x];
            g = data[x+1];
            b = data[x+2];

            avg = Math.floor((r+g+b)/3);
            colorSum += avg;
        }

        var brightness = Math.floor(colorSum / (this.width*this.height));
        callback(brightness);
    }
}

用法:

getImageLightness("image.jpg",function(brightness){
    console.log(brightness);
});

JSF中:

http://jsfiddle.net/s7Wx2/

于 2012-12-07T12:25:23.030 回答
34

我的答案重用了@lostsource 答案中的大部分代码,但它使用不同的方法来尝试区分暗图像和亮图像。

首先,我们需要(简要地)分析一下 RGB 通道之和的平均值是什么结果。对于人类来说,这毫无意义。粉红色比绿色亮吗?即,为什么您希望 (0, 255, 0) 给出比 (255, 0, 255) 更低的亮度值?另外,中灰(128、128、128)是否和中绿(128、255、0)一样亮?考虑到这一点,我只处理通道的颜色亮度,就像在 HSV 颜色空间中所做的那样。这只是给定 RGB 三元组的最大值。

剩下的就是启发式了。让我们max_rgb = max(RGB_i)谈谈i。如果max_rgb低于 128(假设是 8bpp 图像),那么我们发现了一个新的点i是暗点,否则是亮点。对每个点都这样做i,我们得到A亮点和B暗点。如果(A - B)/(A + B) >= 0那时我们说图像很轻。请注意,如果每个点都是暗点,那么你得到的值是 -1,相反,如果每个点都是亮点,你得到 +1。可以调整之前的公式,以便您可以接受几乎不暗的图像。在代码中,我将变量命名为,但它对图像处理中的字段fuzzy不公平。fuzzy所以,如果 ,我们说图像是轻的(A - B)/(A + B) + fuzzy >= 0

代码在http://jsfiddle.net/s7Wx2/328/,非常简单,不要让我的符号吓到你。

于 2012-12-07T15:56:53.213 回答
8

称为背景检查的脚本可以检测图像中的暗度/亮度。它使用 JavaScript 来做到这一点。

这是它的链接:

http://www.kennethcachia.com/background-check/

我希望这可以帮助任何想要在其中制作带有这种类型检测的滑块的人。

于 2013-10-01T12:15:31.197 回答
2

MarvinJ提供了averageColor(image)方法来获取给定图像的平均颜色。有了平均颜色,您可以创建规则来定义图像上标签的颜色。

加载图像:

var image = new MarvinImage();
image.load("https://i.imgur.com/oOZmCas.jpg", imageLoaded);

获得平均颜色:

var averageColor = Marvin.averageColor(image2); // [R,G,B]

这篇文章的片段的输出:

在此处输入图像描述

var canvas = document.getElementById("canvas");
var image1 = new MarvinImage();
image1.load("https://i.imgur.com/oOZmCas.jpg", imageLoaded);
var image2 = new MarvinImage();
image2.load("https://i.imgur.com/1bZlwv9.jpg", imageLoaded);
var loaded=0;

function imageLoaded(){
  if(++loaded == 2){
    var averageColor;
    averageColor = Marvin.averageColor(image1);
    setText("LION", averageColor, "text1");
    averageColor = Marvin.averageColor(image2);
    setText("LION", averageColor, "text2");
  }
}

function setText(text, averageColor, id){
  if(averageColor[0] <= 80 && averageColor[1] <= 80 && averageColor[2] <= 80){
     document.getElementById(id).innerHTML = "<font color='#ffffff'>"+text+"</font>";
  }
  else if(averageColor[0] >= 150 && averageColor[1] >= 150 && averageColor[2] >= 150){
     document.getElementById(id).innerHTML = "<font color='#000000'>"+text+"</font>";
  }
  
}
.divImage{
  width:400px; 
  height:268px;
  display:grid;
}

.divText{
  font-family:Verdana;
  font-size:56px;
  font-weight:bold;
  margin:auto;
  display:table-cell;
}
<script src="https://www.marvinj.org/releases/marvinj-0.8.js"></script>
<div id="result"></div>
<div style="background-image:url(https://i.imgur.com/oOZmCas.jpg);" class="divImage">
   <div id="text1", class="divText"></div>
</div>
<div style="background-image:url(https://i.imgur.com/1bZlwv9.jpg);" class="divImage">
   <div id="text2", class="divText"></div>
</div>

于 2018-03-29T12:27:36.440 回答
1

在我的场景中,我正在处理具有透明背景的图像,因此我需要以不同的方式处理这些像素。

有关代码,请参见this fiddle。有两个具有透明背景的图像。具有浅色前景的图像以前被认为是带有@mmgp 代码的深色图像,但现在它被正确解释为浅色。

我的答案是基于 mmgp这个答案的 jsfiddle。不同之处在于完全透明的像素不计为亮或暗。此外,明暗比仅考虑一个或另一个像素,而不是透明的。

// Ignore transparent pixels
if (data[x+3] === 0) {
  continue;
}
// Calculate the dark to light ratio
var dl_diff = ((light - dark) / (light + dark));

希望对 alpha 通道有更多了解的人可以改进它。我觉得只考虑完全透明(0?)的像素是透明的而不处理其他值(1到255)是错误的。可能需要做一些数学运算,比如将 alpha 值除以 255,然后......?

于 2020-12-08T20:00:58.040 回答
0

在我的设置中,我想检查图像是否透明,如果是,则在不透明像素中主要是暗还是亮。我还想使用远程图像(URL)而不是 base64 编码的数据图像,所以我调整了@lostsource 的优秀答案以包含一些额外的功能:

  • 返回transparencynonTransparentBrightness(以及brightness
  • CORS 支持crossOrigin="anonymous"( src )
  • 使用0-100所以结果是 %'s (而不是0- 255)
  • 确保使用完整图像大小而不是渲染图像大小(使用img.naturalWidthimg.naturalHeight),因为图像越小,结果越不可靠(可能是由于像素化)

在我的设置中,我在深色背景上显示图像,所以如果nonTransparentBrightness <= 60 && transparency > 0我添加少量填充和白色背景。

这还没有经过彻底的测试,所以可能有一些怪癖,但看起来方向正确并且到目前为止适用于我的用例。

const getImageBrightness = (img) => {
  if (!img) return null;

  let alphaSum = 0;
  let colorSum = 0;

  var canvas = document.createElement("canvas");
  
  // make the canvas use the full size of the image, not the rendered size
  canvas.width = img.naturalWidth;
  canvas.height = img.naturalHeight;

  var ctx = canvas.getContext("2d");
  ctx.drawImage(img, 0, 0);

  var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
  var data = imageData.data;
  var r, g, b, a, avg;

  for (var x = 0, len = data.length; x < len; x += 4) {
    r = data[x];
    g = data[x + 1];
    b = data[x + 2];
    a = data[x + 3];

    avg = Math.floor((r + g + b) / 3);
    colorSum += avg;
    alphaSum += a;
  }

  const transparency = 100 - Math.floor((alphaSum / (img.naturalWidth * img.naturalHeight) / 255) * 100);
  const brightness = Math.floor((colorSum / (img.naturalWidth * img.naturalHeight) / 255) * 100);
  const nonTransparentBrightness = Math.floor((brightness / (100 - transparency)) * 100);

  return { brightness, transparency, nonTransparentBrightness };
};

var imgs = document.body.getElementsByTagName('img');

const handleImage = (imageSrc) => {
  const img = document.createElement("img");
  img.src = imageSrc;
  img.style.display = "none";
  img.crossOrigin = "anonymous";
  document.body.appendChild(img);

  img.onload = () => {
    const { brightness, nonTransparentBrightness, transparency } =
      getImageBrightness(img);

    document.getElementsByTagName('pre')[0].innerHTML = `brightness: ${brightness} | nonTransparentBrightness: ${nonTransparentBrightness} | transparency: ${transparency}`;
  };
}

for(var x = 0; x < imgs.length; x++) {
  imgs[x].onclick = function() {
    const imgEl = this;
    handleImage(imgEl.src);
  }
}
body {
  background-color: #999;
}

img {
  width: 100px;
}
<img src="https://static.files.bbci.co.uk/orbit/8161b75793cc3c38d814e1a4a19a2f6a/img/blq-orbit-blocks_grey.svg" />
<img src="https://static.aviva.io/assets/logo/aviva-logo.svg" />
<img src="https://www.moneyrates.com/wp-content/uploads/imagesrv_wp/2516/barclays_bank_logo_thumbnail.png" />

<pre>Click on image to get values</pre>

于 2022-01-17T16:19:33.767 回答