我想计算在两幅画布中绘制的两个数字之间的距离,实际上我正在做以下事情,迭代画布的数据(画布具有相同的大小):
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;
}
这不是很有效。
有更好的方法吗?我读到了复合操作,但我不确定在这种情况下这是否有用。
我故意只考虑R频道,因为现在我正在使用黑白图像,但我可能会稍后考虑其他频道。
答案 0 :(得分:1)
您可以在单个画布上使用新的difference
混合方法,在最后一次绘制之前使用模式设置绘制两个图像,然后提取位图数据以获得总和。
您可以使用相同的属性globalCompositeOperation
将混合模式设置为。
通过这种方式,您可以让浏览器执行初始工作来计算每个组件的差异,只留下它们。您还要保存一个画布,一个调用getImageData()
,这在硬件加速系统上相对昂贵:
ctx.drawImage(image1, x, y);
ctx.globalCompositeOperation = "difference"; // use composite to set blending...
ctx.drawImage(image2, x, y);
// extract data, and sum -
注意:IE11不支持新的混合模式。对于IE,您需要手动进行差异计算。
您可以通过在支持时提供快速方法,在不提供时手动检测此功能:
ctx.globalCompositeOperation = "difference";
if (ctx.globalCompositeOperation === "difference") {
// fast
}
else {
// manual
}
Test1将进行手动差异校准,test2将使用浏览器差异混合模式。在我的设置中,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>