Существуют ли какие-либо библиотеки javascript для сравнения пикселей с использованием HTML5 canvas (или любым другим способом)? - PullRequest
2 голосов
/ 04 февраля 2012

Хотелось бы проверить, соответствует ли пиксель 2 изображениям и / или соответствует ли пиксель изображения меньшего размера некоторому сечению такого же размера большего изображения.

Ответы [ 7 ]

9 голосов
/ 04 февраля 2012

Первая часть, тест на соответствие двух изображений, довольно прямолинейна.

//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;
}

Пока вы не используете изображения с очень высоким разрешением, я не буду беспокоиться о скорости, одинПодобные итерации по холсту обычно бывают очень быстрыми: ~ 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;
}

Здесь среднеквадратичное значение будет варьироваться от [0,255], 0, если изображения точно совпадают, 255, если одно изображениевсе rgba (0,0,0,0), а все остальные RGBA (255,255,255,255).Как определить допустимую среднеквадратичную разницу, зависит от вас (возможно, от 1 до 2).

Во второй части вашего вопроса, соответствует ли пиксель изображения меньшего размера некоторому сечению такого же размерав более крупном изображении, я предполагаю, что они не переведены и что мы знаем разницу между двумя масштабами, в противном случае это может привести к очень сложной и интересной проблеме, см. Распознавание образов .Затем с этим вопиющим допущением я использовал холст, чтобы масштабировать большое изображение до того же размера, что и меньшее, и получать среднеквадратичное значение между ними.Не проверяйте точное совпадение, так как масштабирование всегда будет приводить к небольшим ошибкам и никогда не будет точным совпадением.

4 голосов
/ 02 августа 2012
3 голосов
/ 08 августа 2012

Я не знаю, есть ли что-то подобное, и я не уверен, что веб-браузер - это то место, где можно это сделать ... однако я немного поигрался с элементом canvasи хотел поделиться тем, что я придумаю.Возможно, вы найдете в нем что-то полезное.

Приведенный ниже код протестирован только в Chrome 20. У вас должны быть загружены изображения и скрипт из одного домена , иначе он не будет работать (я не нашел способа загрузить изображения на jsfiddle, поэтому я не поместил это туда)

Чтобы проверить, идентичны ли два изображения, я загружаю каждое изображение и рисую его на элементе canvas и сравниваю ширину, высоту и пиксельные данные.

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>

Идентичнопиксели сравнивать.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 из BIG сравните, подходит ли 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');
    }
2 голосов
/ 04 августа 2012

вы можете попробовать paper.js

, что позволяет использовать ваше изображение как растр

http://paperjs.org/tutorials/images/using-pixel-colors/ http://paperjs.org/tutorials/images/working-with-rasters/

lib.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');
        }
1 голос
/ 01 ноября 2013

Resemble.js - это библиотека JavaScript для сравнения изображений.Из описания GitHub:

Resemble.js можно использовать для анализа любых требований к изображениям и их сравнения в браузере.Тем не менее, он был разработан и создан для использования библиотекой визуальной регрессии PhantomJS PhantomCSS .PhantomCSS должен иметь возможность игнорировать сглаживание, поскольку это приведет к различиям между снимками экрана, полученными с разных компьютеров.

Resemble.js использует файловый API HTML5 для анализа данных изображения и canvas для визуализации различий изображений.

1 голос
/ 04 февраля 2012

Ну, я не знаю, есть ли что-то для этого, поэтому я сделаю это:

во-первых, вам понадобится функция для сравнения двух массивов, вы найдете один в любом месте в Интернете; как:

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 массива, чтобы выяснить, содержится ли один в другом.

В качестве последнего замечания я знаю, что эти массивы очень очень велики и что это внедрение может быть неэффективным с точки зрения затрат. Я знаю, что, возможно, есть лучшие решения для этой проблемы, но это было то, что я мог придумать. Я уверен, что вы можете найти более эффективные средства сравнения массивов, и, возможно, мой подход совершенно бесполезен рядом с другими, которых я не знаю.

0 голосов
/ 05 февраля 2012

при условии, что data1 и data2 являются массивами.Вы можете использовать canvasPixelArray (s)

var same = [];
same = data1 && data2;
if (same.length < data1.length) {
   //your code here
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...