起因是我想要在 Electron 用上圖像辨識,在尋找過程中有找到一些 js 圖像處理套件,例如 JIMP、sharp、Resemble.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();
展示完整程式碼還是交給專業的展示地方 CodePen 吧。
如何在 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 萬歲 ~
你也用 Opencv.js 做專案嗎?請跟我分享吧。如果你喜歡我的文章,請幫我按讚,我能藉此獲得鼓勵以及微小的收入,支持我繼續創作。請按下方綠色拍手的符號~