如何在 Nodejs 或前端使用 OpenCV(免安裝)

Up Chen
6 min readFeb 2, 2020

--

Photo by CDC on Unsplash

起因是我想要在 Electron 用上圖像辨識,在尋找過程中有找到一些 js 圖像處理套件,例如 JIMPsharpResemble.js 等。但都不符合需求,我需要的有以圖找圖、圖片分析、圖片處理等。最理想的就是老牌的 OpenCV 了,有我所有需要的功能。

可是,在本機使用 OpenCV 很簡單,在伺服器端使用 OpenCV 也很簡單,但是在前端呢?原本以為沒希望,後來找到居然有純 JS 的版本。官方有在不起眼的地方提到,是可以用 Emscripten 把原始碼編譯成 OpenCV.js,只要引入編譯好的 js 檔案就能在前端使用了,簡直完美!

在這邊我將用常常使用到的 Canny 邊緣偵測方法,來展示在前端使用 Opencv.js 的方法。所以文章接下來的部分,包含:

  • 如何獲得編譯好的 opencv.js 檔案
  • 如何在前端環境使用 opencv.js 來做邊緣偵測
  • 如何在 node.js 環境中使用 opencv.js

如何獲得編譯好的 opencv.js 檔案

官方說明文檔中有提到,要用 Emscripten 來編譯原始碼。如果你有嘗試過,就知道編譯任何的原始碼最常遇到的就是編譯失敗,缺東缺西,有時候編譯時沒錯誤訊息,但也不知道是不是正確的。

我遇到了一樣的問題,想說不可能阿官方怎麼會沒有放出編譯好的版本讓人直接使用呢?認真 Google 一番官方還真有放出來,只是完全沒在任何地方寫到。

官方編譯好的版本下載網址為:

https://docs.opencv.org/_VERSION_/opencv.js

其中 _VERSION_ 請帶入你想要的版本,目前最新的為 4.2.0 版本。

如果你懶得自己下載,或是跟我一樣怕官方有一天拿掉這個連結的話,我有把他整理到 github 上面,請自行取用 >> compiled-opencvjs

Opencv.js 下載連結:compiled-opencvjs

如何在前端環境使用 opencv.js 來做邊緣偵測

獲得 opencv.js程式碼以後,事情就比較簡單了,只要在前端引入就可以使用了。只是需要注意幾個小地方

陷阱 1:Opencv.js 很大,載入很慢

opencv.js功能很強,所以程式碼也非常大,大到有 8MB 左右,所以在前端載入的時候需要加上 async 標籤,並且設定 onload 事件來偵測是否載入完成。

利用這段程式碼異步載入 opencv.js

<script src=”https://cdn.jsdelivr.net/gh/wallat/compiled-opencvjs/v4.2.0/opencv.js" async onload=”onOpenCvReady();” type=”text/javascript”></script>

利用 html script onload 事件來偵測是否載入完成

window.onOpenCvReady = function () { 
// dosomething
}

陷阱 2:imread 用法和 python 版本的不同

js 版本的 imread 有被特別改過,不能像 python 一樣直接傳入路徑。

<img id=”src-image” src=”” alt=””>

imread必須傳入 <img /> 或是 <canvas />id 或是 DOM 才行。

// 可以傳入 DOM
var src = cv.imread(document.getElementById('src-image'));
// 也可以直接傳入 id
var src = cv.imread('src-image');

陷阱 3: imshow 的用法和 python 當然也不同

經過了陷阱 2,陷阱 3 就比較容易理解了。一樣是傳入 <canvas />id 或是 DOM 就可以了。

cv.imshow('canvas-id', cvMat);

陷阱 4: 用完的 Mat 記得要 delete

這是我花了一整個下午得到的教訓,怎麼跑一跑 opencv 就會壞掉呢?實測的結果是當你有約 2000 個 cv.Mat 的時候,opencv 就會直接壞掉給你看了,所以記得用完要馬上刪除才行。

var dst = new cv.Mat(); // 有 newdst.delete(); // 就千萬要記得 delete

終於可以實做邊緣檢測了 ~

剩下的就是簡單的事情了,只要複製貼上 opencv 提供的範例程式碼就好了。

核心程式碼

var src = cv.imread(srcImgEl); // load the image from <img>
var dst = new cv.Mat();
// Convert to gray scale
cv.cvtColor(src, src, cv.COLOR_RGB2GRAY, 0);
// You can try more different parameters
cv.Canny(src, dst, 50, 100, 3, false);
// display the output to canvas
cv.imshow('the-canvas', dst);
// remember to free the memory
src.delete();
dst.delete();
Canny Edge Detection 邊緣偵測結果

展示完整程式碼還是交給專業的展示地方 CodePen 吧。

Canny Edge Detection 邊緣偵測完整範例

如何在 node.js 環境中使用 opencv.js

我們下載的 opencv.js 一樣可以在 node.js 環境或是 electron 環境中使用。不過要小心另外一個地雷就是:opencv.js 在伺服器環境一樣是延遲載入的,使用前要先確定已經載入完成了。

opencv.js 一樣有好心的提供載入完成時 callback,只要記得收到完成訊號以後再做其他的事情就可以了。範例程式碼如下

import cv from 'opencv.js'cv.onRuntimeInitialized = ()=>{
// opencv is ready
}

JS 快要統一天下了

這是發現前端不用安裝居然也能用 Opencv.js 的感想,但無論如何,能不用重新打造輪子就是好事情。OpenCV 萬歲 ~

Photo by Christopher Robin Ebbinghaus on Unsplash

你也用 Opencv.js 做專案嗎?請跟我分享吧。如果你喜歡我的文章,請幫我按讚,我能藉此獲得鼓勵以及微小的收入,支持我繼續創作。請按下方綠色拍手的符號~

--

--

Up Chen

工程師、軟體顧問、理想生活追求者。我協助想要達成理想生活的工程師找到改變的勇氣以及可執行的方向