资讯动态

EmojiFace代码解读(二):Android端ONNX Runtime集成与orx自定义算子实现模型预处理后处理

发布时间:2026/10/26 16:37:51 来源:尧图企业网站定制
【免费下载链接】EmojiFaceIdentify faces in an image and replace them with emojis.项目地址https://gitcode.com/gh_mirrors/emo/EmojiFace点击查看免费下载EmojiFace 是一款「识别图片中的人脸并将其替换成 Emoji 表情」的开源应用。本篇代码解读聚焦 Android 端如何集成 ONNX Runtime 在设备端运行 YOLOv8n 人脸检测模型以及如何借助 ORTXONNX Runtime 扩展包自定义算子把预处理与后处理直接「烘焙」进 ONNX 模型让应用层只需传入一段图像字节流就能直接拿到最终的检测框与关键点。EmojiFace 同时提供 Android 应用与 Web 双端实现Web 端的编辑器界面如下右侧面板可切换 Emoji 替换 / 模糊打码模式、自定义随机表情列表一、痛点人脸检测的预处理和后处理由谁来写YOLOv8n 系列模型对输入有固定要求输入尺寸固定为640×640需要保持宽高比缩放并做 LetterBox 灰边填充像素需归一化到 0..1 并转换为 CHW 排布输出是「原始预测」还要经过NMS 去重、按 LetterBox 参数做坐标缩放还原才能得到原图尺寸下的边界框。如果这些逻辑都写在应用代码里Kotlin 端就要手写 LetterBox、NMS、坐标换算代码量大且容易出错。EmojiFace 的 Web 版走的正是这条传统路线——在 JS 层完成全部前后处理imageUtils.tspreprocess用 Canvas 做 LetterBox 填充并转 CHW 归一化张量OnnxFaceDetector.tspostprocess以0.45置信度阈值和0.5IOU 阈值执行 NMS 并还原坐标。而 Android 端选择了另一条更优雅的路径利用ORTX 提供的自定义算子把这些步骤作为节点直接追加进 ONNX 计算图。模型输入不再是张量而是原始图像字节模型输出不再是原始预测而是处理完毕的检测结果。应用层与算法层彻底解耦。二、把预处理/后处理烘焙进模型ORTX 算子流水线整个改造由 add_prepost.py 完成。它基于onnxruntime_extensions.tools.pre_post_processing.PrePostProcessor把标准模型改造为「字节进、结果出」的新模型1. 新增模型输入inputs [create_named_value(image_bytes, onnx.TensorProto.UINT8, [num_bytes])]新输入image_bytes直接接收 PNG/JPG 的原始字节见 add_prepost.py#L61图像解码由算子完成。2. 预处理链add_prepost.py#L65-L72顺序算子作用①ConvertImageToBGR将图像字节解码为 BGR 图HWC②ChannelsLastToChannelsFirstHWC → CHW 转置③Resizepolicynot_larger等比缩放最长边不超过 640④LetterBox灰边填充至 640×640⑤ImageBytesToFloat像素归一化到 0..1⑥Unsqueeze([0])补 batch 维得到[1,3,640,640]3. 后处理链add_prepost.py#L76-L91顺序算子作用①Squeeze([0])Transpose([1,0])整理输出为[num_boxes, channels]②Split([4,1,15])拆分为边界框、置信度、5 组关键点③SelectBestBoundingBoxesByNMSIOU 阈值 0.5、置信度阈值 0.45 过滤冗余框④ScaleNMSBoundingBoxesAndKeyPoints结合Resize/LetterBox中间结果IoMapEntry把框和关键点还原到原始图像坐标4. 输出格式模型输出是一个二维浮点数组每个检测占21 个 float[x_center, y_center, width, height, confidence, class_id, 5×(keypoint_x, keypoint_y, keypoint_conf)]。Android 端与 Web 端 NMS 所用的阈值完全一致0.45 / 0.5保证双端行为对齐。仓库中还配套了两个工具脚本quantize_model.pyquantize_dynamic做 QUInt8 动态量化显著压缩模型体积predict.py桌面端 Python 参考推理注册 ORTX 库后直接喂image_bytes并用左右眼连线计算人脸 roll 角度做可视化验证。各端使用的模型文件一览模型文件体积说明face.onnx~12.6 MBAndroid 端打包于res/raw已烘焙前后处理yolov8n-face.onnx~12.1 MBWeb 端原始模型前后处理在 JS 完成yolov8n-face-int8.onnx~5.4 MBWeb 端 INT8 量化版三、Kotlin 端集成初始化 ONNX Session 的三个关键点1. 依赖配置libs.versions.tomlonnxruntime-android 1.22.0 onnxruntime-extensions-android 0.13.0 // 即 ORTX提供自定义算子两个依赖缺一不可extensions包提供 C 算子实现与OrtxPackage工具类。2. 注册自定义算子库 —— 最关键的一行在 FaceDetector.kt#L36-L40 中val sessionOptions OrtSession.SessionOptions().apply { registerCustomOpLibrary(OrtxPackage.getLibraryPath()) } ortSession ortEnv.createSession(modelBytes, sessionOptions)模型图里包含ConvertImageToBGR、SelectBestBoundingBoxesByNMS等 ORTX 自定义算子若不注册 ORTX 的 so 库路径createSession会因找不到算子实现而直接失败。这也是本篇标题中「orx 自定义算子」的落点。3. 检测流程字节流进、结果出YoloPoseDetector 以Singleton Hilt 注入的方式全局复用 Session并在init中一次性加载R.raw.face。detect()的流程极为简洁inputStream.readBytes()读取 PNG 字节OnnxTensor.createTensor(..., OnnxJavaType.UINT8)以一维 shape[numBytes]构造张量绑定输入名image_bytessession.run(inputs)后从第一个输出读取ArrayFloatArray封装为 DetectionResult 返回。解码、缩放、NMS、坐标还原全部发生在模型内部Kotlin 代码里没有一行 LetterBox 或 NMS 逻辑。四、DetectFacesUseCase缩放策略与坐标还原上层调用链在 DetectFacesUseCase.kt 中完成「三件套」先缩放scaleBitmapIfNeeded 将最长边限制在 1024控制推理耗时记录缩放因子scaleFactorX/Y 原图尺寸 / 缩放后尺寸随 DetectionOutput 一起下发转字节流bitmapToInputStream 以 PNG 压缩为字节流——因为模型输入就是图像字节ConvertImageToBGR算子内部可直接解码。由于模型输出已是缩放后图片坐标系下的结果CalculateEmojiPositionsUseCase 只需乘以缩放因子即可把框与 5 个关键点映射回原图并用左右眼连线atan2计算 roll 角度让贴上去的 Emoji 跟随脸部姿态倾斜。最终由 EmojiViewModel 统一编排先缩放生成预览图 → 调用detectFacesUseCase→ 根据 Emoji / 模糊模式分发到后续渲染 UseCase。五、要点清单 ✅ ORTX 自定义算子让「预处理 后处理」成为模型图的一部分应用层零算法代码✅registerCustomOpLibrary(OrtxPackage.getLibraryPath())是 Android 端加载此类模型的必要步骤✅ 模型输入为一维UINT8字节张量image_bytes输出为每行 21 个 float 的检测结果✅ NMS 阈值score 0.45 / IOU 0.5与坐标还原参数在 add_prepost.py 中集中定义双端一致✅ 缩放在进入模型前完成缩放因子随结果回传保证坐标系可逆。附核心文件路径文件说明app/src/main/java/top/maary/emojiface/facedetection/FaceDetector.ktORT Session 初始化与推理入口app/src/main/java/top/maary/emojiface/facedetection/DetectionResult.kt检测结果数据结构app/src/main/java/top/maary/emojiface/domain/usecase/DetectFacesUseCase.kt缩放、调用检测、坐标因子app/src/main/java/top/maary/emojiface/util/BitmapUtils.ktscaleBitmapIfNeeded/bitmapToInputStreamscripts/add_prepost.pyORTX 前后处理烘焙脚本scripts/quantize_model.pyQUInt8 动态量化脚本scripts/predict.py桌面端推理与可视化验证gradle/libs.versions.tomlONNX Runtime 依赖版本赞分享【免费下载链接】EmojiFaceIdentify faces in an image and replace them with emojis.项目地址https://gitcode.com/gh_mirrors/emo/EmojiFace点击查看免费下载相关推荐ONNX Runtime模型预处理数据预处理与后处理优化ONNX Runtime模型预处理数据预处理与后处理优化 在机器学习模型部署过程中数据预处理与后处理Preprocessing Postprocess人工智能推理引擎模型优化模型量化模型编译预训练分布式训练ONNX Runtime Transformer 模型优化工具开发指南图融合原理与自定义算子接入实战ONNX Runtime Transformer 模型优化工具开发指南图融合原理与自定义算子接入实战 Transformer 优化工具Transformer人工智能推理引擎模型优化模型量化模型编译预训练分布式训练YOLOv8-seg ONNX Runtime 纯 Python 分割推理实战从模型导出到掩码后处理全解析YOLOv8 seg ONNX Runtime 纯 Python 分割推理实战从模型导出到掩码后处理全解析 本文围绕 yolov12 仓库自带的 YOLOv8计算机视觉深度学习人工智能创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑