Skip to content
ColonelParrot edited this page Jul 19, 2024 · 10 revisions

Import

npm:

$ npm i jscanify
import jscanify from 'jscanify'

cdn:

<script src="https://docs.opencv.org/4.7.0/opencv.js" async></script>
<!-- warning: loading OpenCV can take some time. Load asynchronously -->
<script src="https://cdn.jsdelivr.net/gh/ColonelParrot/jscanify@master/src/jscanify.min.js"></script>

Snippets

Highlight Paper in Image

<img src="/path/to/your/image.png" id="image" />
const scanner = new jscanify();
image.onload = function () {
  const highlightedCanvas = scanner.highlightPaper(image);
  document.body.appendChild(highlightedCanvas);
};

Extract Paper

const scanner = new jscanify();
const paperWidth = 500;
const paperHeight = 1000;
image.onload = function () {
  const resultCanvas = scanner.extractPaper(image, paperWidth, paperHeight);
  document.body.appendChild(resultCanvas);
};

Highlighting Paper in User Camera

The following code continuously reads from the user's camera and highlights the paper:

<video id="video"></video>
<canvas id="canvas"></canvas>  <!-- original video -->
<canvas id="result"></canvas>  <!-- highlighted video -->
const scanner = new jscanify();
const canvasCtx = canvas.getContext("2d");
const resultCtx = result.getContext("2d");
navigator.mediaDevices.getUserMedia({ video: true }).then((stream) => {
  video.srcObject = stream;
  video.onloadedmetadata = () => {
    video.play();

    setInterval(() => {
      canvasCtx.drawImage(video, 0, 0);
      const resultCanvas = scanner.highlightPaper(canvas);
      resultCtx.drawImage(resultCanvas, 0, 0);
    }, 10);
  };
});

Core Methods

  • findPaperContour(mat) - returns cv.Mat - finds the contour of the paper within the image (of type cv.Mat)
  • highlightPaper(image, options) - returns HTMLCanvasElement - highlights the paper detected inside the image
  • extractPaper(image, resultWidth, resultHeight, cornerPoints?) - returns HTMLCanvasElement - extracts and undistorts the image detected within the frame
  • getCornerPoints(contour) - returns Object - calculates the corner points of a contour

Note: parameters with name img/image can be passed anything that OpenCV can process. This means HTMLImageElement, HTMLCanvasElement and Files (from file inputs)

findPaperContour(mat)

Finds the contour of the paper within img. img is of type cv.Mat.

Returns: cv.Mat containing the contour. This value should be passed to getCornerPoints to get the corner points of the contour

highlightPaper(image, options)

Highlights the piece of paper within image.

options accepts two properties:

  • color: any valid value for strokeStyle. Default orange
  • thickness: thickness of outline in pixels. Default 10

Returns: HTMLCanvasElement containing image with the outline draw on it.

extractPaper(image, resultWidth, resultHeight, cornerPoints?)

Extracts the piece of paper in image.

Undistorts the detected paper and scales it to the properly width (resultWidth) and height (resultHeight), both in pixels.

An HTMLCanvasElement will be returned. The canvas will contain the resulting piece of paper.

Note: prior to v1.2, extractPaper had an onComplete callback which received the canvas element as the only parameter.

By default the piece of paper is automatically detected and extracted. However, if automatic detection results are unsatisfactory, custom cornerPoints can optionally be provided. cornerPoints must be in the format:

{
    topLeftCorner: { x: ..., y: ... },
    topRightCorner: { x: ..., y: ... },
    bottomLeftCorner: { x: ..., y: ... },
    bottomRightCorner: { x: ..., y: ... },
}

getCornerPoints(contour)

Gets the corner points of the contour extracted with findPaperContour.

Returns: object containing corner points compliant with extractPaper's cornerPoints spec (see above).

Use on NodeJS

NodeJS does not have elements like HTMLCanvasElement or HTMLImageElement. As such, we simulate this with the canvas package. Don't worry - it's just as easy!

To read an image from a path, you should use the loadImage method from the canvas library:

import { loadImage } from 'canvas';

loadImage(path_to_image).then((image) => {
   const extracted = scanner.extractPaper(image, width, height) //...
   const highlighted = scanner.highlightPaper(image) //...
})

WATCH OUT!!! You will come across multiple confusing errors if you forget this: OpenCV must be loaded before any method is called. jscanify handles this natively. You must call loadOpenCV:

const scanner = new jscanify()
scanner.loadOpenCV(function(cv){
    scanner.extractPaper() //...
})

Do note, however, that the loading operation can take some time. This is normal.

More example uses can be seen in the test script. For instance, to write the result canvas to a file, see this line.

Full NodeJS Example

import jscanify from 'jscanify'
import { loadImage } from 'canvas'
import { writeFileSync } from 'fs';

const IMAGE_PATH = '/path/to/raw/image.png'
loadImage(IMAGE_PATH).then((image) => {
    const scanner = new jscanify()
    scanner.loadOpenCV(function(cv){
        const highlighted = scanner.highlightPaper(image)
        writeFileSync('.../output/highlighted.jpg', highlighted.toBuffer("image/jpeg"))
    })
})