ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

OpenCV.js 图像分类实战指南:基于 dnn 模块从 ONNX 模型加载到 Top-K 结果输出

OpenCV.js 图像分类实战指南:基于 dnn 模块从 ONNX 模型加载到 Top-K 结果输出 OpenCV.js 图像分类实战指南基于 dnn 模块从 ONNX 模型加载到 Top-K 结果输出【免费下载链接】opencvOpen Source Computer Vision Library项目地址: https://gitcode.com/GitHub_Trending/opencv31/opencv本文围绕 OpenCV.jsOpenCV 的 WebAssembly 构建的dnn模块完整讲解如何在浏览器中实现图像分类流水线从页面骨架与交互控件、推理参数配置、模型文件写入 Emscripten 虚拟文件系统到blobFromImage预处理、readNet/forward推理和 softmax Top-K 后处理。读完本文你可以直接复用仓库内置的交互示例js_image_classification.html跑通任意 ONNX/TensorFlow 分类模型并理解每个环节背后的源码实现。一、目标与运行环境该教程的目标见 js_image_classification.markdown是学习如何使用 OpenCV.js 的 dnn 模块完成图像分类。教程配套一个可交互的 HTML 示例页面其基本操作路径为点击modelFile按钮上传一个 ONNX或 TensorFlow模型文件根据所上传的模型修改第一段代码片段推理参数点击Try it按钮执行一次推理输入图片也可以换成其他图像在右侧表格中查看 Top-3 分类标签与概率状态栏显示模型路径与推理耗时毫秒。1.1 获取并加载 opencv.jsOpenCV.js 的获取与引入方式在 js_usage.markdown 中有完整说明核心要点预构建的opencv.js可以从每个 release 的opencv-{VERSION_NUMBER}-docs.zip中获得也可以从在线文档站点直接下载对应版本的opencv.js想要最新构建时选5.x也可以按 js_setup.markdown 使用 Emscripten 自行构建emcmake python ./platforms/js/build_js.py build_js。示例页面通过 utils.js 中的Utils.loadOpenCv()动态注入script标签加载opencv.js并兼容三种就绪状态同步脚本、cv为 Promise 类型需await、以及注册onRuntimeInitialized回调。这也是 OpenCV.js 官方推荐写法cv (cv instanceof Promise) ? await cv : cv;官方教程同时建议使用本地 Web 服务器托管页面而不是直接以file://方式打开——本例中的标签文件、模型信息 JSON 都通过fetch拉取跨域与同源限制下必须有 HTTP 服务。二、页面骨架画布、结果表格与两个文件输入交互示例的 DOM 结构js_image_classification.html由以下部分构成canvas idcanvasInput width400 height400输入图像画布页面加载时会在其中绘制一张默认图片input typefile idfileInput acceptimage/*更换输入图像input typefile idmodelFile上传模型文件核心入口未上传时点击 Try it 会提示 Please upload model file by clicking the button first.table idresult初始visibility: hidden推理成功后显示三行label0/prob0至label2/prob2的 Top-3 标签与概率p idstatus状态栏显示 Running function main()...、模型路径与Inference time: xx.xx ms六个textarea classcode代码编辑器对应 6 段可编辑的示例代码Utils.executeCode()会对编辑器内容执行eval因此读者可以直接在页面上改写参数与逻辑做实验。页面加载流程utils.loadOpenCv()就绪后移除 Try it 按钮的disabled属性drawInfoTable()拉取模型信息 JSON 并在附录区渲染出各模型的参数表格。三、推理参数配置各模型如何设置 mean / std / swapRB / softmax第一段代码片段codeSnippet是所有分类模型的公共参数模板inputSize [224,224]; mean [104, 117, 123]; std 1; swapRB false; // record if need softmax function for post-processing needSoftmax false; // url for label file, can from local or Internet labelsUrl https://raw.githubusercontent.com/opencv/opencv/5.x/samples/data/dnn/classification_classes_ILSVRC2012.txt;各字段含义参数含义说明inputSize网络输入尺寸绝大多数 ImageNet 分类网络为[224, 224]getBlobFromImage中会以cv.Size(inputSize[0], inputSize[1])传入mean均值减除向量注意以BGR 顺序给出OpenCV 默认通道序如 TF inception 的 RGB 均值 123/117/104 对应 BGR 的 104/117/123std缩放系数 scalefactor在blobFromImage调用中该参数位置实际是标量scalefactor详见第五节swapRB是否交换 R、B 通道用于模型在 RGB 空间训练时的通道对齐needSoftmax输出是否需要额外 softmax取决于网络输出层是否已带 SoftmaxlabelsUrl标签文件地址每行一个类别名支持本地或网络地址默认参数mean[104,117,123]、std1、swapRBfalse、needSoftmaxfalse正是针对 TensorFlow 版 Inception 图tensorflow_inception_graph.pb配置其输出已是概率无需再套 softmax。示例附录区渲染的完整模型参数来自 js_image_classification_model_info.json各模型下载链接保存在该文件的modelUrl字段中。整理如下ONNX 模型均来自 ONNX 模型仓库均为 224×224 输入模型meanstdscaleswapRBneedSoftmax模型文件googlenet103.939, 116.779, 123.6751, 1, 11falsetruegooglenet-8.onnxsqueezenet0.485, 0.456, 0.4060.229, 0.224, 0.2250.003921truetruesqueezenet1.1-7.onnxresnet (resnet50)123.675, 116.28, 103.5358.395, 57.12, 57.3751truetrueresnet50-v2-7.onnxvgg16103.939, 116.779, 123.681, 1, 11falsetruevgg16-bn-7.onnxdensenet121123.675, 116.28, 103.530.229, 0.224, 0.2250.003921truetruedensenet-8.onnxTensorFlow 模型模型meanstdscaleswapRBneedSoftmax模型文件inception123, 117, 10411truefalsetensorflow_inception_graph.pb从源码结构看本教程的简化预处理管线getBlobFromImage只把std作为标量 scalefactor传入blobFromImage见下文因此表格中带分通道 std/scale 的模型如 squeezenet、densenet121若严格按表使用应把scale0.003921作为该参数传入而分通道归一化需要更完整的预处理接口。四、模型加载把文件写入 Emscripten 虚拟文件系统浏览器里的 OpenCV.js 运行在 WebAssembly 之上cv.readNet(path)读取的是Emscripten 虚拟文件系统中的路径而不是浏览器本地磁盘。因此 js_dnn_example_helper.js 提供了loadModelloadModel async function(e) { return new Promise((resolve) { let file e.target.files[0]; let path file.name; let reader new FileReader(); reader.readAsArrayBuffer(file); reader.onload function(ev) { if (reader.readyState 2) { let buffer reader.result; let data new Uint8Array(buffer); cv.FS_createDataFile(/, path, data, true, false, false); resolve(path); } } }); }流程input typefile的 change 事件拿到File对象 →FileReader以 ArrayBuffer 读出 → 包成Uint8Array→ 调用cv.FS_createDataFile(/, 文件名, data, true, false, false)在虚拟 FS 根目录下创建同名文件 → 返回路径字符串modelPath。utils.js中另有一个createFileFromUrl()变体用XMLHttpRequestresponseType: arraybuffer从网络下载后走同样的FS_createDataFile落盘适用于模型托管在服务器上的场景。五、预处理从 Canvas 到归一化后的 Blob标签加载很简单——fetch标签 URL 后按换行切分loadLables async function(labelsUrl) { let response await fetch(labelsUrl); let label await response.text(); label label.split(\n); return label; }图像输入则从 Canvas或图像路径转换为模型输入张量getBlobFromImage function(inputSize, mean, std, swapRB, image) { let mat; if (typeof(image) string) { mat cv.imread(image); } else { mat image; } let matC3 new cv.Mat(mat.matSize[0], mat.matSize[1], cv.CV_8UC3); cv.cvtColor(mat, matC3, cv.COLOR_RGBA2BGR); let input cv.blobFromImage(matC3, std, new cv.Size(inputSize[0], inputSize[1]), new cv.Scalar(mean[0], mean[1], mean[2]), swapRB); matC3.delete(); return input; }要点解析Canvas 读取的像素是 RGBA 四通道而分类网络要求 3 通道所以先cvtColor转成CV_8UC3的 BGR 图cv.blobFromImage对应 C 侧接口其签名见 dnn.hppMat blobFromImage(InputArray image, double scalefactor1.0, const Size sizeSize(), const Scalar meanScalar(), bool swapRBfalse, ...)。可以看到 JS 调用中第二个实参教程里命名为std对应的正是scalefactor随后依次是输入尺寸、均值向量与swapRB标志——这与上文“std 实为 scalefactor”的说明相互印证返回的input是一个 4 维 blobNCHWMat推理完成后需input.delete()释放 Emscripten 堆内存OpenCV.js 的 Mat 均为显式管理务必 delete。六、推理主循环readNet → setInput → forward第二段代码片段是一次完整的单帧推理js_image_classification.html 中codeSnippet1main async function() { const labels await loadLables(labelsUrl); const input getBlobFromImage(inputSize, mean, std, swapRB, canvasInput); let net cv.readNet(modelPath); net.setInput(input); const start performance.now(); const result net.forward(); const time performance.now()-start; const probs softmax(result); const classes getTopClasses(probs, labels); updateResult(classes, time); input.delete(); net.delete(); result.delete(); }调用链说明cv.readNet(modelPath)从第四节写入的虚拟 FS 路径加载网络权重构建cv.dnn_Netnet.setInput(input)绑定预处理后的 blobnet.forward()执行全图前向传播返回输出层Matdata32F为各类别得分向量用performance.now()前后相减得到纯推理耗时展示在状态栏三个delete()分别释放输入、网络与输出对象避免 WASM 堆内存累积。注意getBlobFromImage(inputSize, mean, std, swapRB, canvasInput)这里传的是字符串 id函数内部走cv.imread(canvasInput)分支——OpenCV.js 支持直接从 canvas 元素读取Mat。七、后处理数值稳定的 softmax 与 Top-K 提取分类结果后处理由两个函数完成分别位于 HTML 的codeSnippet5与 js_dnn_example_helper.jssoftmax function(result) { let arr result.data32F; if (needSoftmax) { const maxNum Math.max(...arr); const expSum arr.map((num) Math.exp(num - maxNum)).reduce((a, b) a b); return arr.map((value, index) { return Math.exp(value - maxNum) / expSum; }); } else { return arr; } }实现上做了经典的数值稳定处理先减去最大值maxNum再取指数避免exp上溢needSoftmaxfalse时如 TF Inception直接返回原始输出。getTopClasses function(probs, labels, topK 3) { probs Array.from(probs); let indexes probs.map((prob, index) [prob, index]); let sorted indexes.sort((a, b) { if (a[0] b[0]) {return 0;} return a[0] b[0] ? -1 : 1; }); sorted.reverse(); let classes []; for (let i 0; i topK; i) { let prob sorted[i][0]; let index sorted[i][1]; let c { label: labels[index], prob: (prob * 100).toFixed(2) } classes.push(c); } return classes; }将[prob, index]配对排序、倒序后取前topK默认 3项概率换算成百分比并保留两位小数标签名通过原始下标回查labels数组——这一步保证了重排后标签与得分不脱节。页面侧的updateResult(classes, time)把三行结果写入#result表格显示后其visibility改为 visible并在状态栏输出Model: modelPath与Inference time: ms。八、完整操作步骤将opencv.js与示例页面放在同一目录用本地 HTTP 服务器打开 js_image_classification.html从附录“Model Info”表格数据源 js_image_classification_model_info.json中选定一个模型下载对应模型文件链接在 JSON 的modelUrl字段点击modelFile按钮上传模型文件状态栏应显示 The model file 文件名 is created successfully.若所选模型不是默认配置的 TF Inception按第三节参数表修改第一段代码编辑器中的inputSize/mean/std(scale) /swapRB/needSoftmax并确保labelsUrl指向对应类别文件示例默认使用 ILSVRC2012 的classification_classes_ILSVRC2012.txt需要换图时用canvasInput下的 file 控件选择任意图像内部经loadImageToCanvas重新绘制到画布点击Try it查看 Top-3 标签、概率与推理耗时。九、延伸摄像头实时分类与其他 dnn 示例同一教程族还提供摄像头实时版本 js_image_classification_with_camera.markdown在静态图基础上用getUserMedia获取视频流逐帧推理utils.js的startCamera已封装该能力。整个 OpenCV.js dnn 教程目录见 js_table_of_contents_dnn.markdown还包含目标检测、语义分割、风格迁移与姿态估计等示例均复用本文的“模型落盘 → readNet → forward → 后处理”范式可对照 js_dnn_example_helper.js 快速改造。需要 GPU 加速方向时资源目录中另备有 WebNN polyfill 与 Electron 版页面doc/js_tutorials/js_assets/js_image_classification_webnn_polyfill.html可供参考。【免费下载链接】opencvOpen Source Computer Vision Library项目地址: https://gitcode.com/GitHub_Trending/opencv31/opencv创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表