'Is is possible to use OpenCV.js with Web Worker in Angular?

I'm trying to use OpenCV.js in web workers in Angular. My project needs to conduct multiple graphic computings at the same time, which would take long time.

But when I use OpenCV in a *.worker.ts file like components, it said function not defined.

blur.worker.ts:

/// <reference lib="webworker" />

addEventListener('message', ({ data }) => {
  const src = data.src;
  const color = data.color;
  const kSize = data.kSize;
  if (color === false) {
    cv.cvtColor(src, src, cv.COLOR_RGB2GRAY, 0);
  }
  const dst = new cv.Mat();
  if (kSize > 0) {
    cv.medianBlur(src, dst, kSize);
  } else {
    src.copyTo(dst);
  }
  postMessage({dst});
});

Main thread (a service):

const src = cv.imread(srcImg.nativeElement.id);
const worker = new Worker('../workers/blur.worker.ts', { type: 'module' });
worker.onmessage = ({ data }) => {
  cv.imshow(dstImg.nativeElement.id, data.dst);
};
worker.postMessage({src, color, args});

It seems opencv.js has been loaded, but web worker cannot access it.



Solution 1:[1]

You can fix by removing this code block from generated opencv.js file, present at the top of the file. 'cv' object will be returned as promise.

else if (typeof importScripts === 'function') {
      // Web worker
      root.cv = factory;
}

Solution 2:[2]

This took me a stupidly long time to figure out. But here you go everyone.

addEventListener('message', async (data) => {
  self["Module"] = {
    scriptUrl: '/assets/opencv/opencv.js',
    wasmBinaryFile: '/assets/opencv/opencv_js.wasm',
    usingWasm: true,
    onRuntimeInitialized: () => { }
  }

  //Hack to fake correct path to .wasm file
  let scriptDirectory = self.location.href
  scriptDirectory = scriptDirectory.substr(0, scriptDirectory.lastIndexOf("/")) + self["Module"].wasmBinaryFile;
  let document = { currentScript: { src: scriptDirectory } }
  self["document"] = document;

  //Load and await the .js OpenCV
  self.importScripts(self["Module"].scriptUrl);
  cv = await cv;

  //!!Use cv here!!

  postMessage(response);
});

Normaly when loading OpenCV, the Module infomation is declared globlay using window["Module"], however as we are a web worker, we don't have acess to window. Instead i replaced this with self["Module"].

The hack using scriptDirectory is designed to take advantage of the _scriptDir variable (in opencv.js) to overide the nasty scriptDirectory generated in the ENVIROMENT_IS_WORKER if else block.

Have fun!

for Typescript replace

self["document"] = document;
self.importScripts(self["Module"].scriptUrl);

with

//@ts-ignore
self["document"] = document;
//@ts-ignore
self.importScripts(self["Module"].scriptUrl);

(Do bear in mind that this will load opencv from the server every time the worker is pinnged, consider moving this code outside of the onmessage)

Solution 3:[3]

For guys looking for importing OpenCV in module workers, i.e.

new Worker('worker.js', { type: 'module' })

I've come up with the following solution.

  1. Download "opencv-4.5.5.js" from OpenCV official site https://docs.opencv.org/4.x/d0/d84/tutorial_js_usage.html

  2. Change this file (1): Add let Module; to the first line, so that line 44-46 will not give you error.

  // line 44-46
  if (typeof Module === 'undefined')
    Module = {};
  return cv(Module);
  1. Change this file (2): As you will find root be undefined, and it comes from line 22. Make a fallback to self which we use for workers.
  } else {
    // Other shells, e.g. d8
    root.cv = factory();
  }
}(this||self, function () {   // <-- original: }(this, function () {
  
var cv = (function() {
  1. Change this file (3): Find this and give it a missing ()
  } else if (typeof importScripts === 'function') {
    // Web worker
    root.cv = factory();   // original: root.cv = factory;
  }
  1. I created a wrapper for the import, opencv-wrapper.js
await import("/lib/opencv-4.5.5.js");  // where your modified file locate
export default cv;
  1. Import as normal
import cv from "/lib/opencv-wrapper.js"; // where you place your wrapper

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 mAc
Solution 2 Peter Csala
Solution 3