客户端脚本中的图像亮度检测
Posted
技术标签:
【中文标题】客户端脚本中的图像亮度检测【英文标题】:Image brightness detection in client side script 【发布时间】:2012-11-25 14:50:14 【问题描述】:有谁知道是否有一个脚本可用于使用客户端脚本检测图像(包括 html)中的暗度/亮度?
我基本上希望能够检测背景中使用的图像的亮度(暗/亮),并让 CSS/HTML/jQuery/JS 根据暗或亮(真或假)的变量调整页面)。
我知道有可用的服务器端脚本,但不能用于这个特定的开发项目。
【问题讨论】:
唯一的方法是使用 html 不是这个问题的真正答案,但仍然适合那些想在图像上方放置一些文字的人:just add a black outline to your text! 【参考方案1】:此函数会将每种颜色转换为灰度并返回所有像素的平均值,因此最终值将介于 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);
);
JSFiddle:
http://jsfiddle.net/s7Wx2/
【讨论】:
我无法让它与远程图像一起使用。有什么想法吗? @shanebo 您需要使您的 CORS 代码适用。此外,远程图像应具有适当的 CORS 标头。请检查:jsfiddle.net/ray986/rLe0zLr0 我使用了具有 CORS 标头的远程图像,并且我还为保留远程图像的 img 元素设置了 crossOrigin="anonymous" 属性。 不适用于 Firefox 58,也不适用于当前的 Chromium on linux。舔图像没有任何反应。 不确定这是从哪里来的,但 JSfiddle 无法加载 mootools,即使在两个浏览器上都禁用了 adblocker。将其复制到 codepen 即可。 要修复 CORS 问题,您必须在document.body.appendChild(img);
之前添加行 img.crossOrigin = "anonymous";
(src: developer.mozilla.org/en-US/docs/Web/HTML/Attributes/…)【参考方案2】:
我的答案重用了@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/,很简单,不要让我的符号吓到你。
【讨论】:
这是一个真正考虑如何复制人类感知的真正解决方案——而不仅仅是简单的 RGB 平均值。 +1 太棒了。小提琴有点坏,但功能很好。 我修复了小提琴并编辑了链接,它应该可以再次使用。 jsfiddle.net/s7Wx2/328【参考方案3】:称为背景检查的脚本可以检测图像中的暗度/亮度。它使用 javascript 来做到这一点。
这是一个链接:
http://www.kennethcachia.com/background-check/
我希望这可以帮助任何想要在其中制作带有此类检测的滑块的人。
【讨论】:
嗯,这个插件好像不太好用,也让页面变慢了。我使用@lostsource 的想法编写了自己的代码,效果很好。【参考方案4】:MarvinJ 提供方法 averageColor(image) 来获取给定图像的平均颜色。有了平均颜色,您可以创建规则来定义图像上标签的颜色。
加载图片:
var image = new MarvinImage();
image.load("https://i.imgur.com/oOZmCas.jpg", imageLoaded);
获取平均颜色:
var averageColor = Marvin.averageColor(image2); // [R,G,B]
本文sn-p的输出:
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>
【讨论】:
我希望它能跨域工作,但它不能在启用 CORS 的情况下工作。任何方式都很棒的图书馆。【参考方案5】:在我的场景中,我正在处理具有透明背景的图像,因此我需要以不同的方式处理这些像素。
有关代码,请参阅this fiddle。有两个具有透明背景的图像。带有浅色前景的图像以前被认为是来自@mmgp 的代码的深色图像,但现在它被正确解释为浅色。
我的回答是基于this answer from 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,然后...?
【讨论】:
【参考方案6】:在我的设置中,我想检查图像是否透明,如果是,则在不透明像素中主要是暗还是亮。我还想使用远程图像(URL)而不是 base64 编码的数据图像,所以我调整了 @lostsource's excellent answer 以包含一些额外的功能:
返回transparency
和nonTransparentBrightness
(以及brightness
)
crossOrigin="anonymous"
(src) 支持 CORS
使用0
- 100
所以结果是%(而不是0
- 255
)
确保使用完整图像大小而不是渲染图像大小(img.naturalWidth
和 img.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>
【讨论】:
以上是关于客户端脚本中的图像亮度检测的主要内容,如果未能解决你的问题,请参考以下文章
目标检测:python实现多种图像数据增强的方法(光照,对比度,遮挡,模糊)
目标检测:python实现多种图像数据增强的方法(光照,对比度,遮挡,模糊)