@pkboom/opencv-nodejs
v1.0.5
Published
Asynchronous OpenCV 4.x nodejs bindings with JavaScript and TypeScript API.
Maintainers
Readme
@pkboom/opencv-nodejs
Getting started
opencv-nodejs is zero-configuration: install OpenCV from your platform's package manager, then install this module — that's it. There is no source build of OpenCV, no Docker image, and nothing to configure in package.json.
# macOS (OpenCV 5)
brew install opencv
# macOS (OpenCV 4)
brew install opencv@4
# Debian / Ubuntu (OpenCV 4.x)
sudo apt install libopencv-dev
# Windows (OpenCV 4.x)
choco install opencvnpm install --save @pkboom/opencv-nodejsnpm install builds the native addon automatically against whichever OpenCV it finds. See How to install for the full details, requirements, and troubleshooting.

opencv-nodejs allows you to use the native OpenCV library in nodejs. Besides a synchronous API the package provides an asynchronous API, which allows you to build non-blocking and multithreaded computer vision tasks. opencv-nodejs supports OpenCV 4 and OpenCV 5.
The ultimate goal of this project is to provide a comprehensive collection of nodejs bindings to the API of OpenCV and the OpenCV-contrib modules. To get an overview of the currently implemented bindings, have a look at the type declarations of this package. Furthermore, contribution is highly appreciated. If you want to add missing bindings check out the contribution guide.
- Examples
- How to install
- Usage with Electron
- Usage with NW.js
- Quick Start
- Async API
- With TypeScript
- External Memory Tracking (v4.0.0)
Examples
See examples for implementation.
Face Detection

Face Recognition with the OpenCV face module
Check out Node.js + OpenCV for Face Recognition.

Face Landmarks with the OpenCV face module

Face Recognition with face-recognition.js
Check out Node.js + face-recognition.js : Simple and Robust Face Recognition using Deep Learning.
Hand Gesture Recognition
Check out Simple Hand Gesture Recognition using OpenCV and JavaScript.

Object Recognition with Deep Neural Networks
Check out Node.js meets OpenCV’s Deep Neural Networks — Fun with Tensorflow and Caffe.
Tensorflow Inception

Single Shot Multibox Detector with COCO

Machine Learning
Check out Machine Learning with OpenCV and JavaScript: Recognizing Handwritten Letters using HOG and SVM.

Object Tracking

Feature Matching

Image Histogram

Boiler plate for combination of opencv-nodejs, express and websockets
opencv4nodejs-express-websockets - Boilerplate express app for getting started on opencv with nodejs and to live stream the video through websockets.
Automating lights by people detection through classifier
Check out Automating lights with Computer Vision & NodeJS.

How to install
npm install --save @pkboom/opencv-nodejsThe module's install lifecycle script runs node bin/install.js rebuild, which detects your OpenCV install (via Homebrew, pkg-config, or the usual distro locations) and compiles the native addon against it with node-gyp. There is no source build of OpenCV and nothing to configure — just install OpenCV first, from your package manager.
Native node modules are built via node-gyp, which already comes with npm by default. However, node-gyp requires you to have python installed. If you are running into node-gyp specific issues have a look at known issues with node-gyp first.
Important note: node-gyp won't handle whitespaces properly, thus make sure, that the path to your project directory does not contain any whitespaces. Installing opencv-nodejs under "C:\Program Files\some_dir" or similar will not work and will fail with: "fatal error C1083: Cannot open include file: 'opencv2/core.hpp'"!**
On Windows, you will furthermore need Visual Studio Build Tools to compile opencv-nodejs.
Requirements
- Node.js 24 or 26 (
engines.noderequires>=24.0.0) - OpenCV 4.x or OpenCV 5.x, installed from your platform's package manager
macOS
brew update
# OpenCV 5
brew install opencv
# OpenCV 4 (keg-only formula)
brew install opencv@4Both are detected automatically, no brew link step required.
Debian / Ubuntu
sudo apt install libopencv-devInstalls OpenCV 4.x.
Windows
choco install opencvInstalls OpenCV 4.x via the Chocolatey package manager.
OpenCV installed somewhere unusual
If OpenCV isn't found automatically (not installed via Homebrew, pkg-config, or a standard distro/Windows location), point opencv-nodejs at it directly:
export OPENCV_INCLUDE_DIR=/path/to/opencv/include
export OPENCV_LIB_DIR=/path/to/opencv/lib
npm install --save @pkboom/opencv-nodejsThe CLI
The module ships a small CLI for driving the build directly, also available via npm scripts (npm run info, npm run rebuild, npm run clean) and as the build-opencv bin once installed/linked:
node bin/install.js info # print the detected OpenCV install
node bin/install.js rebuild # build the native addon
node bin/install.js clean # remove build outputDebugging module loading
Set OPENCVNODEJS_DEBUG_REQUIRE=1 before requiring the module for verbose diagnostics about how it locates and loads the native addon.
Usage with Electron
opencv-electron - example for opencv-nodejs with electron
Add the following script to your package.json:
"electron-rebuild": "build-opencv --electron rebuild"Run the script:
npm run electron-rebuildRequire it in the application:
const cv = require('@pkboom/opencv-nodejs');Usage with NW.js
Any native modules, including opencv-nodejs, must be recompiled to be used with NW.js. Instructions on how to do this are available in the Use Native Modules section of the NW.js documentation.
Once recompiled, the module can be installed and required as usual:
const cv = require('@pkboom/opencv-nodejs');Quick Start
const cv = require('@pkboom/opencv-nodejs');Initializing Mat (image matrix), Vec, Point
const rows = 100; // height
const cols = 100; // width
// empty Mat
const emptyMat = new cv.Mat(rows, cols, cv.CV_8UC3);
// fill the Mat with default value
const whiteMat = new cv.Mat(rows, cols, cv.CV_8UC1, 255);
const blueMat = new cv.Mat(rows, cols, cv.CV_8UC3, [255, 0, 0]);
// from array (3x3 Matrix, 3 channels)
const matData = [
[[255, 0, 0], [255, 0, 0], [255, 0, 0]],
[[0, 0, 0], [0, 0, 0], [0, 0, 0]],
[[255, 0, 0], [255, 0, 0], [255, 0, 0]]
];
const matFromArray = new cv.Mat(matData, cv.CV_8UC3);
// from node buffer
const charData = [255, 0, ...];
const matFromArray = new cv.Mat(Buffer.from(charData), rows, cols, cv.CV_8UC3);
// Point
const pt2 = new cv.Point(100, 100);
const pt3 = new cv.Point(100, 100, 0.5);
// Vector
const vec2 = new cv.Vec(100, 100);
const vec3 = new cv.Vec(100, 100, 0.5);
const vec4 = new cv.Vec(100, 100, 0.5, 0.5);Mat and Vec operations
const mat0 = new cv.Mat(...);
const mat1 = new cv.Mat(...);
// arithmetic operations for Mats and Vecs
const matMultipliedByScalar = mat0.mul(0.5); // scalar multiplication
const matDividedByScalar = mat0.div(2); // scalar division
const mat0PlusMat1 = mat0.add(mat1); // addition
const mat0MinusMat1 = mat0.sub(mat1); // subtraction
const mat0MulMat1 = mat0.hMul(mat1); // elementwise multiplication
const mat0DivMat1 = mat0.hDiv(mat1); // elementwise division
// logical operations Mat only
const mat0AndMat1 = mat0.and(mat1);
const mat0OrMat1 = mat0.or(mat1);
const mat0bwAndMat1 = mat0.bitwiseAnd(mat1);
const mat0bwOrMat1 = mat0.bitwiseOr(mat1);
const mat0bwXorMat1 = mat0.bitwiseXor(mat1);
const mat0bwNot = mat0.bitwiseNot();Accessing Mat data
const matBGR = new cv.Mat(..., cv.CV_8UC3);
const matGray = new cv.Mat(..., cv.CV_8UC1);
// get pixel value as vector or number value
const vec3 = matBGR.at(200, 100);
const grayVal = matGray.at(200, 100);
// get raw pixel value as array
const [b, g, r] = matBGR.atRaw(200, 100);
// set single pixel values
matBGR.set(50, 50, [255, 0, 0]);
matBGR.set(50, 50, new Vec(255, 0, 0));
matGray.set(50, 50, 255);
// get a 25x25 sub region of the Mat at offset (50, 50)
const width = 25;
const height = 25;
const region = matBGR.getRegion(new cv.Rect(50, 50, width, height));
// get a node buffer with raw Mat data
const matAsBuffer = matBGR.getData();
// get entire Mat data as JS array
const matAsArray = matBGR.getDataAsArray();IO
// load image from file
const mat = cv.imread('./path/img.jpg');
cv.imreadAsync('./path/img.jpg', (err, mat) => {
...
})
// save image
cv.imwrite('./path/img.png', mat);
cv.imwriteAsync('./path/img.jpg', mat, (err) => {
...
})
// show image
cv.imshow('a window name', mat);
cv.waitKey();
// load base64 encoded image
const base64text='data:image/png;base64,R0lGO..';//Base64 encoded string
const base64data =base64text.replace('data:image/jpeg;base64','')
.replace('data:image/png;base64','');//Strip image type prefix
const buffer = Buffer.from(base64data,'base64');
const image = cv.imdecode(buffer); //Image is now represented as Mat
// convert Mat to base64 encoded jpg image
const outBase64 = cv.imencode('.jpg', croppedImage).toString('base64'); // Perform base64 encoding
const htmlImg='<img src=data:image/jpeg;base64,'+outBase64 + '>'; //Create insert into HTML compatible <img> tag
// open capture from webcam
const devicePort = 0;
const wCap = new cv.VideoCapture(devicePort);
// open video capture
const vCap = new cv.VideoCapture('./path/video.mp4');
// read frames from capture
const frame = vCap.read();
vCap.readAsync((err, frame) => {
...
});
// loop through the capture
const delay = 10;
let done = false;
while (!done) {
let frame = vCap.read();
// loop back to start on end of stream reached
if (frame.empty) {
vCap.reset();
frame = vCap.read();
}
// ...
const key = cv.waitKey(delay);
done = key !== 255;
}Useful Mat methods
const matBGR = new cv.Mat(..., cv.CV_8UC3);
// convert types
const matSignedInt = matBGR.convertTo(cv.CV_32SC3);
const matDoublePrecision = matBGR.convertTo(cv.CV_64FC3);
// convert color space
const matGray = matBGR.bgrToGray();
const matHSV = matBGR.cvtColor(cv.COLOR_BGR2HSV);
const matLab = matBGR.cvtColor(cv.COLOR_BGR2Lab);
// resize
const matHalfSize = matBGR.rescale(0.5);
const mat100x100 = matBGR.resize(100, 100);
const matMaxDimIs100 = matBGR.resizeToMax(100);
// extract channels and create Mat from channels
const [matB, matG, matR] = matBGR.splitChannels();
const matRGB = new cv.Mat([matR, matB, matG]);Drawing a Mat into HTML Canvas
const img = ...
// convert your image to rgba color space
const matRGBA = img.channels === 1
? img.cvtColor(cv.COLOR_GRAY2RGBA)
: img.cvtColor(cv.COLOR_BGR2RGBA);
// create new ImageData from raw mat data
const imgData = new ImageData(
new Uint8ClampedArray(matRGBA.getData()),
img.cols,
img.rows
);
// set canvas dimensions
const canvas = document.getElementById('myCanvas');
canvas.height = img.rows;
canvas.width = img.cols;
// set image data
const ctx = canvas.getContext('2d');
ctx.putImageData(imgData, 0, 0);Method Interface
OpenCV method interface from official docs or src:
void GaussianBlur(InputArray src, OutputArray dst, Size ksize, double sigmaX, double sigmaY = 0, int borderType = BORDER_DEFAULT);translates to:
const src = new cv.Mat(...);
// invoke with required arguments
const dst0 = src.gaussianBlur(new cv.Size(5, 5), 1.2);
// with optional paramaters
const dst2 = src.gaussianBlur(new cv.Size(5, 5), 1.2, 0.8, cv.BORDER_REFLECT);
// or pass specific optional parameters
const optionalArgs = {
borderType: cv.BORDER_CONSTANT
};
const dst2 = src.gaussianBlur(new cv.Size(5, 5), 1.2, optionalArgs);Async API
The async API can be consumed by passing a callback as the last argument of the function call. By default, if an async method is called without passing a callback, the function call will yield a Promise.
Async Face Detection
const classifier = new cv.CascadeClassifier(cv.HAAR_FRONTALFACE_ALT2);
// by nesting callbacks
cv.imreadAsync('./faceimg.jpg', (err, img) => {
if (err) { return console.error(err); }
const grayImg = img.bgrToGray();
classifier.detectMultiScaleAsync(grayImg, (err, res) => {
if (err) { return console.error(err); }
const { objects, numDetections } = res;
...
});
});
// via Promise
cv.imreadAsync('./faceimg.jpg')
.then(img =>
img.bgrToGrayAsync()
.then(grayImg => classifier.detectMultiScaleAsync(grayImg))
.then((res) => {
const { objects, numDetections } = res;
...
})
)
.catch(err => console.error(err));
// using async await
try {
const img = await cv.imreadAsync('./faceimg.jpg');
const grayImg = await img.bgrToGrayAsync();
const { objects, numDetections } = await classifier.detectMultiScaleAsync(grayImg);
...
} catch (err) {
console.error(err);
}With TypeScript
import cv from '@pkboom/opencv-nodejs'Check out the TypeScript examples.
External Memory Tracking (v4.0.0)
Since version 4.0.0 was released, external memory tracking has been enabled by default. Simply put, the memory allocated for Matrices (cv.Mat) will be manually reported to the node process. This solves the issue of inconsistent Garbage Collection, which could have resulted in spiking memory usage of the node process eventually leading to overflowing the RAM of your system, prior to version 4.0.0.
Note, that in doubt this feature can be disabled by setting an environment variable OPENCVNODEJS_DISABLE_EXTERNAL_MEM_TRACKING before requiring the module:
export OPENCVNODEJS_DISABLE_EXTERNAL_MEM_TRACKING=1 // linux
set OPENCVNODEJS_DISABLE_EXTERNAL_MEM_TRACKING=1 // windowsOr directly in your code:
process.env.OPENCVNODEJS_DISABLE_EXTERNAL_MEM_TRACKING = 1
const cv = require('@pkboom/opencv-nodejs')
