mapbox / pixelmatch

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

Uncaught (in promise) Error: Image data: Uint8Array, Uint8ClampedArray or Buffer expected. #109

Closed github-jeff closed 2 years ago

github-jeff commented 2 years ago

I must be doing something errant. (Javascript Browser method)

import pixelmatch from "pixelmatch"

export default async function TextFromImage(imageElement, frameData, lastImage) {

  const scaleFactor = 4

  //create an offscreen canvas and crop the image
  var crop = document.createElement('canvas');
  crop.width = frameData.width * scaleFactor
  crop.height = frameData.height * scaleFactor
  var crop_x = crop.getContext('2d');

  const imageProcessing = crop_x.getImageData(0, 0, crop.width, crop.height);

  const origImg = imageProcessing
  console.log("origImg: ", imageProcessing)

  PreProcessFunctions(imageProcessing.data, frameData.name, destWidth, destHeight, grey, blur, dilate, invert, thresh, replace, threshLevel, rLevelMIN, rLevelMAX, gLevelMIN, gLevelMAX, bLevelMIN, bLevelMAX)

  const newImg = imageProcessing
  console.log("newImg: ", imageProcessing)

  const numDiffPixels = pixelmatch(origImg, newImg, {threshold: 0.1});
}

Console.log:

ImageData { width: 393, height: 120, data: Uint8ClampedArray(188640) }
​data: Uint8ClampedArray(188640) [ 255, 255, 255, … ]
​height: 120
​width: 393
​<prototype>: ImageDataPrototype { width: Getter, height: Getter, data: Getter, … }

ImageData { width: 393, height: 120, data: Uint8ClampedArray(188640) }
​data: Uint8ClampedArray(188640) [ 255, 255, 255, … ]
​height: 120
​width: 393
​<prototype>: ImageDataPrototype { width: Getter, height: Getter, data: Getter, … }

Error: Uncaught (in promise) Error: Image data: Uint8Array, Uint8ClampedArray or Buffer expected.

The images are the same size. I also tried added in diff using:

const diff = new Image()
const numDiffPixels = pixelmatch(origImg, newImg, diff, 393, 120, {threshold: 0.1});

Eventually I would like to use lastImage, but for now this function basically compares the original image before tesseract pre-processing to a new image after pre-processing. The images (orig and new) should be very different from each other but will still be the same size.

mourner commented 2 years ago

You're serving pixelmatch ImageData objects when it expects the actual data arrays. Try origImg.data and newImg.data along with the sizes. See the docs in the readme.

github-jeff commented 2 years ago

Thank you for getting back to me. Unfortunately, that does not seem to be working either. Please let me know if I am doing something incorrectly.

    ....
    const origImg = crop_x.getImageData(0, 0, crop.width, crop.height);
    console.log("origImg.data: ", origImg.data)

    PreProcessFunctions(imageProcessing.data, frameData.name, destWidth, destHeight, grey, blur, dilate, invert, thresh, replace, threshLevel, rLevelMIN, rLevelMAX, gLevelMIN, gLevelMAX, bLevelMIN, bLevelMAX)

    const newImg = crop_x.getImageData(0, 0, crop.width, crop.height);
    console.log("newImg.data: ", newImg.data)

    console.log("origImg: ", origImg)
    console.log("newImg: ", newImg)
    console.log("crop.width: ", crop.width)
    console.log("crop.height: ", crop.height)

    const dataUrl = crop.toDataURL("image/jpeg");

    const numDiffPixels = pixelmatch(origImg.data, newImg.data, crop.width, crop.height, {threshold: 0.1});
    console.log("numDiffPixels: ", numDiffPixels)
    ...

Console.log

origImg.data:  
  Uint8ClampedArray(188640) [ 21, 103, 46, 255, 20, 103, 45, 255, 20, 102, … ]

newImg.data:  
  Uint8ClampedArray(188640) [ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, … ]

origImg:  
ImageData { width: 393, height: 120, data: Uint8ClampedArray(188640) }
  ​data: Uint8ClampedArray(188640) [ 21, 103, 46, … ]
  height: 120
  ​width: 393
  ​<prototype>: ImageDataPrototype { width: Getter, height: Getter, data: Getter, … }

newImg:  
ImageData { width: 393, height: 120, data: Uint8ClampedArray(188640) }
  ​data: Uint8ClampedArray(188640) [ 255, 255, 255, … ]
  ​height: 120
  ​width: 393
  ​<prototype>: ImageDataPrototype { width: Getter, height: Getter, data: Getter, … }

crop.width:  393 
crop.height:  120

Error: Uncaught (in promise) Error: Image data: Uint8Array, Uint8ClampedArray or Buffer expected.

I have also tried defining diff as:

var diffElement = document.createElement('canvas');
    var diff_x = diffElement.getContext('2d');
    const diff = diff_x.createImageData(crop.width, crop.height);

or

const diff = new Image(crop.width, crop.height);

and used diff as:

const numDiffPixels = pixelmatch(origImg.data, newImg.data, diff, crop.width, crop.height, {threshold: 0.1});

Error: Uncaught (in promise) Error: Image data: Uint8Array, Uint8ClampedArray or Buffer expected.

In the end I do not need to know what diff is, if that is complicating things. I'm only going to be using the numDiffPixels with a threshold, but if diff needs to be in the call that is ok too.

github-jeff commented 2 years ago

Figured it out. Thank you. All is well.


const diff = new Image(crop.width, crop.height);
const numDiffPixels = pixelmatch(origImg.data, newImg.data, diff.data, crop.width, crop.height, {threshold: 0.1});

so diff.data absolutely needs to be in there, even if it's not going to be used.

mourner commented 2 years ago

@github-jeff you can supply null instead of diff, per the docs.