npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@graciousstar/opencv5

v0.1.0

Published

A few OpenCV 5 vision ops on raw image buffers - colorConvert, resize, filter, crop, rotate, ORB+ECC imageAlign - as a prebuilt N-API addon: async, bounds-checked, the same bytes on every CPU.

Readme

@graciousstar/opencv5

A few OpenCV 5 vision ops on raw image buffers, as a prebuilt N-API addon: colour conversion, resize, Otsu and Sobel filters, crop, rotate, and an ORB + ECC affine alignment. Not general OpenCV bindings - the ops node-red-contrib-vision-tools needs, done well:

  • Prebuilt, no toolchain. One binary per platform: Linux x64 and arm64 (glibc 2.17+ and musl), Windows x64, macOS x64 and arm64, each built and tested on its own CI runner. No install script; each binary's size and SHA-256 are checked against prebuilds/manifest.json before it is opened.
  • Any CPU of its arch, the same bytes on all. Built for the baseline (x86-64-v2: SSE4.2 + POPCNT; arm64: NEON) with nothing chosen at run time, no fast-math and no FMA contraction. test/expected.json pins every op's output bytes per arch, and each OS's binary of that arch must reproduce them (on x64, Linux glibc, Linux musl and Windows do).
  • Async, bounds-checked, and never sharing a buffer with a pool thread. Every op runs on libuv's pool and returns a promise. Every argument is checked before native code touches a byte; the input is copied into the addon's own memory before the op is queued, and every reply is a new buffer, so a caller may reuse, rewrite or even transfer its buffers the moment a call returns; no op writes to an input. The copy costs about 1.2 ms for a 10 MB RGB frame (reused staging memory: no page faults), and a queued op's copy counts as V8 external memory until it completes.
  • Small. A static OpenCV of six modules (core, imgproc, features, flann, geometry, video) and no codecs: 5-7 MB a binary, 2-2.8 MB gzipped. Encoded images go through sharp.
const cv = require("@graciousstar/opencv5");
const { image } = await cv.resize(
	{ data, width: 4000, height: 3000, channels: 3, colorSpace: "RGB", dtype: "uint8" },
	"num", 1000, "num", 0, "raw",
);

API

Images are raw descriptors, { data, width, height, channels, colorSpace, dtype }: data a Buffer or Uint8Array of at least width * height * channels bytes, channels 1, 3 or 4, colorSpace GRAY, RGB, RGBA, BGR or BGRA, dtype uint8. Every op returns a promise of { image, timing }, with image a new raw descriptor - or an encoded Buffer when fmt is jpg, png or webp (through sharp; quality applies to jpg and webp). fmt raw (or omitted) returns raw.

| op | does | |---|---| | colorConvert(image, target, [fmt], [quality]) | cvtColor to target (any pair of the colour spaces above); a copy when they match. image may also be an encoded Buffer (jpg/png/webp/tiff..., decoded by sharp at its own channel count, grey + alpha as RGBA, no EXIF rotation). | | resize(image, wMode, w, hMode, h, [fmt], [quality]) | INTER_LINEAR. Mode num is pixels, pct a percentage, scale a factor; a 0 on one side keeps the aspect ratio. | | filter(image, type, kernel, intensity, [fmt], [quality]) | otsu: Gaussian blur (kernel 3-31, sigma 0) then Otsu threshold to a 0/255 mask; the reply also carries blurred, the blurred grey as a raw image (the bridge this replaces wrote it back over the caller's input instead - nothing here does); edge: Sobel magnitude, |gx|/2 + |gy|/2 times intensity, kernel 3-7 (a chosen bound, not a correctness limit). A colour input is taken to grey first. | | crop(image, x, y, w, h, normalized, [fmt], [quality]) | A copy of the rect, clamped into the frame; normalized reads x/y/w/h as fractions of the frame. Non-numbers are TypeErrors, NaN or infinite values and a non-positive size RangeErrors. | | rotate(image, angleDeg, [padColor], [fmt], [quality]) | getRotationMatrix2D(centre, angleDeg) into a canvas grown to hold the rotated frame (each side Math.trunc of the rotated extent), re-centred; bilinear, the border in padColor (#rrggbb; a grey image takes its luma). | | imageAlign(reference, target, scale, iterations, epsilon, fmt, quality, pngOptimize, returnImage, polygon, motion, pipeline, eccRefine, detector) | Grey images. ORB (800 features, 1.2, 5 levels) on copies at scale, Lowe ratio 0.75, estimateAffine2D (USAC MAGSAC, 5 px), then ECC (iterations, epsilon) from that seed - skipped in eccRefine auto when the seed has 50 inliers or more. Returns { success, image, transformMatrix: { matrix2x3 }, inliers, timing }: the matrix maps reference coordinates into the target resized to the reference's size; image is the target warped onto the reference (nearest neighbour, 0 outside). Only affine, features+ecc, orb and no polygon are supported; anything else is refused. iterations is 1-500, and the alignment copy at scale must be at least 32 px a side (ORB's pyramid): either is otherwise a RangeError. |

The argument positions are those of the @rosepetal/node-red-contrib-image-tools cpp-bridge, which this replaces. pngOptimize true compresses a png output harder (zlib 9, adaptive filtering), false fast (zlib 1).

Raw data must be a Buffer, Uint8Array or Uint8ClampedArray (a Float32Array or DataView is a TypeError), and not a resizable or growable store; inputs are capped at 65536 px a side and 1 GiB, outputs at 64 megapixels and 16384 px a side.

imageAlign finds a reference's ORB features once, keyed by the reference's content (a 64-bit hash of every byte, about 0.3 ms for 3 MP, then a byte-for-byte compare against the kept copy before it is reused, about as much again: the hash is fast, not collision-proof), and keeps the four most recently used: a reference rewritten in place is a new reference, and a caller cycling through scales or references does not keep each alive. A golden whose features OpenCV cannot find keeps that error; running out of memory while finding them is not kept, and the next align tries again.

Also: load() (the addon, or a throw saying why it does not load here), available(), ready(), candidates() (the binary paths it would try).

OPENCV5_ADDON=/path/to/opencv5.node loads that binary instead, unchecked

  • for a local build (a path that does not exist says so). A binary that does not load is remembered for the process, as nothing that decides it changes while it runs; _reset() forgets it.

The shipped binaries (prebuilds/manifest.json holds their sizes and SHA-256). The Linux ones rebuild to the same bytes with native/prebuild-linux.sh; the Windows and macOS ones are the bytes their CI runners built and tested:

| binary | bytes | SHA-256 | |---|---|---| | darwin-arm64/opencv5.node | 5626464 | 3999167e780a6dee727f9b8de0cc372203da442df349fe6a26f3ca85fc395f5e | | darwin-x64/opencv5.node | 6345192 | 07715f090d869ad25ff3cde48bc68c598c02c76e5381f841dbb9c677b3839c2e | | linux-arm64/opencv5.glibc.node | 5713872 | e5110226df2ab1329e1a53c5f5b7a7ff3ebec3d93a0afa60fb2dd5b1b7b92d4c | | linux-arm64/opencv5.musl.node | 6039456 | d8875969aa6218009b6f3c277eebb7482281aec71738db298c70620030a2f359 | | linux-x64/opencv5.glibc.node | 6524632 | 4602771f58da4180f96c5e60c9198de747b4febf1f26b62350de3ed9f628f899 | | linux-x64/opencv5.musl.node | 7026640 | db20ed3aab037ef282dc25b1376ad733faad13a040a072cffe93c2aa77098aec | | win32-x64/opencv5.node | 5049856 | 578a2818a245ba9450d3047e61bcebd513fd065646debce8283228170058c445 |

Building

sh native/prebuild-linux.sh x64|arm64 glibc|musl   # docker; pinned images, cached OpenCV
OPENCV_PREFIX=... npx node-gyp rebuild             # Windows, in native/ (after build-opencv.sh)
sh native/build.sh OUT.node NODE_INCLUDE OPENCV_PREFIX   # macOS / any Unix
node native/manifest.js                            # rewrite prebuilds/manifest.json

native/build-opencv.sh builds the static OpenCV 5.0.0 from its release tarball (SHA-256 pinned in prebuild-linux.sh): 85 s in manylinux2014, 150 s in musllinux, 90 s with MSVC on 16 threads. Two clean Linux builds give the same bytes; CI (.github/workflows/prebuild.yml, once this is its own repository) rebuilds the x64 ones and fails on any difference from the manifest. node native/manifest.js --complete runs before npm publish and refuses a package without all seven binaries.

Licence

Apache-2.0. The binaries link OpenCV (Apache-2.0), FLANN, Berkeley SoftFloat, fdlibm and zlib: see NOTICE.