{"id":22343364,"url":"https://github.com/an0ncer/imagecomparator","last_synced_at":"2025-07-21T12:04:54.932Z","repository":{"id":183313060,"uuid":"580096306","full_name":"AN0NCER/ImageComparator","owner":"AN0NCER","description":"Сравнение изображений на чистом js, с использованием масок.","archived":false,"fork":false,"pushed_at":"2022-12-19T21:11:22.000Z","size":246,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-07-10T23:12:07.876Z","etag":null,"topics":["image","image-processing","images-comparator","javascript","javascript-library"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AN0NCER.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2022-12-19T17:55:42.000Z","updated_at":"2022-12-19T20:56:57.000Z","dependencies_parsed_at":"2023-07-23T22:43:06.285Z","dependency_job_id":null,"html_url":"https://github.com/AN0NCER/ImageComparator","commit_stats":null,"previous_names":["an0ncer/imagecomparator"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/AN0NCER/ImageComparator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AN0NCER%2FImageComparator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AN0NCER%2FImageComparator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AN0NCER%2FImageComparator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AN0NCER%2FImageComparator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AN0NCER","download_url":"https://codeload.github.com/AN0NCER/ImageComparator/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AN0NCER%2FImageComparator/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266296816,"owners_count":23907015,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-21T11:47:31.412Z","response_time":64,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["image","image-processing","images-comparator","javascript","javascript-library"],"created_at":"2024-12-04T08:15:54.068Z","updated_at":"2025-07-21T12:04:54.899Z","avatar_url":"https://github.com/AN0NCER.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ImageComparator\n\nПодключение скрипта:\n\n```html\n\u003cscript src=\"https://raw.githubusercontent.com/AN0NCER/ImageComparator/main/imagecomparator.js\"\u003e\u003c/script\u003e\n```\n\nИспользование:\n\n```js\nconst comparator = new ImageComparator();\ncomparator.compare('image1.png', 'image2.png').then(similarity =\u003e {\n  console.log(similarity);\n});\n```\nЭта функция использует класс `ImageComparator` для сравнения двух изображений с именами `image1.png` и `image2.png`. Класс `ImageComparator` содержит метод `compare`, который принимает два изображения и возвращает обещание (promise), которое разрешается с оценкой схожести между ними. Оценка схожести представляет собой число от 0 до 1, где 0 соответствует полному отсутствию схожести, а 1 соответствует полной схожести.\n\nПосле того как обещание разрешается, в блоке then выполняется функция, которая выводит оценку схожести в консоль. Например, если изображения полностью совпадают, в консоли будет выведено число 1. Если они не совпадают, в консоли будет выведено число, отличное от 1.\n_____\n\n# Реализация\n\nМожно сравнить два изображения в JavaScript. Один из способов сравнения изображений – это сравнение их хэш-сумм. Хэш-сумма – это некоторое числовое значение, которое уникально соответствует каждому изображению. Если два изображения имеют одинаковую хэш-сумму, то с высокой вероятностью они являются одинаковыми.\n\nВот пример кода, который сравнивает хэш-суммы двух изображений:\n\n```js\nconst image1 = document.getElementById('image1');\nconst image2 = document.getElementById('image2');\n\n// Вычисление хэш-суммы изображения\nfunction getImageHash(image) {\n  // Преобразование изображения в массив байт\n  const imageData = new Uint8Array(image.data.length);\n  for (let i = 0; i \u003c image.data.length; i++) {\n    imageData[i] = image.data[i];\n  }\n  // Вычисление хэш-суммы массива байт\n  return hash(imageData);\n}\n\n// Сравнение хэш-сумм двух изображений\nconst image1Hash = getImageHash(image1);\nconst image2Hash = getImageHash(image2);\nif (image1Hash === image2Hash) {\n  console.log('Изображения одинаковые');\n} else {\n console.log('Изображения отличаются');\n}\n```\n\n________\n\nЕсли размеры изображений отличаются, то сравнение хэш-сумм не будет работать. В этом случае можно использовать другие методы сравнения изображений.\n\nОдин из таких методов – это сравнение изображений посредством сравнения их пикселей. Для этого можно преобразовать изображения в массивы пикселей и сравнить соответствующие пиксели в двух массивах. Если все пиксели совпадают, то изображения считаются одинаковыми.\n\nВот пример кода, который сравнивает два изображения посредством сравнения их пикселей:\n\n```js\nconst image1 = document.getElementById('image1');\nconst image2 = document.getElementById('image2');\n\n// Преобразование изображений в массивы пикселей\nconst image1Pixels = getImagePixels(image1);\nconst image2Pixels = getImagePixels(image2);\n```\n\n`getImagePixels` – это функция, которая преобразует изображение в массив пикселей. Каждый пиксель представлен в виде массива из трех элементов (красный, зеленый, синий), которые определяют цвет пикселя.\n\nВот пример реализации функции `getImagePixels`:\n\n```js\nfunction getImagePixels(image) {\n  const canvas = document.createElement('canvas');\n  const context = canvas.getContext('2d');\n  context.drawImage(image, 0, 0);\n  return context.getImageData(0, 0, image.width, image.height).data;\n}\n```\n\nЭта функция создает новый холст, рисует на нем изображение, а затем извлекает массив пикселей с помощью метода `getImageData`.\n\nОбратите внимание, что в этом примере мы предполагаем, что изображение уже загружено на страницу и доступно через объект `image`.\n\n\n____\n\nДля сравнения изображений по пикселям нужно сравнить соответствующие пиксели в двух массивах пикселей. Вот пример функции, которая сравнивает два изображения по пикселям:\n\n```js\nfunction compareImages(image1, image2) {\n  const image1Pixels = getImagePixels(image1);\n  const image2Pixels = getImagePixels(image2);\n\n  // Сравнение массивов пикселей\n  if (image1Pixels.length !== image2Pixels.length) {\n    console.log('Изображения разных размеров');\n    return false;\n  }\n\n  for (let i = 0; i \u003c image1Pixels.length; i++) {\n    if (image1Pixels[i] !== image2Pixels[i]) {\n      console.log('Изображения разные');\n      return false;\n    }\n  }\n\n  console.log('Изображения одинаковые');\n  return true;\n}\n```\n\nВ этой функции мы сначала преобразуем два изображения в массивы пикселей с помощью функции `getImagePixels`, а затем сравниваем соответствующие пиксели в двух массивах. Если все пиксели совпадают, то функция возвращает `true`, в противном случае – `false`.\n\n\u003e\n\u003e И да, этот метод не работает с разными размерами изображений\n\u003e\n\u003e Если изображения разных размеров, то сравнение пикселей не сработает, так как массивы пикселей будут разной длины.\n\u003e\n\u003e Мы приблежаемся ближе к сути\n\u003e\n____\n\nОдним из способов сравнения изображений разных размеров является создание маски изображения, которая состоит из черно-белых пикселей (белый пиксель – означает наличие информации, черный – отсутствие). Затем маску можно сравнивать с другой маской, используя те же методы, что и для сравнения массивов пикселей.\n\n___\n\nЕсли изображения разного размера, но содержат одинаковое изображение, то можно использовать следующий подход:\n\n1.  Создать маску для каждого изображения. Маска – это черно-белое изображение, где белый пиксель означает наличие информации, а черный – отсутствие.\n\n2.  Изменить размер маски с меньшим размером до размера маски с большим размером. Это можно сделать, например, с помощью библиотеки для работы с изображениями, такой как `lodash`, `imagemagick` или `sharp`.\n\n3.  Сравнить полученные маски с помощью тех же методов, что и для сравнения обычных изображений.\n\n___\n\nФункция `createImageMask` преобразует изображение в черно-белую маску, где белый пиксель означает наличие информации, а черный – отсутствие.\n\nОдин из способов реализации функции `createImageMask` – преобразовать изображение в монохромное с помощью фильтра Яркость. Для этого можно использовать следующий код:\n\n```js\nfunction createImageMask(image) {\n  const canvas = document.createElement('canvas');\n  const context = canvas.getContext('2d');\n  context.drawImage(image, 0, 0);\n  const imageData = context.getImageData(0, 0, image.width, image.height);\n  const data = imageData.data;\n\n  // Преобразование изображения в монохромное\n  for (let i = 0; i \u003c data.length; i += 4) {\n    const brightness = 0.34 * data[i] + 0.5 * data[i + 1] + 0.16 * data[i + 2];\n    data[i] = brightness;\n    data[i + 1] = brightness;\n    data[i + 2] = brightness;\n  }\n\n  context.putImageData(imageData, 0, 0);\n\n  // Создание маски изображения\n  const mask = [];\n  for (let y = 0; y \u003c image.height; y++) {\n    for (let x = 0; x \u003c image.width; x++) {\n      const index = (y * image.width + x) * 4;\n      mask.push(data[index] \u003e 0 ? 1 : 0);\n    }\n  }\n\n  return mask;\n}\n```\n\n___\n\nДля изменения размера маски с меньшим размером до размера маски с большим размером на JavaScript можно использовать следующий код:\n\n```js\nfunction resizeMask(mask, width, height) {\n  const canvas = document.createElement('canvas');\n  canvas.width = width;\n  canvas.height = height;\n  const context = canvas.getContext('2d');\n  const imageData = context.createImageData(width, height);\n  const data = imageData.data;\n\n  // Заполнение массива данных маски\n  for (let y = 0; y \u003c height; y++) {\n    for (let x = 0; x \u003c width; x++) {\n      const index = (y * width + x) * 4;\n      data[index] = mask[y * width + x] ? 255 : 0;\n      data[index + 1] = mask[y * width + x] ? 255 : 0;\n      data[index + 2] = mask[y * width + x] ? 255 : 0;\n      data[index + 3] = 255;\n    }\n  }\n\n  context.putImageData(imageData, 0, 0);\n\n  // Создание новой маски с новым размером\n  const newMask = [];\n  for (let y = 0; y \u003c height; y++) {\n    for (let x = 0; x \u003c width; x++) {\n      const index = (y * width + x) * 4;\n      newMask.push(data[index] \u003e 0 ? 1 : 0);\n    }\n  }\n\n  return newMask;\n}\n```\n\nЭта функция принимает маску изображения и размеры новой маски в виде аргументов `mask`, `width` и `height` соответственно.\n\n___\n\nВ качестве аргументов `width` и `height` функции `resizeMask` нужно передать размеры маски с большим размером, до которого нужно изменить размер маски с меньшим размером.\n\nНапример, если маска с меньшим размером имеет размеры 100x100, а маска с большим размером – 200x200, то нужно передать `width` равным 200 и `height` равным 200:\n\n```js\nconst smallMask = [...]; // маска с меньшим размером\nconst largeMask = resizeMask(smallMask, 200, 200); // маска с большим размером\n```\n\nОбратите внимание, что маска с меньшим размером должна быть представлена в виде массива булевых значений (1 – белый пиксель, 0 – черный).\n\n___\n\nЧтобы достать размеры изображения и использовать их в функции `resizeMask`, можно воспользоваться свойствами `width` и `height` объекта `Image`. Например, так:\n\n```js\n\nconst image = new Image();\nimage.src = 'image.png';\n\nimage.onload = () =\u003e {\n  const mask = createImageMask(image);\n  const resizedMask = resizeMask(mask, image.width, image.height);\n  // Дальнейшая работа с ресайзнутой маской\n};\n\n```\n\nЭтот код создает новый экземпляр объекта `Image`, загружает изображение и создает маску с помощью функции `createImageMask`. Когда изображение загружено, оно используется для создания ресайзнутой маски с помощью функции `resizeMask`.\n\nОбратите внимание, что функция `createImageMask` должна быть реализована ранее.\n\n___\n\nВот пример кода, который сравнивает два изображения и выводит результат сравнения в консоль:\n\n```js\nconst image1 = new Image();\nimage1.src = 'image1.png';\n\nconst image2 = new Image();\nimage2.src = 'image2.png';\n\nPromise.all([image1, image2].map(img =\u003e new Promise((resolve, reject) =\u003e {\n  img.onload = () =\u003e resolve(img);\n  img.onerror = reject;\n}))).then(images =\u003e {\n  const mask1 = createImageMask(images[0]);\n  const mask2 = createImageMask(images[1]);\n  const resizedMask1 = resizeMask(mask1, images[1].width, images[1].height);\n  console.log(resizedMask1 === mask2);\n});\n```\n\nЭтот код загружает два изображения, создает маски для них с помощью функции `createImageMask` и ресайзит маску первого изображения до размера второго изображения с помощью функции `resizeMask`. Затем он сравнивает ресайзнутую маску и маску второго изображения и выводит результат сравнения в консоль.\n\nОбратите внимание, что функции `createImageMask` и `resizeMask` являются псевдокодом и должны быть реализованы ранее.\n\n_____\n\nЕсли вы не знаете, какое изображение является большим, а какое – меньшим, то можно сравнить размеры изображений и выбрать то, которое больше. Например, так:\n\n```js\nconst image1 = new Image();\nimage1.src = 'image1.png';\n\nconst image2 = new Image();\nimage2.src = 'image2.png';\n\nPromise.all([image1, image2].map(img =\u003e new Promise((resolve, reject) =\u003e {\n  img.onload = () =\u003e resolve(img);\n  img.onerror = reject;\n}))).then(images =\u003e {\n  const mask1 = createImageMask(images[0]);\n  const mask2 = createImageMask(images[1]);\n  let resizedMask, originalMask;\n  if (images[0].width \u003e images[1].width || images[0].height \u003e images[1].height) {\n    resizedMask = resizeMask(mask2, images[0].width, images[0].height);\n    originalMask = mask1;\n  } else {\n    resizedMask = resizeMask(mask1, images[1].width, images[1].height);\n    originalMask = mask2;\n  }\n  console.log(resizedMask === originalMask);\n});\n```\n\nВ этом коде сначала сравниваются размеры изображений, а затем выбирается то, которое больше. Ресайзнутая маска и оригинальная маска соответственно выбираются в зависимости от того, какое изображение является большим. Затем они сравниваются и результат сравнения выводится в консоль.\n\n____\n\nЧтобы сравнить маски в процентном соотношении, можно использовать следующий код:\n\n```js\nfunction compareMasks(mask1, mask2) {\n  const width = Math.max(mask1.length, mask2.length);\n  const height = Math.max(mask1[0].length, mask2[0].length);\n  let count = 0;\n  for (let i = 0; i \u003c width; i++) {\n    for (let j = 0; j \u003c height; j++) {\n      if (mask1[i] \u0026\u0026 mask2[i] \u0026\u0026 mask1[i][j] === mask2[i][j]) {\n        count++;\n      }\n    }\n  }\n  return count / (width * height);\n}\n\nconst image1 = new Image();\nimage1.src = 'image1.png';\n\nconst image2 = new Image();\nimage2.src = 'image2.png';\n\nPromise.all([image1, image2].map(img =\u003e new Promise((resolve, reject) =\u003e {\n  img.onload = () =\u003e resolve(img);\n  img.onerror = reject;\n}))).then(images =\u003e {\n  const mask1 = createImageMask(images[0]);\n  const mask2 = createImageMask(images[1]);\n  const resizedMask1 = resizeMask(mask1, images[1].width, images[1].height);\n  const similarity = compareMasks(resizedMask1, mask2);\n  console.log(similarity);\n});\n```\n\n___\n\nВот как можно реализовать функцию сравнения масок с процентным соотношением внутри класса:\n\n```js\nclass ImageComparator {\n    constructor() {\n        this.image1 = new Image();\n        this.image2 = new Image();\n    }\n\n    compare(image1Src, image2Src) {\n        this.image1.src = image1Src;\n        this.image2.src = image2Src;\n\n        return Promise.all([this.image1, this.image2].map(img =\u003e new Promise((resolve, reject) =\u003e {\n            img.onload = () =\u003e resolve(img);\n            img.onerror = reject;\n        }))).then(images =\u003e {\n            const mask1 = this.createImageMask(images[0]);\n            const mask2 = this.createImageMask(images[1]);\n            let resizedMask, originalMask;\n            if (images[0].width \u003e images[1].width || images[0].height \u003e images[1].height) {\n                resizedMask = this.resizeMask(mask2, images[0].width, images[0].height);\n                originalMask = mask1;\n            } else {\n                resizedMask = this.resizeMask(mask1, images[1].width, images[1].height);\n                originalMask = mask2;\n            }\n            return this.compareMasks(resizedMask, originalMask);\n        });\n    }\n\n    createImageMask(image) {\n        const canvas = document.createElement('canvas');\n        const ctx = canvas.getContext('2d');\n        canvas.width = image.width;\n        canvas.height = image.height;\n        ctx.drawImage(image, 0, 0);\n        const imageData = ctx.getImageData(0, 0, image.width, image.height);\n        const mask = [];\n        for (let i = 0; i \u003c image.width; i++) {\n            mask[i] = [];\n            for (let j = 0; j \u003c image.height; j++) {\n                const index = (i + j * image.width) * 4;\n                mask[i][j] = imageData.data[index] === 0 ? 1 : 0;\n            }\n        }\n        return mask;\n    }\n\n    resizeMask(mask, newWidth, newHeight) {\n        const resizedMask = [];\n        for (let i = 0; i \u003c newWidth; i++) {\n            resizedMask[i] = [];\n            for (let j = 0; j \u003c newHeight; j++) {\n                resizedMask[i][j] = mask[Math.floor(i * mask.length / newWidth)][Math.floor(j * mask[0].length / newHeight)];\n            }\n        }\n        return resizedMask;\n    }\n\n    compareMasks(mask1, mask2) {\n        const width = Math.max(mask1.length, mask2.length);\n        const height = Math.max(mask1[0].length, mask2[0].length);\n        let count = 0;\n        for (let i = 0; i \u003c width; i++) {\n            for (let j = 0; j \u003c height; j++) {\n                if (mask1[i] \u0026\u0026 mask2[i] \u0026\u0026 mask1[i][j] === mask2[i][j]) {\n                    count++;\n                }\n            }\n        }\n        return count / (width * height);\n    }\n}\n        \nconst comparator = new ImageComparator();\ncomparator.compare('image1.png', 'image2.png').then(similarity =\u003e {\n  console.log(similarity);\n});\n ```\n \n Теперь вы можете использовать этот класс для сравнения двух изображений, независимо от их размера. Функция `compare` возвращает промис, который выполнится с процентным соотношением совпадающих пикселей.\n \n ___\n \n Вот несколько примеров сравнение двух изображений:\n \n ![First](https://github.com/AN0NCER/ImageComparator/blob/main/example1.png?raw=true)\n \n \n \u003e100% совпадение\n \n ![Second](https://github.com/AN0NCER/ImageComparator/blob/main/example2.png?raw=true)\n \n \n \u003e70% совпадение\n \n ![Last](https://github.com/AN0NCER/ImageComparator/blob/main/example3.png?raw=true)\n \n \n \u003e38% совпадение\n \n ___\n \n Это решение предоставляет примерное сравнение изображений, но оно может не быть совсем точным. Оно сравнивает изображения по пикселям, но не учитывает цвета и интенсивность цвета. Например, если два изображения совпадают по размеру и форме, но отличаются цветом, то это решение может неправильно определить их как несовпадающие.\n\nДля более точного сравнения изображений следует использовать более сложные алгоритмы, которые учитывают также цвета и интенсивность цвета. \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fan0ncer%2Fimagecomparator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fan0ncer%2Fimagecomparator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fan0ncer%2Fimagecomparator/lists"}