最近,我完成了一個 demo 演示,展示了 OpenVINO 在 Node.js 框架中的強大功能。得益于與 Electron.js 的集成,該演示不僅能夠高效地執行神經網絡推理,還提供了交互式的用戶體驗。
1
應用程序概覽:一種簡單的背景虛化方法
這個演示展示了如何在 Node.js 環境中使用 OpenVINO 工具包實現背景虛化,并通過 Electron.js 創建的直觀桌面界面進行呈現。啟動應用程序后,您會看到一個帶有黑色占位符的界面。要激活攝像頭,只需從檢測到的設備列表中選擇您喜歡的視頻源并點擊“開始”。
完成此步驟后,您應該會在界面中的框內看到來自攝像頭的實時視頻流。
最初,您的畫面將顯示為未經過任何虛化處理的原始圖像。要啟用背景虛化功能,請通過指定的切換開關打開推理模式。該應用還允許您選擇推理設備,可以在操作前或操作過程中進行設置。當您在會話中首次選擇設備時,可能會出現短暫的延遲,因為模型需要進行編譯。
在攝像頭畫面上方,您會看到一個推理時間顯示器,顯示最近50幀的平均推理時間。同時,還會顯示每秒處理(或推理)的幀數,讓您了解性能表現。
在應用運行期間,您可以隨時停止攝像頭或推理,切換視頻源,或更改推理設備。
2
項目架構
完整代碼可以在 OpenVINO Build & Deploy 倉庫中找到。該 Electron 應用項目分為幾個關鍵部分:
GitHub - openvinotoolkit/openvino_build_deploy: Pre-built components and code samples to help you build and deploy production-grade AI applications with the OpenVINO Toolkit from Intel
界面(Interface):
包括定義界面視覺效果的 HTML 和 CSS 文件,以及控制功能的 renderer.js 文件。
OpenVINO 任務(OpenVINO Jobs):
后端組件,位于 ov-jobs.js 文件中,包含推理、前處理、后處理和背景虛化的相關函數。
主程序(Main):
main.js 文件負責啟動應用程序,設置必要參數,并處理中斷等操作。
預加載(Preload):
preload.js 文件作為主程序與界面組件之間的橋梁,啟用后端功能并處理用戶觸發的中斷。
Node 模塊(Node Modules):
程序所需的外部庫和模塊列在 package.json 文件中,同時包含其他必要的開發信息。要安裝這些模塊,只需在主目錄運行以下命令:
npm install
保持清晰的項目架構至關重要,因為 OpenVINO 的 Node.js 庫只能在后端運行。如果將其導入到界面層會導致錯誤。因此,最佳實踐是將 OpenVINO 的導入限制在 ov-jobs.js 文件中。
3
它是如何工作的?
背景虛化功能使用了一個來自 TensorFlow 的分割模型,名為 “TensorFlow_Lite_Frontend_IR”,該模型已被轉換為 OpenVINO 的 IR 格式。此模型要求輸入尺寸為 1x3x256x256,因此在預處理步驟中,需要將圖像調整為正方形(無需填充)。如果圖像不是 RGB 格式,還需要將其顏色表示轉換為 RGB 格式。
const sharp = require('sharp'); // originalImg is a sharp object. async function preprocess(originalImg) { const inputSize = { w: 256, h: 256 }; const inputImg = await originalImg .resize(inputSize.w, inputSize.h, { fit: 'fill' }) .removeAlpha() // converting RGBA to RGB .raw() .toBuffer(); const resizedImageData = new Uint8ClampedArray(inputImg.buffer); const tensorData = Float32Array.from(resizedImageData, x => x / 255); const shape = [1, inputSize.w, inputSize.h, 3]; return new ov.Tensor(ov.element.f32, shape, tensorData);
該模型作為分類器工作,將圖像中的每個像素分配到六個類別之一,其中類別 0 代表背景。在推理后,輸出會經過后處理生成一個掩碼,其中 0 表示背景(需要進行虛化),1 表示其他元素(需要保持清晰)。隨后,該掩碼會被調整為與原始圖像尺寸匹配。
程序運行時采用兩個主要線程:一個線程從攝像頭捕獲幀,根據掩碼對背景進行虛化處理,并將處理后的結果顯示在屏幕上。另一個線程“借用”一幀圖像,運行推理以更新掩碼,確保攝像頭的畫面保持流暢,即使某些設備上的推理需要較長時間。
4
在 JavaScript 中
使用 OpenVINO 的基本功能
發現可用來進行推理的設備:
const { addon: ov } = require('openvino-node'); const core = new ov.Core(); const devices = core.getAvailableDevices();
讀入和編譯模型:
const { addon: ov } = require('openvino-node'); const core = new ov.Core(); const modelPath = "path/to/your/model"; const model = await core.readModel(modelPath); const device = "AUTO"; // or "GPU", "CPU" and others const compiledModel = await core.compileModel(model, device);
運行編譯后的模型:
// have compiledModel and inputTensor prepared let inferRequest = compiledModel.createInferRequest(); inferRequest.setInputTensor(inputTensor); inferRequest.infer() // inference const outputLayer = compiledModel.outputs[0]; // only one output in this scenario const resultTensor = inferRequest.getTensor(outputLayer); // your inference result
虛化步驟:
這是最簡單的虛化圖像的方式:
捕獲一幀圖像
從攝像頭捕獲當前幀。
復制并虛化圖像
創建原始圖像的副本,使用 sharp.blur() 對整個副本進行虛化處理(替代方案:OpenCV 或卷積操作)。
獲取分割模型生成的掩碼
在獨立線程中運行分割模型,獲取當前幀的掩碼。
應用掩碼到虛化圖像
將虛化圖像的所有像素值與掩碼相乘,保留需要虛化的區域。
生成“反掩碼”
計算掩碼的反值(即 1 - mask),生成“非虛化區域掩碼”。
應用“反掩碼”到原始圖像
將原始圖像的像素值與“反掩碼”相乘,保留需要保持清晰的區域。
融合兩張圖像
將虛化后的圖像和清晰區域的圖像進行融合,生成最終圖像。
在最終的應用程序代碼中,多個操作被整合在一起,充分利用了 Sharp 庫的功能。以下是使用 Sharp 實現的方法:
1.根據掩碼裁剪原始圖像:
const sharp = require('sharp'); const person = await sharp(outputMask, { raw: { channels: 3, width: inputSize.w, height: inputSize.h, } }) .resize(width, height, { fit: 'fill' }) .unflatten() .composite([{ input: image.data, raw: { channels: 4, width, height, }, blend: 'in', }]) .toBuffer();
2.對副本進行虛化處理,并將其與裁剪后的原始圖像合并(復合):
const blurSize = Math.floor(widthOfImage * 0.01) const blurredImage = await sharp(imageToBlur.data, { raw: { channels: 4, width, height }, // back to RGBA }) .blur(blurSize) .composite([{ input: person, raw: { channels: 4, width, height }, blend: 'atop' }]) .raw() .toBuffer();
5
虛化面臨的挑戰
圖像虛化是一項耗時的操作,對性能影響較大,尤其是當它是圖像顯示線程的一部分時,這直接關系到用戶體驗。沒有人希望視頻流出現卡頓。
一種優化方法是在一開始就將圖像調整為最終顯示的大小。較小的圖像處理速度更快,從而提高性能。
起初,我們嘗試使用 OpenCV 的虛化功能(通過 opencv-wasm 模塊)。然而事實證明,其速度太慢,甚至比模型推理還慢,這促使我們尋找替代方案。
我們曾設想創建一個專門用于虛化的輕量化模型。該模型以圖像幀和掩碼作為輸入,執行“虛化過程”部分描述的數學操作,并通過深度卷積(Depthwise Convolution)實現虛化。我們使用 TensorFlow 構建了這個模型,并將其轉換為 OpenVINO 格式。
重要說明:OpenVINO 從 2024.4 版本開始度卷積操作。
盡管這種方法具有潛力,但由于深度卷積速度較慢且優化不足,最終被我們放棄。
最終,我們發現 Sharp 庫在此操作中表現最佳,因此將其作為項目中的解決方案。
6
總結
如果遵循以下關鍵指南,使用 Electron.js 和 OpenVINO 創建桌面應用程序是非常簡單的:
1.前后端功能分離:
確保將后端功能與前端功能分開,并記住 OpenVINO 只能在后端使用。
2.JavaScript API 的局限性:
并非所有 Python 中可用的 OpenVINO 方法都已在 JavaScript 中實現。然而,當前的 API 已足以完成大多數任務。
3.閱讀文檔:
許多常見問題的答案都可以在文檔中找到。參考 OpenVINO Node.js API 文檔以獲取更多信息。
4.檢查庫兼容性:
某些 JavaScript 庫可能無法很好地與 Electron 配合使用。在這些情況下,您可能需要尋找替代版本或定制分支。
別忘了親自體驗一下 "Hide Your Mess Behind" 應用程序!您可以從代碼倉庫運行該應用程序,也可以下載適用于 Windows(exe)或 Linux(deb、rpm)的可執行版本。
-
應用程序
+關注
關注
37文章
3265瀏覽量
57677 -
OpenVINO
+關注
關注
0文章
92瀏覽量
196
原文標題:開發者實戰|如何使用 OpenVINO? 在 ElectronJS 中創建桌面應用程序
文章出處:【微信號:英特爾物聯網,微信公眾號:英特爾物聯網】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論