是否有任何javascript库可以使用HTML5画布(或任何其他方式)对图像进行像素比较
Are there any javascript libs to pixel compare images using HTML5 canvas (or any other means)?
想要测试两个图像的像素是否匹配和/或较小大小的图像像素是否匹配较大图像的某个相同大小的部分。
第一部分,测试两个图像是否完美匹配,非常直接。
//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;
}
只要你不使用超高分辨率的图像,我就不会担心速度,像这样的画布数据的一次迭代通常非常快,在一台配有现代浏览器的像样电脑上,每兆像素约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的范围将从[0255]到0,如果一个图像都是rgba(0,0,0,0),而另一个图像全是rgba,则rms的范围为255(255255255)。如何设定可接受的均方根差的阈值取决于您的调整(可能在1到2左右)。
对于问题的第二部分,较小尺寸的图像像素是否与较大图像的相同尺寸部分匹配,我假设它们没有被翻译,并且我们知道两者之间的比例差异,否则这将导致一个非常复杂和有趣的问题,请参阅模式识别。然后,根据这个令人震惊的假设,我会使用画布将大图像缩小到与小图像完全相同的大小,并获得它们之间的rms。不要测试精确匹配,因为缩放总是会产生轻微错误,而且永远不会是精确匹配。
我不知道是否有类似的东西,我也不确定网络浏览器是否适合做这件事……然而,我一直在玩画布元素,并想分享我的想法。也许你在里面找到了有用的东西。
以下代码仅在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);
}
);
});
要测试一个图像是否是另一个图像的一部分,是慢速。
- 比较大小:如果"小">"大",则它不可能是"大"的一部分
- 对于BIG的每个x和y,比较SMALL是否适合
(将此添加到上面的代码中,并在加载图像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');
}
您可以尝试paper.js
它允许您将图像用作光栅
http://paperjs.org/tutorials/images/using-pixel-colors/http://paperjs.org/tutorials/images/working-with-rasters/
paper.js库绝对可以做的不仅仅是比较图像。。
这里有一个简单的脚本。。
// 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');
}
好吧,我不知道是否有什么原因,所以我试试:
首先,你需要一个函数来比较两个数组,你会在网上的任何地方找到一个;类似:
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
}
现在,这涵盖了问题的第一部分。我相信,只要付出一点努力,你就可以在网上找到一个函数来比较两个数组,找出其中一个数组是否包含在另一个数组中。
最后要指出的是,我知道这些阵列非常非常大,而且这种实现可能不具有成本效益。我知道这个问题可能有更好的解决方案,但这是我能想到的。我相信你可以在周围找到更有效的数组比较器,也许我的方法在我不知道的其他方法附近是完全无用的。
Resemble.js是一个用于图像比较的JavaScript库。来自GitHub描述:
类似的.js可以用于任何图像分析和比较浏览器中可能存在的要求。然而为PhantomJS驱动的视觉回归而设计和构建库PhantomCSS。PhantomCSS需要能够忽略抗锯齿因为这会导致源于不同的机器。
Resemble.js使用HTML5 File API解析图像数据,并使用canvas用于渲染图像差异。
假设数据1&data2是数组。可以使用canvasPixelArray
var same = [];
same = data1 && data2;
if (same.length < data1.length) {
//your code here
}
- 客户端图像调整大小.任何已知问题
- 有人知道有没有jquery插件可以在图像上写文本,并让用户将其放置在图像内的任何位置
- 如何通过ajax php将图像上传到服务器本地目录,其中html表单haven't任何传统的提交按钮
- 防止图像拖动,但其他任何内容
- 是从画布获取图像数据的任何方法,从远程视频中提取
- 提交输入类型=“;图像“;到另一个servlet时,未能返回任何参数
- websocketapi-图像编码在客户端不产生任何图像类型
- 有没有任何方法可以使用joomla为图像添加描述!模态挤压盒
- 是否有任何事件在浏览器请求另一个资源(如图像)之前触发
- 任何比较两个不同位图图像并在javascript中检测不同区域的方法
- 单击图像不执行任何操作
- 仅发布图像文件或允许不发布任何文件
- 我无法在我的网站上获取任何图像或显示任何 URL 图像
- 是否可以在不使用任何 severside 脚本语言的情况下将图像上传到服务器文件夹
- JavaScript:Canvas.drawImage 不显示任何图像
- 是否可以使用任何 PHP 仅使用 jQuery 上传图像
- 一种脚本,它从数组中随机加载图像,在查看完所有图像之前不重复任何图像
- Fancybox 加载,但不包含任何图像,即使我很确定图像在正确的位置
- Webshot不保存任何图像
- 如何验证只接受(任何)图像类型文件的表单