Comments (8)
Here is my solution to compare (possibly) differently-dimensioned images: first place each image on an empty canvas having the maximum width and height among both images. Then compare these identically sized versions. I use sharp for the image dimension harmonization.
#!/usr/bin/env node
// filename: pixelmatch-different-size.mjs
'use strict';
import fs from 'fs';
import { PNG } from 'pngjs'; // npm install pngjs ... https://www.npmjs.com/package/pngjs/v/6.0.0
import pixelmatch from 'pixelmatch'; // npm install pixelmatch ... https://www.npmjs.com/package/pixelmatch/v/5.3.0
import sharp from 'sharp'; // npm install sharp ... https://www.npmjs.com/package/sharp/v/0.31.1
const buffer1 = fs.readFileSync('img1.png'); // https://nodejs.org/api/fs.html#fsreadfilesyncpath-options
const sharp1 = sharp(buffer1); // https://sharp.pixelplumbing.com/api-constructor
const sharp1Metadata = await sharp1.metadata(); // https://sharp.pixelplumbing.com/api-input#metadata
const buffer2 = fs.readFileSync('img2.png');
const sharp2 = sharp(buffer2);
const sharp2Metadata = await sharp2.metadata();
// choose maximum width and height among both images, providing a bounding box canvas which can contain either image
const maximumWidth = Math.max(sharp1Metadata.width, sharp2Metadata.width);
const maximumHeight = Math.max(sharp1Metadata.height, sharp2Metadata.height);
// derive a new version "boxedBuffer1" of "img1.png", conceptually placing "img1.png" in the upper-left corner of a bounding box canvas
const boxedBuffer1 = await sharp1
.resize({ // https://sharp.pixelplumbing.com/api-resize#resize
width: maximumWidth,
height: maximumHeight,
fit: 'contain', // instead of cropping or stretching, use "(letter/pillar/window)-boxing" (black space) to fill any excess space
position: 'left top' // arrange the original image in the upper-left corner
})
.raw()
.toBuffer();
const boxedBuffer2 = await sharp2
.resize({
width: maximumWidth,
height: maximumHeight,
fit: 'contain',
position: 'left top'
})
.raw()
.toBuffer();
// boxedBuffer1 and boxedBuffer2 will have the same dimensions
const diff = new PNG({ // create a new PNG for holding the pixelmatch difference
width: maximumWidth,
height: maximumHeight
});
const numDiffPixels = pixelmatch(
boxedBuffer1,
boxedBuffer2,
diff.data,
maximumWidth,
maximumHeight,
{threshold: 0.05} // my favorite threshold to also consider lighter grays as differences
);
fs.writeFileSync('diff-boxed.png', PNG.sync.write(diff));
await sharp1.png().toFile('img1-boxed.png');
await sharp2.png().toFile('img2-boxed.png');
Example
$ node pixelmatch-different-size.mjs
numDiffPixels: 69302
from pixelmatch.
Currently no easy way to compare differently sized images, but it's possible to prepare for it manually if you slice out the relevant pixels from a bigger image before feeding to pixelmatch
. Something like this:
var croppedImage = new Uint8Array(4 * smallerHeight * smallerWidth);
for (var y = 0; y < smallerHeight; y++) {
for (var x = 0; x < smallerWidth; x++) {
var i = (y * biggerWidth + x) * 4;
var j = (y * smallerWidth + x) * 4;
croppedImage[j + 0] = biggerImage[i + 0];
croppedImage[j + 1] = biggerImage[i + 1];
croppedImage[j + 2] = biggerImage[i + 2];
croppedImage[j + 3] = biggerImage[i + 3];
}
}
from pixelmatch.
here is my minimal-dependency solution to the problem:
/** Creates a diff of the given input images, which may have different sizes.
* @param {PNG} img1
* @param {PNG} img2
* @param {pixelmatch.PixelmatchOptions} options
* @returns {{diff: PNG, numOfDiffPixels: number}}
*/
function createDiff(img1, img2, options) {
const diffDimensions = {
width: Math.max(img1.width, img2.width),
height: Math.max(img1.height, img2.height),
};
const resizedImg1 = createResized(img1, diffDimensions);
const resizedImg2 = createResized(img2, diffDimensions);
const diff = new PNG(diffDimensions);
const numOfDiffPixels = pixelmatch(
resizedImg1.data,
resizedImg2.data,
diff.data,
diffDimensions.width,
diffDimensions.height,
options,
);
return {diff, numOfDiffPixels};
}
/** Cretes a copy of {@link img}, with the {@link dimensions}.
* @param {PNG} img
* @param {{width: number, height: number}} dimensions
* @returns {PNG}
*/
function createResized(img, dimensions) {
if(img.width > dimensions.width || img.height > dimensions.height) {
throw new Error(`New dimensions expected to be greater than or equal to the original dimensions!`);
}
const resized = new PNG(dimensions);
PNG.bitblt(img, resized, 0, 0, img.width, img.height);
return resized;
}
from pixelmatch.
here is my minimal-dependency solution to the problem:
This works really well, @htho and @Abdull -- thank you for posting your implementations. Setting an automatically sized, common-dimensions canvas as a starting point and comparing from 0,0 is a great solution.
from pixelmatch.
I have had luck with subimage-match. It allows different sizes of images and is basically developed around this repo's method and efficiency.
Not to steal credits though... just for the sake of helping on this issue.
from pixelmatch.
Looking at the arguments of Pixelmatch, it is very unlikely to ever support different image sizes out-of-the box.
Pixelmatch operates on Buffers. It does not care where these buffers come from, it does not create new ones.
Pixelmatch receives two Buffers of input-image data.
In these Buffers, 4 bytes of data make a pixel. Buffers are 1-Dimensional. There is no information about the width and the height of the images stored in these buffers. Width and height are meta-data.
We provide a Buffer for the output diff.
We need to provide the dimensions Pixelmatch uses to interpret these Buffers.
Pixelmatch does one thing. I like that.
from pixelmatch.
Excuse me,Does it support the comparison of two images of different sizes, Now? if so how to set it
from pixelmatch.
Hi @zinen , look like subimage-match can't handle different sizes of images by some scenarios, for example, my case is the capture the image from different iPhone model iOS simulator, subimage-match
can't handle this case, for example, capture the same image from iPhone 11 pro iOS simulator and iPhone 14 Pro Max iOS simulator.
from pixelmatch.
Related Issues (20)
- The problem is me or the lib? HOT 2
- Image data: Uint8Array, Uint8ClampedArray or Buffer expected. HOT 3
- Comparing two pictures with different text returns no diff HOT 2
- View
- Sam
- Avoid generating diff images with no differences in it
- way to merge the diff HOT 1
- Image accuracy
- Weird comparator behaviour. HOT 1
- True or false for same image? HOT 2
- How can I group the differences or determine if there is a common change among them? HOT 1
- install in browser not work HOT 3
- Change Rate Limit Request HOT 1
- Can you provide an executable file for a windows? HOT 1
- can i get quantitative value? HOT 1
- CDN script error: module not defined HOT 2
- Following the doc but "Image data: Uint8Array, Uint8ClampedArray or Buffer expected." is still thrown. HOT 2
- CommonJS based require throws error HOT 1
- PixelMatch leakinng Data Buffer HOT 1
- Typescript support
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from pixelmatch.