是否有任何 javascript 库可以使用 HTML5 画布(或任何其他方式)对图像进行像素比较?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9136524/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Are there any javascript libs to pixel compare images using HTML5 canvas (or any other means)?
提问by Sean
Would like to test if 2 images pixel match and/or whether a smaller sized image pixel matches some same sized section of a larger image.
想测试 2 个图像像素是否匹配和/或较小尺寸的图像像素是否与较大图像的某个相同尺寸的部分匹配。
回答by crazyjoe
The first part, test if two images match perfectly, is pretty straight forward.
第一部分,测试两个图像是否完美匹配,非常简单。
//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;
}
As long as you aren't using extremely hi-res images I wouldn't worry about speed, one iteration trough canvas data like this is typically very fast, ~10ms per Mega Pixel on a decent computer with a modern browser. Remember width and height of the images must be the same. For most practical purposes this yes or no match is not very useful, encoding errors lead to imperceptible changes in images, it is best to use a metric to measure how far apart the two images are. A naive but fairly effective metric is the RMSof the two images:
只要您不使用非常高分辨率的图像,我就不会担心速度,像这样的一个迭代槽画布数据通常非常快,在配备现代浏览器的体面计算机上每百万像素约 10 毫秒。请记住图像的宽度和高度必须相同。对于大多数实际目的,这种是或否匹配并不是很有用,编码错误会导致图像发生不可察觉的变化,最好使用度量来衡量两个图像相距多远。一个简单但相当有效的指标是两个图像的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;
}
Here the rms will range from [0,255], 0 if the images match exactly, 255 if one image is all rgba(0,0,0,0) and the other is all rgba(255,255,255,255). How to threshold what is an acceptable rms difference is up to you to tune (around 1 to 2 perhaps).
这里的 rms 范围为 [0,255],如果图像完全匹配,则为 0,如果一个图像全部为 rgba(0,0,0,0),另一张图像全部为 rgba(255,255,255,255),则为 255。如何确定可接受的均方根差值的阈值取决于您的调整(可能约为 1 到 2)。
For the second part of your question, whether a smaller sized image pixel matches some same sized section of a larger image, I'm assuming that they are not translated and that we know the scale difference between the two, otherwise this would open it up into a very complicated and interesting problem see Pattern Recognition. Then with this egregious assumption I would use the canvas to scale the large image down to the exact same size as the smaller one and get the rms between them. Don't test for an exact match as scaling will always create slight errors and never be an exact match.
对于您问题的第二部分,较小尺寸的图像像素是否与较大图像的某个相同尺寸的部分匹配,我假设它们没有被翻译并且我们知道两者之间的比例差异,否则这会打开它变成一个非常复杂和有趣的问题参见模式识别。然后根据这个令人震惊的假设,我将使用画布将大图像缩小到与较小图像完全相同的大小,并获得它们之间的均方根值。不要测试完全匹配,因为缩放总是会产生轻微的错误并且永远不会完全匹配。
回答by chris
回答by some
I don't know if there is anything like that out there, and I'm not sure the web-browser is the place to do it in... however I have been playing around with the canvas element a little bit and wanted to share what I come up with. Maybe you find something useful in it.
我不知道那里是否有类似的东西,我不确定网络浏览器是否适合做这件事……但是我一直在玩画布元素并想分享我的想法。也许你会从中发现一些有用的东西。
The code below is tested in Chrome 20 only. You must have the images and the script loaded from the same domain, or it will not work (I didn't find a way to upload images on jsfiddle so I didn't put this there)
以下代码仅在 Chrome 20 中测试。 您必须从同一个域加载图像和脚本,否则它将无法工作(我没有找到在 jsfiddle 上上传图像的方法,所以我没有把它放在那里)
To test if two images are identical I load each image and draw it on a canvas element, and compare the width, height and pixeldata.
为了测试两个图像是否相同,我加载每个图像并将其绘制在画布元素上,然后比较宽度、高度和像素数据。
index.html
索引.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>
Identical pixels compare.js
相同像素 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);
}
);
});
To test if an image is part of another image, is slow.
测试一个图像是否是另一个图像的一部分,很慢。
- Compare sizes: if SMALL > BIG then it can't be part of BIG.
- For every x and y of BIG, compare if SMALL is a fit.
- 比较尺寸:如果 SMALL > BIG 那么它不能是 BIG 的一部分。
- 对于 BIG 的每个 x 和 y,比较 SMALL 是否合适。
(add this to the code above, and change the call after image B is loaded)
(在上面的代码中添加这个,在加载图片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');
}
回答by hackerone
you could try paper.js
你可以试试 paper.js
it allows you to use your image as a raster
它允许您将图像用作光栅
http://paperjs.org/tutorials/images/using-pixel-colors/http://paperjs.org/tutorials/images/working-with-rasters/
http://paperjs.org/tutorials/images/using-pixel-colors/http://paperjs.org/tutorials/images/working-with-rasters/
the paper.js lib can definitely do more than comparing images..
paper.js 库绝对可以做的不仅仅是比较图像..
here's a simple script that works..
这是一个有效的简单脚本..
// 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');
}
回答by André Al?ada Padez
Well, i don't know if there's something out there for that so, i'll give it a shot:
好吧,我不知道那里是否有一些东西,所以,我会试一试:
first, you will need a function to compare two arrays, you will find one anywhere on the web; like:
首先,您需要一个函数来比较两个数组,您可以在网络上的任何地方找到一个;喜欢:
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;
}
then you create a function that will return the imageData, of the image:
然后创建一个函数,该函数将返回图像的 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;
}
then you can do something like:
那么你可以做这样的事情:
var imgData1 = getImgData('../img/image1');
var imgData2 = getImgData('../img/image2');
if(arrayCompare(imgData1, imgData2)){
//images are the same;
} else {
// images are different
}
Now, this covers the first part of the problem. I'm sure that with a little bit of effort, you can find a function on the web to compare 2 arrays finding out if one is contained by the other.
现在,这涵盖了问题的第一部分。我敢肯定,只要稍加努力,您就可以在网上找到一个函数来比较 2 个数组,以确定一个数组是否包含在另一个数组中。
As a final note, i am aware that these arrays are very very large and that this implemention may not be cost effective. I know that there are probably better solutions for this problem, but this was what i could think of. I'm sure you can find more effective array comparers around and, maybe my approach is completely useless near others that i don't know.
最后要注意的是,我知道这些数组非常非常大,而且这种实现可能不符合成本效益。我知道这个问题可能有更好的解决方案,但这是我能想到的。我相信你可以找到更有效的数组比较器,也许我的方法在我不知道的其他方法附近完全没用。
回答by FelipeAls
Resemble.jsis a JavaScript library for image comparison. From GitHub description:
Resemble.js是一个用于图像比较的 JavaScript 库。来自 GitHub 描述:
Resemble.js can be used for any image analysis and comparison requirement you might have in the browser. However, it has been designed and built for use by the PhantomJS powered visual regression library PhantomCSS. PhantomCSS needs to be able to ignore antialiasing as this would cause differences between screenshots derived from different machines.
Resemble.js uses the HTML5 File API to parse image data, and canvas for rendering image diffs.
Resemble.js 可用于您在浏览器中可能有的任何图像分析和比较需求。但是,它是为 PhantomJS 支持的视觉回归库PhantomCSS设计和构建的。PhantomCSS 需要能够忽略抗锯齿,因为这会导致来自不同机器的屏幕截图之间存在差异。
Resemble.js 使用 HTML5 文件 API 来解析图像数据,并使用画布来呈现图像差异。
回答by tnt-rox
assuming data1 & data2 are arrays. you can use canvasPixelArray(s)
假设 data1 & data2 是数组。你可以使用 canvasPixelArray(s)
var same = [];
same = data1 && data2;
if (same.length < data1.length) {
//your code here
}