想测试2个图像像素是否匹配和/或较小尺寸的图像像素是否与较大图像的相同尺寸部分匹配。
答案 0 :(得分:9)
第一部分,测试两个图像是否完美匹配,非常简单。
//assuming data1,data2 are canvas data of images of the same size
function isMatch(data1,data2){
for(var i = 0; i<data1.length; i++){
if(data1[i] != data2[i]) return false;
}
return true;
}
只要你没有使用非常高分辨率的图像我就不用担心速度了,像这样的一次迭代通常非常快,每台Mega Pixel在带有现代浏览器的不错的计算机上大约10ms。请记住图像的宽度和高度必须相同。对于大多数实际用途,这种是或否匹配不是很有用,编码错误会导致图像中难以察觉的变化,最好使用度量来测量两幅图像之间的距离。一个天真但相当有效的指标是两个图像的RMS:
//assuming data1,data2 are canvas data of images of the same size
function rmsDiff(data1,data2){
var squares = 0;
for(var i = 0; i<data1.length; i++){
squares += (data1[i]-data2[i])*(data1[i]-data2[i]);
}
var rms = Math.sqrt(squares/data1.length);
return rms;
}
这里的rms范围为[0,255],如果图像完全匹配则为0,如果一个图像全部为rgba(0,0,0,0)则为255,另一个为rgba(255,255,255,255)。如何阈值可接受的均方根差异取决于您调整(可能大约为1到2)。
对于问题的第二部分,较小尺寸的图像像素是否与较大图像的相同大小的部分匹配,我假设它们没有被翻译,并且我们知道两者之间的比例差异,否则这会将其打开成一个非常复杂和有趣的问题,请参阅Pattern Recognition。然后,通过这种令人震惊的假设,我将使用画布将大图像缩小到与较小图像完全相同的大小,并获得它们之间的rms。不要测试完全匹配,因为缩放总是会产生轻微错误,永远不会完全匹配。
答案 1 :(得分:4)
答案 2 :(得分:3)
我不知道那里是否有类似的东西,我不确定网络浏览器是否适合这样做...但是我一直在玩一下canvas元素并想分享我的想法。也许你会发现一些有用的东西。
以下代码仅在Chrome 20中进行测试。 您必须从同一个域加载图片和脚本,否则它将无效(我没有找到在jsfiddle上传图片的方法,所以我没有把它放在那里)
为了测试两个图像是否相同,我加载每个图像并在画布元素上绘制它,并比较宽度,高度和像素数据。
的index.html
<!doctype html>
<html>
<head>
<title></title>
<script type="application/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<script type="application/javascript" src="compare.js"></script>
</head>
<body>
</body>
</html>
相同的像素 compare.js
$(function(){
function compare(url_a, url_b, callback) {
var canvas = $("<canvas>").appendTo(document.body)[0];
var ctx = canvas.getContext('2d');
var
image_a = new Image(),
image_b = new Image();
function getData(image) {
//Set canvas to the same size as the image
canvas.width = image.width;
canvas.height = image.height;
//Draw the image on the canvas
ctx.drawImage(image, 0, 0);
//Get the image data from the canvas.
return ctx.getImageData(0,0,canvas.width,canvas.height);
}
function compareIdentical(A,B) {
// Check sizes
if (
A.width != B.width ||
A.height != B.height ||
A.data.length != B.data.length
) {
return callback(false,'Not same size');
}
var a=A.data; b=B.data;
//Check image data
for (var idx=0, len=A.data.length; idx < len; ++idx) {
if (a[idx] !== b[idx]) {
return callback(false,'Not same');
}
}
return callback(true,'Identical');
}
$(image_a).load(function(){
console.log('Image A loaded');
image_a = getData(image_a);
//Load image b
image_b.src = url_b;
});
$(image_b).load(function(){
console.log('Image B loaded');
image_b = getData(image_b);
canvas.parentNode.removeChild(canvas);
compareIndentical(image_a, image_b);
//comparePartOf(image_a, image_b);
});
//Load image a
image_a.src = url_a;
}
//IMPORTANT: Images must be loaded from the same domain as the
//script, or getImageData will not give any data.
compare(
'IMG_2195.JPG',
'IMG_2195.JPG',
function(result,message){
console.log(result,message);
}
);
});
要测试图像是否属于另一张图像,很慢。
(将其添加到上面的代码中,并在加载图像B后更改调用)
function comparePartOf(bigimg, smallimg) {
if (
bigimg.width < smallimg.width ||
bigimg.height < smallimg.height ||
bigimg.data.length < smallimg.data.length
) {
return callback(false,'bigimg smaller than smallimg');
}
var
big=bigimg.data,
small=smallimg.data,
idx,
len=small.length/4,
big_x,
big_y,
big_width = bigimg.width,
big_height = bigimg.height,
small_x,
small_y,
small_width = smallimg.width,
small_height = smallimg.height,
lenw = big_width - small_width,
lenh = big_height - small_height,
big_offset,
small_offset,
result=false;
for(big_x=0; big_x < lenw; ++big_x) {
for(big_y=0; big_y < lenh; ++big_y) {
result = true;
for (idx=0; idx < len; ++idx) {
small_x = idx % small_width;
small_y = Math.floor(idx / small_width);
big_offset = (
(big_x + small_x) + ((big_y + small_y) * big_width)
)<<2;
small_offset = idx << 2;
if (
big[big_offset++] != small[small_offset++] ||
big[big_offset++] != small[small_offset++] ||
big[big_offset++] != small[small_offset++] ||
big[big_offset] != small[small_offset]
) {
result = false;
break;
}
}
if (result) return callback(true,'Found at '+big_x+' '+big_y);
}
}
return callback(false,'not found');
}
答案 3 :(得分:2)
你可以试试paper.js
它允许您将图像用作栅格
http://paperjs.org/tutorials/images/using-pixel-colors/ http://paperjs.org/tutorials/images/working-with-rasters/
paper.js lib绝对可以比比较图像更多。
这是一个有效的简单脚本..
// rasterize both images
var im_a = new Raster('image_a');
var im_b = new Raster('image_b');
var ratio = Math.round(im_a.width / 100);
// downsize the images so we don't have to loop through all the pixels.
im_a.size = new Size(im_a.width/ratio, im_a.height/ratio);
im_b.size = new Size(im_b.width/ratio, im_b.height/ratio);
//hide the images, so they don't display on the canvas
im_a.visible = false;
im_b.visible = false;
var different = false;
// check the image dimensions
if((im_a.width == im_b.width) && (im_a.height == im_b.height)){
// loop through the pixels
for(x = 0 ; x < im_a.width ; x++){
for(y = 0; y < im_a.height; y++){
if(im_a.getPixel(x,y) != im_b.getPixel(x,y) ){
different = true;
break;
}
}
}
}else{
alert('not the same size');
}
答案 4 :(得分:1)
好吧,我不知道那里有什么东西,所以我会试一试:
首先,你需要一个比较两个数组的函数,你会在网络上的任何地方找到一个;像:
function arrayCompare(){
if (x === y)
return true;
if (x.length != y.length)
return false;
for (key in x) {
if (x[key] !== y[key]) {
return false;
}
}
return true;
}
然后你创建一个函数,它将返回图像的imageData:
function getImgData(imgUrl){
var img = new Image(); // Create new img element
img.src = '../img/logo.png'; // params are urls for the images
var canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext('2d');
ctx.drawImage(img1,0,0);
var imageData = ctx.getImageData(0,0,canvas.width, canvas.height);
//returns an array, see documentation for * info
return imageData.data;
}
然后你可以做类似的事情:
var imgData1 = getImgData('../img/image1');
var imgData2 = getImgData('../img/image2');
if(arrayCompare(imgData1, imgData2)){
//images are the same;
} else {
// images are different
}
现在,这涵盖了问题的第一部分。我确信只需要一点点努力,你就可以在网上找到一个函数来比较2个数组,看看是否有另一个数据包含。
作为最后一点,我知道这些阵列非常庞大,而且这种实现可能不符合成本效益。我知道这个问题可能有更好的解决方案,但这是我能想到的。我相信你可以找到更有效的阵列比较器,也许我的方法在我不知道的其他人附近完全没用。
答案 5 :(得分:1)
Resemble.js 是用于图片比较的JavaScript库。来自GitHub描述:
Resemble.js可用于任何图像分析和比较 您可能在浏览器中的要求。但是,它一直都是 设计和构建供PhantomJS驱动的视觉回归使用 库 PhantomCSS 。 PhantomCSS需要能够忽略抗锯齿 因为这会导致从中导出的屏幕截图之间存在差异 不同的机器。
Resemble.js使用HTML5 File API来解析图像数据和画布 用于渲染图像差异。
答案 6 :(得分:0)
假设data1&amp; data2是数组。你可以使用canvasPixelArray(s)
var same = [];
same = data1 && data2;
if (same.length < data1.length) {
//your code here
}