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

@wasmedia/wopencv

v0.1.0

Published

OpenCV compiled to WebAssembly for browsers

Readme

wopencv

WebAssembly build of OpenCV, pinned to 4.14.0, scoped as the computer-vision stage of the wasmedia photo pipeline. Single-threaded + SIMD, no SharedArrayBuffer, no COOP/COEP headers — works on any site, following the house pattern of sibling ports wvips and wlensfun.

How this differs from opencv.js

OpenCV already ships an official WASM build, opencv.js. wopencv is not a replacement for it and does not try to be. There is no Mat class at the JS boundary and no way to call an arbitrary cv:: function — wopencv exposes a small, curated, strongly-typed task API over the specific operations the wasmedia sibling ports need (geometry, features and homography, computational photography, automatic stitching, detection), each taking and returning plain pixel buffers.

If you want general-purpose access to OpenCV's API from the browser, use opencv.js instead. wopencv's small export table (curated rather than generated) is what lets dead-code elimination keep the binary small; that trade is the whole reason this project exists rather than just depending on upstream.

Status

The core bundle's capabilities are complete. Geometry, colour, feature detection, matching, model fitting, HDR, computational photography, dense optical flow and automatic stitching exist, built as a core bundle (dist/wopencv.{js,wasm}) plus a detection bundle (dist/wopencv-detect.{js,wasm}): remap, resize, warpAffine, warpPerspective, cvtColor, convertDepth, detectFeatures, matchFeatures, findHomography, estimateAffinePartial2D, mergeExposures, mergeDebevec, tonemap, denoise, inpaint, seamlessClone, detailEnhance, edgePreservingFilter, opticalFlowFarneback, flowToMap, createStitcher/Stitcher.stitch, and the stitching stages one by one for layers warped elsewhere: compensateExposure, findSeams and multibandBlend. Detection is complete too, in its own entry point: loadCascade (Haar cascades) and loadFaceDetector (YuNet), imported from @wasmedia/wopencv/detect. Both run off the main thread in the Web Worker at @wasmedia/wopencv/worker, driven by WOpencvWorker, and npm run playground serves a page that uses it. PixelBuffer is validated at runtime, not just at compile time. See briefs/INITIAL.md for the roadmap and design rationale.

Installation

npm install @wasmedia/wopencv

Models and cascades used by detection features are not bundled in the npm package. Their licences are permissive (BSD-3-Clause-style for the cascades, MIT for YuNet), so bundling them would be lawful. They are fetched separately to keep the package small and let model versions move independently of releases, as a deliberate manual step that is not part of install or build, into a local directory. You pass their bytes in, and wopencv mounts them into the wasm module's virtual filesystem:

npx wopencv-fetch-models

It writes models/ and a THIRD-PARTY-LICENSES.md, and you pass the bytes to loadCascade and loadFaceDetector.

Usage

The shape wopencv is building toward — stateless tasks as one-shot functions, stateful things (feature sets, stitcher, DNN net) as handles with explicit disposal:

import { initWOpencv } from '@wasmedia/wopencv';

const cv = await initWOpencv();

// The data contract: tightly packed, RGB(A) at the boundary.
interface PixelBuffer {
  data: Uint8Array | Uint16Array | Float32Array;
  width: number;
  height: number;
  channels: number;
  depth: 'u8' | 'u16' | 'f32';
}

// Stateless tasks are one-shot functions.
const smaller = cv.resize(img, { width: 1024 });
const clean   = cv.denoise(img, { strength: 7 });
const fused   = cv.mergeExposures([under, mid, over]);   // Mertens
const display = cv.tonemap(cv.mergeDebevec(stack, times), { method: 'reinhard' });

// The wlensfun composition point: apply someone else's correction maps.
const corrected = cv.remap(img, { mapX, mapY, interpolation: 'linear' });

// Stateful things are handles with explicit disposal.
const a = cv.detectFeatures(left,  { detector: 'akaze' });
const b = cv.detectFeatures(right, { detector: 'akaze' });
const matches = cv.matchFeatures(a, b, { ratio: 0.75 });
const fit = cv.findHomography(matches, { method: 'ransac' });
if (fit) { const { matrix, inliers } = fit; /* … */ }
a.dispose(); b.dispose();

// The automatic panorama path.
const stitcher = cv.createStitcher({ mode: 'panorama' });
const result = stitcher.stitch([left, mid, right]);   // { ok: true, image } | { ok: false, status }
stitcher.dispose();

// Errors are thrown, and the module survives them.
try { cv.resize(img, { width: -1 }); }
catch (e) { /* WOpencvError — cv is still usable */ }

Every call in the sketch above works today. Detection is a separate bundle with its own import, and takes model bytes you fetched with npx wopencv-fetch-models:

import { readFile } from 'node:fs/promises';
import { initWOpencvDetect } from '@wasmedia/wopencv/detect';

const det = await initWOpencvDetect();
const faces = det.loadFaceDetector(
  new Uint8Array(await readFile('models/face_detection_yunet_2023mar.onnx')),
);
const found = faces.detect(img);   // [{ x, y, width, height, score, landmarks }]
faces.dispose();

In a browser, run it in a Web Worker so no operation blocks the page. Each bundle loads in the worker on first use, and results' buffers are transferred rather than copied:

import { WOpencvWorker } from '@wasmedia/wopencv/worker-client';

const cv = new WOpencvWorker(() =>
  new Worker(new URL('@wasmedia/wopencv/worker', import.meta.url), { type: 'module' }));
const small = await cv.call('resize', img, { width: 1024 });
const pano = await cv.stitch([left, mid, right]);
const yunet = await cv.loadFaceDetector(yunetBytes);
const found = await cv.detect(yunet, img);
await cv.release(yunet);

Errors reject as WOpencvError, rebuilt on the page. If your bundler does not resolve new URL('@wasmedia/wopencv/worker', import.meta.url), see Worker in docs/api.md for alternatives.

See docs/api.md for exactly what ships:

import { initWOpencv } from '@wasmedia/wopencv';

const cv = await initWOpencv();
const gray = cv.cvtColor(image, 'rgb2gray');
const half = cv.resize(gray, { width: Math.round(gray.width / 2) });

Building from source

All native compilation happens inside Docker; see docs/building.md for the full build and size-budget notes.

npm install
npm run build
npm test

npm test downloads the detection models into models/ on its first run (see docs/building.md); after that it runs offline.

Family boundaries

wopencv owns the automatic panorama path (Stitcher, one call, no configuration) and OpenCV's stitching stages as separate calls (exposure compensation, graph-cut seams, multiband blending) for callers that need OpenCV's output, plus features, homography, remap, photo ops and detection. The controllable panorama path — control-point editing, projection choice, bundle adjustment — belongs to whugin. Enblend's blending and enfuse's exposure fusion are wenblend's. wlensfun hands wopencv its lens-correction maps to apply via remap. See briefs/INITIAL.md for the full family-boundaries table.

License

Apache-2.0, matching upstream OpenCV — see LICENSE. The wasm bundles also contain code under other permissive licences: zlib, Protocol Buffers and FLANN, vendored by OpenCV; OpenCV files contributed under their authors' own BSD-style licences (FAST, AGAST, BRISK, ORB, KAZE/AKAZE, SIFT and others); and Emscripten's runtime (with musl libc and Node.js's path code). Their notices are in THIRD-PARTY-NOTICES.md, which ships with the package; docs/licences.md records the audit. Models and cascades fetched via wopencv-fetch-models carry their own licences, separate from wopencv's own, and are not covered by this project's Apache-2.0 grant.