简体   繁体   English

Javascript画布:如何有效地计算两幅画布的距离

[英]Javascript canvas: how to efficiently compute distance of two canvases

I want to compute the distance between two figures drawn in two canvases, actually i'm doing the following, iterating through the data of the canvases (canvases have the same size): 我想计算两个画布中绘制的两个数字之间的距离,实际上我正在做以下操作,迭代画布的数据(画布具有相同的大小):

var computeDifference = function() {

    var imgd1 = bufferCtx.getImageData(0, 0, w, h).data;
    var imgd2 = targetCtx.getImageData(0, 0, w, h).data;

    var diff = 0;

    for(var i=0; i<imgd1.length; i+=4) {
        var d = (imgd1[i]-imgd2[i]);
        var tot = d > 0 ? d : -d;
        diff += tot
    }

    return diff;
}

this is not very efficient. 这不是很有效率。

Is there a better method? 有更好的方法吗? I read about composite operations, but I'm not sure if that could help in this case. 我读到了关于复合操作的内容,但我不确定在这种情况下这是否有帮助。

I've purposely considered only the R channel because for now I'm operating with black and white images, but I'm probably going to consider the other channels later. 我故意只考虑R频道,因为现在我正在使用黑白图像,但我可能会考虑其他频道。

You can use the new difference blending method on a single canvas, draw both images in with mode set before the last draw, then extract the bitmap data to get the total sum. 您可以在单个画布上使用新的difference 混合方法,在最后一次绘制之前使用模式设置绘制两个图像,然后提取位图数据以获得总和。

You would use the same property, globalCompositeOperation , to set blending mode with. 您可以使用相同的属性globalCompositeOperation来设置混合模式。

This way you are letting the browser do the initial work calculating the difference on each component leaving you only to sum them up. 这样您就可以让浏览器完成初始工作,计算每个组件的差异,只留下它们。 You are also saving one canvas, one call to getImageData() which is relative expensive on an hardware accelerated system: 您还要保存一个画布,一个调用getImageData() ,这在硬件加速系统上相对昂贵:

ctx.drawImage(image1, x, y);
ctx.globalCompositeOperation = "difference";  // use composite to set blending...
ctx.drawImage(image2, x, y);

// extract data, and sum -

Note: IE11 does not support the new blending modes. 注意:IE11不支持新的混合模式。 For IE you would need to do the difference calculations manually as initially. 对于IE,您需要手动进行差异计算。

You can feature detect this by providing the fast method when supported, manual when not: 您可以通过在支持时提供快速方法,在不提供时手动检测此功能:

ctx.globalCompositeOperation = "difference";
if (ctx.globalCompositeOperation === "difference") {
    // fast
}
else {
    // manual
}

Live performance test 现场表演测试

Test1 will do manual difference calclation, test2 will use browser difference blending mode. Test1将做手动差异校准,test2将使用浏览器差异混合模式。 On my setup FireFox wins with more than a 4x factor (slightly less difference in Chrome). 在我的设置中,FireFox赢得超过4倍的因素 (Chrome中的差异略小)。

 var canvas1 = document.createElement("canvas"), canvas2 = document.createElement("canvas"), ctx1 = canvas1.getContext("2d"), ctx2 = canvas2.getContext("2d"), img1 = new Image, img2 = new Image, count = 2, startTime1, startTime2, endTime1, endTime2, sum1, sum2; performance = performance || Date; // "polyfill" the performance object img1.crossOrigin = img2.crossOrigin = ""; // we need to extract pixels img1.onload = img2.onload = loader; img1.src = "http://i.imgur.com/TJiD5GM.jpg"; img2.src = "http://i.imgur.com/s9ksOb1.jpg"; function loader() {if(!--count) test1()} // handle async load function test1(){ startTime1 = performance.now(); ctx1.drawImage(img1, 0, 0); ctx2.drawImage(img2, 0, 0); var data1 = ctx1.getImageData(0, 0, 500, 500).data, data2 = ctx2.getImageData(0, 0, 500, 500).data, i = 0, len = data1.length, sum = 0; // we do all channels except alpha channel (not used in difference calcs.) while(i < len) { sum += Math.abs(data2[i] - data1[i++]) + Math.abs(data2[i] - data1[i++]) + Math.abs(data2[i] - data1[i++]); i++ } sum1 = sum; endTime1 = performance.now(); test2(); } function test2(){ startTime2 = performance.now(); ctx1.drawImage(img1, 0, 0); ctx1.globalCompositeOperation = "difference"; if (ctx1.globalCompositeOperation !== "difference") alert("Sorry, use Firefox or Chrome"); ctx1.drawImage(img2, 0, 0); var data = ctx1.getImageData(0, 0, 500, 500).data, i = 0, len = data.length, sum = 0; // we do all channels except alpha channel while(i < len) { sum += data[i++]; sum += data[i++]; sum += data[i++]; i++; } sum2 = sum; endTime2 = performance.now(); result(); } function result() { var time1 = endTime1 - startTime1, time2 = endTime2 - startTime2, factor = time1 / time2, res = "Manual method: " + time1.toFixed(3) + "ms<br>"; res += "Blending mode: " + time2.toFixed(3) + "ms<br>"; res += "Factor: " + factor.toFixed(2) + "x<br>"; res += "Sum 1 = " + sum1; res += "<br>Sum 2 = " + sum2; document.querySelector("output").innerHTML = res; } 
 <output>Loading images and calculating...</output> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM