Android ncnn-android-yolov8-seg源码解析 : 实现人像分割

1. 前言

上篇文章,我们已经将人像分割的ncnn-android-yolov8-seg项目运行起来了,后续文章我们会抽取出Demo中的核心代码,在自己的项目中,来接入人体识别和人像分割功能。

先来看下效果,整个图像的是相机的原图,左上角部分,是我们进行人像识别、人像分割后,处理得到的图像 (未做镜像处理,所以暂时和原图左右是相反的)

在这里插入图片描述

那我们要怎么在自己的项目中,实现人像分割功能呢 ?

我们看ncnn-android-yolov8-seg的源码,可以发现, 这个项目里的相机也是用c/c++,但是在我们项目中,使用的Java层的Camera API来实现的。要想在自己项目里集成ncnn,那就需要把ncnn-android-yolov8-seg里的核心代码给抽离,然后对接到JavaCamera API中。

那需要怎么做呢 ? 接下来我们先来看一下它的源码

2. 源码分析

首先,我们来分析一下 Digital2Slave/ncnn-android-yolov8-seg Demo 中的源码

2.1 加载模型

加载模型是在Java_com_tencent_yolov8ncnn_Yolov8Ncnn_loadModel方法中,这里附上源码

JNIEXPORT jboolean JNICALL Java_com_tencent_yolov8ncnn_Yolov8Ncnn_loadModel(JNIEnv* env, jobject thiz, jobject assetManager, jint modelid, jint cpugpu)
{if (modelid < 0 || modelid > 6 || cpugpu < 0 || cpugpu > 1){return JNI_FALSE;}AAssetManager* mgr = AAssetManager_fromJava(env, assetManager);__android_log_print(ANDROID_LOG_DEBUG, "ncnn", "loadModel %p", mgr);const char* modeltypes[] ={"n","s",};const int target_sizes[] ={320,320,};const float mean_vals[][3] ={{103.53f, 116.28f, 123.675f},{103.53f, 116.28f, 123.675f},};const float norm_vals[][3] ={{ 1 / 255.f, 1 / 255.f, 1 / 255.f },{ 1 / 255.f, 1 / 255.f, 1 / 255.f },};const char* modeltype = modeltypes[(int)modelid];int target_size = target_sizes[(int)modelid];bool use_gpu = (int)cpugpu == 1;// reload{ncnn::MutexLockGuard g(lock);if (use_gpu && ncnn::get_gpu_count() == 0){// no gpudelete g_yolo;g_yolo = 0;}else{if (!g_yolo)g_yolo = new Yolo;g_yolo->load(mgr, modeltype, target_size, mean_vals[(int)modelid], norm_vals[(int)modelid], use_gpu);}}return JNI_TRUE;
}
2.1.1 modelid : 选择某个模型

根据modelid,来选择modeltypes中具体的某个模型。

const char* modeltypes[] =
{"n","s",
};
const char* modeltype = modeltypes[(int)modelid];

这里的模型类别是和项目中asserts文件夹下的模型对应的,yolov8是个模型簇,从小到大包括:yolov8nyolov8syolov8myolov8lyolov8x等。
在这里插入图片描述
通常yolov8n速度最快,具体见下表
在这里插入图片描述

2.1.2 cpugpu : 使用CPU或GPU

接着来看Java_com_tencent_yolov8ncnn_Yolov8Ncnn_loadModel方法,
还有一个参数cpugpu是用来决定使用CPU还是GPU0CPU1GPU

bool use_gpu = (int)cpugpu == 1;
2.1.3 初始化模型

最后,调用g_yolo->load()来初始化模型

g_yolo->load(mgr, modeltype, target_size, mean_vals[(int)modelid], norm_vals[(int)modelid], use_gpu);

2.2 操作相机

ncnn-android-yolov8-seg Demo中的相机操作,都是通过NDKCamera API来完成的

static MyNdkCamera* g_camera = 0;JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
{__android_log_print(ANDROID_LOG_DEBUG, "ncnn", "JNI_OnLoad");g_camera = new MyNdkCamera;return JNI_VERSION_1_4;
}
2.2.1 打开相机

打开相机就是调用g_camera->open()

JNIEXPORT jboolean JNICALL Java_com_tencent_yolov8ncnn_Yolov8Ncnn_openCamera(JNIEnv* env, jobject thiz, jint facing)
{if (facing < 0 || facing > 1)return JNI_FALSE;__android_log_print(ANDROID_LOG_DEBUG, "ncnn", "openCamera %d", facing);g_camera->open((int)facing);return JNI_TRUE;
}
2.2.2 关闭相机

关闭相机是调用g_camera->close()

JNIEXPORT jboolean JNICALL Java_com_tencent_yolov8ncnn_Yolov8Ncnn_closeCamera(JNIEnv* env, jobject thiz)
{__android_log_print(ANDROID_LOG_DEBUG, "ncnn", "closeCamera");g_camera->close();return JNI_TRUE;
}

2.3 人体检测

人体检测是和NDKCamera相关联的,在相机回调的on_image_render方法中,完成了人体检测

2.3.1 on_image_render : 进行人体检测

来看一下on_image_render的源码,主要是通过g_yolo->detect()进行人体检测,g_yolo->draw()标注人体位置,用框框出来。

void MyNdkCamera::on_image_render(cv::Mat& rgb) const
{// nanodet{ncnn::MutexLockGuard g(lock);//cv::resize()if (g_yolo){__android_log_print(ANDROID_LOG_DEBUG, "myncnn", "g_yolo:true");auto start = std::chrono::high_resolution_clock::now();std::vector<Object> objects;g_yolo->detect(rgb, objects); //人体检测start = std::chrono::high_resolution_clock::now();g_yolo->draw(rgb, objects); //标注人体位置,用框框出来}else{__android_log_print(ANDROID_LOG_DEBUG, "myncnn", "g_yolo:false");draw_unsupported(rgb);}}draw_fps(rgb); //绘制当前多少帧率
}
2.3.2 on_image_render 什么时候被调用 ?

那么on_image_render方法是什么时候被调用的呢 ? 来看ndkcamera.cpp中的on_image方法

可以看到,这里会对NV21图像做裁剪和旋转操作,再转成RGB格式,然后才传递给on_image_render()方法处理

// crop and rotate nv21
cv::Mat nv21_croprotated(roi_h + roi_h / 2, roi_w, CV_8UC1);
{const unsigned char* srcY = nv21 + nv21_roi_y * nv21_width + nv21_roi_x;unsigned char* dstY = nv21_croprotated.data;ncnn::kanna_rotate_c1(srcY, nv21_roi_w, nv21_roi_h, nv21_width, dstY, roi_w, roi_h, roi_w, rotate_type);const unsigned char* srcUV = nv21 + nv21_width * nv21_height + nv21_roi_y * nv21_width / 2 + nv21_roi_x;unsigned char* dstUV = nv21_croprotated.data + roi_w * roi_h;ncnn::kanna_rotate_c2(srcUV, nv21_roi_w / 2, nv21_roi_h / 2, nv21_width, dstUV, roi_w / 2, roi_h / 2, roi_w, rotate_type);
}// nv21_croprotated to rgb
cv::Mat rgb(roi_h, roi_w, CV_8UC3);
ncnn::yuv420sp2rgb(nv21_croprotated.data, roi_w, roi_h, rgb.data);on_image_render(rgb);
2.3.3 人体检测的流程

也就是说,从相机中得到的NV21数据,会先进行旋转,然后转成RGB格式,再交由g_yolo->detect()进行人体检测,通过g_yolo->draw()来标注人体位置。

到这里,我们核心源码就分析的差不多了,那我们怎么将该功能集成到自己的项目中呢 ?
我们在下一篇文章中来实现下 : Android 在自己的项目接入OpenCV+YOLOv8+NCNN,实现人像分割-CSDN博客。

3. Android 人像识别 系列文章

  • OpenCV相关

    • Visual Studio 2022 cmake配置opencv开发环境_opencv visualstudio配置_氦客的博客-CSDN博客
    • 在Visual Studio上,使用OpenCV实现人脸识别_氦客的博客-CSDN博客
    • Android Studio 接入OpenCV,并实现灰度图效果_氦客的博客-CSDN博客
    • Android 使用OpenCV实现实时人脸识别,并绘制到SurfaceView上_氦客的博客-CSDN博客
  • NCNN+YOLO8相关

    • Android 导入ncnn-android-yolov8-seg : 实现人体识别和人像分割-CSDN博客
    • Android ncnn-android-yolov8-seg源码解析 : 实现人像分割-CSDN博客
    • Android 在自己的项目接入OpenCV+YOLOv8+NCNN,实现人像分割-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/151610.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux CentOS7 vim多窗口编辑

我们在用vim编辑文件时&#xff0c;有各种需求。如有时需要在多个文件之间来回操作&#xff0c;一会关闭一个文件&#xff0c;一会再打开另外一个文件&#xff0c;这样来回操作显得太笨拙。有时&#xff0c;vim编辑多行的大文件&#xff0c;来回查看、编辑前面一部分及最后一部…

NFT合约分析:ERC721A

概述 读者可前往我的博客获得更好的阅读体验。 本文主要介绍标准NFT实现的一个变体&#xff0c;即ERC721A合约实现的相关细节。ERC721A是由著名NFT系列Azuki提出&#xff0c;该系列NFT是著名的蓝筹NFT。本文主要聚焦于Azuki提出的ERC721A合约的代码细节分析。 与传统的ERC72…

C++ 字符串

在本文中&#xff0c;您将学习如何在C中处理字符串。您将学习声明它们&#xff0c;对其进行初始化以及将它们用于各种输入/输出操作。 字符串是字符的集合。C 编程语言中通常使用两种类型的字符串&#xff1a; 作为字符串类对象的字符串&#xff08;标准C 库字符串类&#xff0…

HiveServer2 Service Crashes(hiveServer2 服务崩溃)

Troubleshooting Hive | 5.9.x | Cloudera Documentation 原因&#xff1a;别人用的都好好的&#xff0c;我的集群为什么会崩溃&#xff1f; 1.hive分区表太多(这里没有说具体数量。) 2.并发连接太多&#xff0c;我记的以前默认是200个连接 3.复杂的hive查询访问表的的分区…

【好玩】如何在github主页放一条贪吃蛇

前言 &#x1f34a;缘由 github放小蛇&#xff0c;就问你烧不烧 起因看到大佬github上有一条贪吃蛇扭来扭去&#xff0c;觉得好玩&#xff0c;遂给大家分享一下本狗的玩蛇历程 &#x1f95d;成果初展 贪吃蛇 &#x1f3af;主要目标 实现3大重点 1. github设置主页 2. git…

多功能频率计周期/脉宽/占空比/频率测量verilog,视频/代码

名称&#xff1a;多功能频率计周期、脉宽、占空比、频率测量verilog 软件&#xff1a;Quartus 语言&#xff1a;Verilog 代码功能&#xff1a; 多功能频率计&#xff0c;可测量信号的周期、脉冲宽度、占空比、频率&#xff0c;语言为verilog&#xff0c;quartus软件设计仿真…

【C++设计模式之组合模式:结构型】分析及示例

简介 组合模式是一种结构型设计模式&#xff0c;它能够将对象组合成树形结构以表示“整体-部分”的层次结构&#xff0c;并且能够使用相同的方式处理单个对象和组合对象。组合模式使得客户端可以一致地处理单个对象和组合对象&#xff0c;无需关心具体的对象类型。 组合模式将对…

3D模型格式转换工具HOOPS Exchange助力Halocline开发VR

挑战&#xff1a; 支持客户群使用各种CAD系统和CAD文件格式。快速准确的加载可视化硬件数据。提供访问模型详细信息&#xff0c;同时确保高帧频性能。 结果&#xff1a; 确保支持标准文件格式和来自领先工程软件包的CAD数据。 通过查看简化模型或根据需要访问高层次的细节&am…

文本自动输入/删除的加载动画效果

效果展示 CSS 知识点 绕矩形四周跑的光柱动画实现animation 属性的 steps 属性值运用 页面基础结构实现 <div class"loader"><!-- span 标签是围绕矩形四周的光柱 --><span></span><span></span><span></span>&l…

Javascript中的模块化详解

1.什么是模块化、模块化开发&#xff1f; 事实上模块化开发最终的目的是将程序划分成一个个小的结构&#xff1b; 这个结构中编写属于自己的逻辑代码&#xff0c;有自己的作用域&#xff0c;不会影响到其他的结构&#xff1b; 这个结构可以将自己希望暴露的变量、函数、对象等…

自动驾驶技术的基础知识

自动驾驶技术是现代汽车工业中的一项革命性发展&#xff0c;它正在改变着我们对交通和出行的理解。本文将介绍自动驾驶技术的基础知识&#xff0c;包括其概念、历史发展、分类以及关键技术要素。 1. 自动驾驶概念 自动驾驶是一种先进的交通技术&#xff0c;它允许汽车在没有人…

ADuM1250 ADuM1251 模块 I2C IIC总线2500V电磁隔离 接口保护

功能说明&#xff1a; 1&#xff0c;2500V电磁隔离&#xff0c;2通道双向I2C&#xff1b; 2&#xff0c;支持电压在3到5.5V&#xff0c;最大时钟频率可达1000KHz&#xff1b; 3&#xff0c;将该隔离模块接入总线&#xff0c;可以保护主MCU引脚&#xff0c;降低I2C总线上的干…

周总结【java项目】

项目进度&#xff1a; 学习了JavaFX&#xff0c;下载了sceneBuilder辅助工具构建窗口&#xff08;目前建立了登陆&#xff0c;注册&#xff0c;忘记密码的界面&#xff09;&#xff0c;然后是学习了MySQL的连接&#xff0c;现在的项目是刚连上数据库&#xff1b; 下一步&…

Tasmota系统之外设配置

Tasmota系统之外设配置 &#x1f388;相关篇《ESP32/ESP8266在线刷写Sonoff Tasmota固件以及配置简要》&#x1f516;这里以ESP32配置DS18B20温度传感器和dht11温湿度传感器为例。 ✨如果想接特定型号的显示屏幕&#xff0c;需要下载指定的固件&#xff0c;目前官方所提供的固件…

计算机毕设 招聘网站爬取与大数据分析可视化 - python 分析 可视化 flask

文章目录 0 前言1 课题背景2 实现效果3 Flask框架4 Echarts5 爬虫6 最后 0 前言 &#x1f525; 这两年开始毕业设计和毕业答辩的要求和难度不断提升&#xff0c;传统的毕设题目缺少创新和亮点&#xff0c;往往达不到毕业答辩的要求&#xff0c;这两年不断有学弟学妹告诉学长自…

web漏洞-SSRF服务端请求伪造

目录 SSRF服务端请求伪造一、定义二、漏洞成因三、漏洞探测四、漏洞利用五、复现pikachu靶场SSRF实验&#xff0c;并且探测靶机端口开放情况。六、利用SSRF探测内网环境并获取shell七、绕过技巧八、SSRF防御方案九、总结 SSRF服务端请求伪造 一、定义 SSRF&#xff08;Server-…

vue实现拖拽排序

在业务中列表拖拽排序是比较常见的需求&#xff0c;常见的JS拖拽库有Sortable.js&#xff0c;Vue.Draggable等&#xff0c;大多数同学遇到这种需求也是更多的求助于这些JS库&#xff0c;其实&#xff0c;使用HTML原生的拖放事件来实现拖拽排序并不复杂&#xff0c;结合Vue的tra…

AK F.*ing leetcode 流浪计划之最近公共祖先(倍增算法)

欢迎关注更多精彩 关注我&#xff0c;学习常用算法与数据结构&#xff0c;一题多解&#xff0c;降维打击。 本期话题&#xff1a;在树上查找2个结点的最近公共祖先 问题提出 最近公共祖先定义 最近公共祖先简称 LCA&#xff08;Lowest Common Ancestor&#xff09;。两个节…

机器学习算法分类

学习视频黑马程序员 监督学习 无监督学习 半监督学习 强化学习

Windows11 安全中心页面不可用问题(无法打开病毒和威胁防护)解决方案汇总(图文介绍版)

本文目录 Windows版本与报错信息问题详细图片&#xff1a; 解决方案:方案一、管理员权限&#xff08;若你确定你的电脑只有你一个账户&#xff0c;则此教程无效&#xff0c;若你也不清楚&#xff0c;请阅读后再做打算&#xff09;方案二、修改注册表(常用方案)方案三、进入开发…