-
Notifications
You must be signed in to change notification settings - Fork 306
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Compare different sized images? #25
Comments
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 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];
}
} |
…add-link-to-blog-post to master * commit '753c24cd7d6e4d387a62e25b2a46799aa44dfe2d': docs(readme): add link to tech blog post fix(package): support jest v23 (mapbox#81)
Excuse me,Does it support the comparison of two images of different sizes, Now? if so how to set it |
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. |
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, |
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
|
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;
} |
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. 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. |
Is there any option for comparing differently sized images? For example, a way to compare the sizes and add to the canvas size of the smaller size or would that still cause distorted or inaccurate diff results?
/cc @mourner
The text was updated successfully, but these errors were encountered: