mapbox / pixelmatch

The smallest, simplest and fastest JavaScript pixel-level image comparison library
ISC License
6.1k stars 304 forks source link

I cant get a correct Matching Image. #97

Closed CaiIsProgrammer closed 2 years ago

CaiIsProgrammer commented 3 years ago

So im trying to compare these images but its not getting the correct one.

async function compareHashTest(type, image, sku) {
  try {
    const path1 = path.resolve(__dirname, `../images/sku/${type}${sku}`);
    const path2 = path.resolve(__dirname, `../images/temp/${type}${image}`);
    const pngPath1 = path.resolve(
      __dirname,
      `../images/sku/${type}${sku.split(".jpg")[0]}.png`
    );
    const pngPath2 = path.resolve(
      __dirname,
      `../images/temp/${type}${image.split(".jpg")[0]}.png`
    );

    let image1 = await sharp(path1).toFile(pngPath1);

    const img1 = PNG.sync.read(fs.readFileSync(pngPath1));

    const { width, height } = img1;

    let image2 = await sharp(path2).resize({ width, height }).toFile(pngPath2);

    const img2 = PNG.sync.read(fs.readFileSync(pngPath2));

    let diff = new PNG({ width, height });

    let num = pixelmatch(img1.data, img2.data, diff.data, width, height, {
      threshold: 0.5,
    });
    console.log("num", num);
    diff = null;
    return num;
  } catch (e) {
    console.log("error", e);
    return 1;
  }
}

How im comparing and these are the images getting lowest number

Find Match Image : https://images.accessgrantedonline.com/Cardid_DHG_1_220693.jpg - image using to match

Test Images: https://c1.scryfall.com/file/scryfall-cards/normal/front/e/9/e95756ee-e76b-44e9-a13f-6125ee097ce7.jpg?1580561471 https://c1.scryfall.com/file/scryfall-cards/normal/front/7/d/7d24b200-5cab-406a-a0e6-71a4d33b26fb.jpg?1592765261 https://c1.scryfall.com/file/scryfall-cards/normal/front/5/3/53d2260a-e001-4d03-a108-759591e4d233.jpg?1543676327

Image matched was https://c1.scryfall.com/file/scryfall-cards/normal/front/5/3/53d2260a-e001-4d03-a108-759591e4d233.jpg?1543676327

Expected Match https://c1.scryfall.com/file/scryfall-cards/normal/front/e/9/e95756ee-e76b-44e9-a13f-6125ee097ce7.jpg?1580561471

towfiqi commented 2 years ago

Same happening here. Resizing with sharp before comparing throws "Size doesn't match" error by pixelmatch.

FoxxMD commented 2 years ago

@towfiqi did you resolve the resize issue? I'm encountering the same problem.

towfiqi commented 2 years ago

nope. Gave up on it.

FoxxMD commented 2 years ago

I got it working...for posterity here is what is needed to make sure your images work with pixelmatch using sharp:

Ensure images are actually the same dimensions USING SHARP

Do not rely on EXIF metadata extracted by third-party libraries or dimensions reported from image source (api, etc..) or other libraries

For an unmodified sharp instance use metadata()

const {width, height} = await sharpImg.metadata();

For a modified sharp instance (where you've done operations) you need to get either:

the OutputInfo object from outputting an image. EX using toBuffer

const { info: { width, height }, data }  = await sharpImg.toBuffer({ resolveWithObject: true })

or output your image into a new sharp instance and get metadata() (if you need dimensions and want to do more edits afterwards)

const newImg = sharp(await oldSharpImg.toBuffer());
const {width, height} = await newImg.metadata();

Ensure output to pixelmatch has an alpha channel

When pixelmatch is checking "exactness" it assumes the passed data has alpha channel. Alpha channel does not exist on jpeg and doesn't always exist on png (afaik). So when doing final output to use with pixelmatch:

const outForPixel1 = await sharpImg.ensureAlpha().toBuffer();
const outForPixel2 = await sharpImg.ensureAlpha().toBuffer();
const diffPixels = pixelmatch(outForPixel1, outforPixel2, null, widthFromMeta, heightFromMeta);

Note: Not sure if necessary but I always output file type as raw() as well so

await sharpImg.ensureAlpha().raw().toBuffer()

That should be sufficient to get pixelmatch to play nice. Outside the scope of this here are some other things I do in my project to get both images (using sharp) to the same dimensions and ready to compare with pixelmatch:

towfiqi commented 2 years ago

Many Thanks! I will give it a try and see if it works.