High-performance OpenCV bindings for Node.js, implemented in Rust via napi-rs. All heavy operations run off the main thread using native async tasks — the event loop is never blocked.
Matclass — Core matrix type: create, clone, copy, convert, reshape, and access raw pixel data- Image I/O —
imread,imwrite,imencode,imdecode(async, non-blocking) - Image processing — resize, color conversion, blur (Gaussian / median / bilateral), threshold (including adaptive), morphology (dilate, erode, open, close, gradient, top-hat, black-hat), Canny edge detection, Sobel/Laplacian derivatives, histogram equalization, border padding, and more
- Arithmetic & logic —
add,subtract,multiply,absDiff,addWeighted,bitwiseAnd,bitwiseOr,bitwiseNot, channelsplit/merge,normalize,hconcat/vconcat,countNonZero,mean - Geometric transforms —
warpAffine,warpPerspective,flip,crop,getRotationMatrix2D,getAffineTransform,getPerspectiveTransform - Feature detection —
findContours,contourArea,arcLength,boundingRect,minAreaRect,convexHull,approxPolyDP,moments,goodFeaturesToTrack,houghLines,houghLinesP,houghCircles - Template matching —
matchTemplate,matchTemplateAllwith built-in NMS - Drawing —
drawLine,drawRectangle,drawCircle,drawEllipse,drawContours,fillPoly,putText - DNN —
Netclass with support for ONNX, Caffe and Darknet models;blobFromImage,nmsBoxes - Video —
VideoCapture(file & camera) andVideoWriter - Fully typed — Complete TypeScript declarations included (
index.d.ts) - Non-blocking — Every async method accepts an optional
AbortSignalfor cancellation
| Dependency | Version |
|---|---|
| Node.js | ≥ 18 |
| OpenCV | 4.x |
| libclang | any recent version (build-time only) |
Linux:
sudo apt install libopencv-dev libclang-devmacOS:brew install opencv llvmWindows: Install OpenCV 4 and setOPENCV_INCLUDE_PATHS,OPENCV_LINK_LIBS,OPENCV_LINK_PATHSenvironment variables.
Prebuilt binaries are published for Linux x64 (glibc) and Windows x64 (MSVC). No Rust toolchain required for these platforms.
npm install node-opencv-rsIf a prebuilt binary is not available for your platform, npm install will attempt to compile from source — see Building from Source.
const cv = require('node-opencv-rs');
// Read an image
const mat = await cv.imread('./photo.jpg');
console.log(mat.rows, mat.cols, mat.channels); // e.g. 1080 1920 3
// Convert to grayscale and write back
const gray = await mat.cvtColor(cv.ColorCode.Bgr2Gray);
await cv.imwrite('./gray.png', gray);
// Template matching
const template = await cv.imread('./template.png');
const matches = await mat.matchTemplateAll(template, cv.TemplateMatchMode.CcoeffNormed, 0.85, 0.1);
console.log(matches); // [{ x, y, width, height }, ...]
// DNN inference (ONNX)
const net = cv.Net.readNetFromOnnx('./model.onnx');
net.setPreferableBackend(cv.DnnBackend.OpenCv);
net.setPreferableTarget(cv.DnnTarget.Cpu);
const blob = await cv.blobFromImage(mat, 1 / 255.0, 640, 640);
net.setInput(blob);
const output = await net.forward();All async methods return
Promise<T>and accept an optionalAbortSignalas the last argument.
| Method | Description |
|---|---|
new Mat() |
Create an empty matrix |
Mat.zeros(rows, cols, type) |
Create a zero-filled matrix |
Mat.ones(rows, cols, type) |
Create a matrix filled with ones |
Mat.eye(rows, cols, type) |
Create an identity matrix |
Mat.fromBuffer(rows, cols, type, buf) |
Create a matrix from a raw Buffer |
.rows / .cols / .channels |
Dimensions |
.matType / .depth / .elemSize |
Type info |
.empty |
Whether the matrix is empty |
.size |
{ width, height } |
.total |
Total number of elements |
.data |
Raw pixel data as Buffer |
.clone() |
Deep copy |
.copyTo(dst) |
Copy into another Mat |
.convertTo(rtype, alpha?, beta?) |
Convert element type |
.reshape(cn, rows?) |
Reshape without copying data |
.release() |
Explicitly free memory |
| Async image ops | cvtColor, resize, gaussianBlur, medianBlur, bilateralFilter, threshold, canny, dilate, erode, morphologyEx, warpAffine, warpPerspective, flip, crop, inRange, normalize, equalizeHist, copyMakeBorder, filter2D, sobel, laplacian |
| Async arithmetic | add, subtract, multiply, absDiff, addWeighted, bitwiseAnd, bitwiseOr, bitwiseNot, split, merge |
| Async analysis | matchTemplate, matchTemplateAll, minMaxLoc |
imread(path: string, flags?: ImreadFlag): Promise<Mat>
imwrite(path: string, mat: Mat): Promise<boolean>
imencode(ext: string, mat: Mat): Promise<Buffer> // e.g. '.png', '.jpg'
imdecode(buffer: Buffer, flags?: ImreadFlag): Promise<Mat>findContours(mat, mode: ContourRetrievalMode, method: ContourApproximation): Promise<Point[][]>
contourArea(contour: Point[]): Promise<number>
arcLength(contour: Point[], closed: boolean): Promise<number>
boundingRect(contour: Point[]): Promise<Rect>
minAreaRect(contour: Point[]): Promise<RotatedRect>
convexHull(points: Point[]): Promise<Point[]>
approxPolyDP(contour: Point[], epsilon: number, closed: boolean): Promise<Point[]>
moments(mat, binaryImage?: boolean): Promise<MomentsResult>
goodFeaturesToTrack(mat, maxCorners, qualityLevel, minDistance): Promise<PointF64[]>
houghLines(mat, rho, theta, threshold): Promise<HoughLine[]>
houghLinesP(mat, rho, theta, threshold, minLineLength?, maxLineGap?): Promise<LineSegment[]>
houghCircles(mat, dp, minDist, ...): Promise<Circle[]>drawLine(mat, pt1, pt2, color, thickness?, lineType?): Promise<Mat>
drawRectangle(mat, rect, color, thickness?, lineType?): Promise<Mat>
drawCircle(mat, center, radius, color, thickness?, lineType?): Promise<Mat>
drawEllipse(mat, center, axes, angle, startAngle, endAngle, color, ...): Promise<Mat>
drawContours(mat, contours, contourIdx, color, thickness?, lineType?): Promise<Mat>
fillPoly(mat, pts, color, lineType?): Promise<Mat>
putText(mat, text, org, fontFace, fontScale, color, thickness?, lineType?): Promise<Mat>// Load models
Net.readNetFromOnnx(path: string): Net
Net.readNetFromCaffe(protoPath: string, modelPath: string): Net
Net.readNetFromDarknet(cfgPath: string, weightsPath: string): Net
// Inference
net.setInput(blob: Mat, name?: string): void
net.forward(outputName?: string): Promise<Mat>
net.getUnconnectedOutLayersNames(): string[]
// Preprocessing
blobFromImage(image, scaleFactor?, width?, height?, mean?, swapRb?, crop?): Promise<Mat>
nmsBoxes(bboxes, scores, scoreThreshold, nmsThreshold): Promise<number[]>// Capture
const cap = VideoCapture.open('./video.mp4'); // or VideoCapture.open(0) for camera
cap.isOpened(): boolean
cap.read(): Promise<Mat | null> // null when stream ends
cap.get(propId: number): number // CAP_PROP_* constants
cap.set(propId: number, value: number): boolean
cap.release(): void
// Writer
const writer = VideoWriter.open('out.mp4', 'mp4v', 30, 1920, 1080);
writer.write(frame: Mat): void
writer.release(): voidinterface Point { x: number; y: number }
interface PointF64 { x: number; y: number }
interface Rect { x: number; y: number; width: number; height: number }
interface Size { width: number; height: number }
interface Scalar { v0: number; v1: number; v2: number; v3: number }
interface RotatedRect { center: PointF64; size: SizeF64; angle: number }Matrix type constants: CV_8U, CV_8UC1, CV_8UC2, CV_8UC3, CV_8UC4, CV_16U, CV_16S, CV_32S, CV_32F, CV_64F, …
Video capture constants: CAP_PROP_FPS, CAP_PROP_FRAME_WIDTH, CAP_PROP_FRAME_HEIGHT, CAP_PROP_FRAME_COUNT, CAP_PROP_POS_FRAMES, CAP_PROP_POS_MSEC, …
Enums: ColorCode, ImreadFlag, ThresholdType, InterpolationFlag, MorphType, MorphShape, BorderType, TemplateMatchMode, FlipCode, LineType, HersheyFont, NormType, DnnBackend, DnnTarget, ContourRetrievalMode, ContourApproximation, AdaptiveThresholdType
1. Install system dependencies
# Ubuntu / Debian
sudo apt-get install cmake libopencv-dev llvm clang libclang-dev
# macOS
brew install opencv llvm
# Windows — install OpenCV 4, then set:
# OPENCV_INCLUDE_PATHS, OPENCV_LINK_LIBS, OPENCV_LINK_PATHS2. Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh3. Clone and build
git clone https://github.com/luckyyyyy/node-opencv.git
cd node-opencv-rs
npm install
npm run build # release build (slower, optimised)
# or
npm run build:debug # debug build (faster, for development)
npm testOn Linux you may need to set
LIBCLANG_PATH:export LIBCLANG_PATH=/usr/lib/x86_64-linux-gnu
Contributions are welcome! Please open an issue or pull request.
- Keep async operations on
napi::AsyncTask— notokio::spawn. - Avoid unnecessary
.clone()calls. - Run
npm run build:debug && npm testbefore submitting.