使用MSDK实现自定义模型的识别检测功能
1、 在github上寻找开源的,部署到安卓平台的项目,最开始是在自己的手机上做实验,发现跑不通,寻找问题,最终是图像转换的问题。
2、 然后训练自己的代码,读程序,了解思路,C++,JNI因为我们需要实例分割与目标识别都需要,然后我创建了一个抽象的yolo类,通过多态的方式实现了针对不同的模型,目标检测与实例分割的结合的操作。
3、 加载航线模板,通过创建航线模板,进行数据替换的方式,完成航线模板的制作。
4、 程序的融合,由于遥控器平台是无人机推流的方式,所以需要进行桢监听的控制,出现了一个bug,模型切换与模型的执行是处于不同线程的函数,所以我通过加锁的方式实现了互斥
最终效果,实现了人体检测,
cameraStreamManager.addFrameListener(LEFT_OR_MAIN, ICameraStreamManager.FrameFormat.RGBA_8888, (ICameraStreamManager.CameraFrameListener) (frameData, offset, length, width, height, format) -> {
yolov8.byte2Mat(frameData, width, height, surfaceView.getHolder().getSurface(), res); //这里res返回5个值
for (int item : res) {
Log.d("yolov8ncnnJava", "value " + item);
}
Log.d("yolov8ncnn", "return");
});
这里调用了视频的监听函数,然后通过JNI调用C++编写的识别函数
#define TAG "yolov8ncnn"
JNIEXPORT void JNICALL Java_com_inspect_guangfu_Jninterface_Yolov8Ncnn_byte2Mat(JNIEnv *env, jobject thiz, jbyteArray in, jint w, jint h, jobject surface, jintArray res){
jint len = env->GetArrayLength(res);
jint * res_point = env->GetIntArrayElements(res, NULL);
if(surface == NULL || surface == nullptr){
__android_log_print(ANDROID_LOG_DEBUG, TAG, "surface null");
return;
}
ANativeWindow* win = ANativeWindow_fromSurface(env, surface);
if(win == nullptr || win == NULL){
__android_log_print(ANDROID_LOG_DEBUG, TAG, "win null");
return;
}
if(in == nullptr){
__android_log_print(ANDROID_LOG_DEBUG, TAG, "in array null");
return;
}
__android_log_print(ANDROID_LOG_DEBUG, TAG, "width %d", ANativeWindow_getWidth(win));
__android_log_print(ANDROID_LOG_DEBUG, TAG, "height %d", ANativeWindow_getHeight(win));
int32_t win_w = ANativeWindow_getWidth(win);
int32_t win_h = ANativeWindow_getHeight(win);
jsize length = env->GetArrayLength(in);
jbyte *data = env->GetByteArrayElements(in, NULL);
cv::Mat src(h, w, CV_8UC4, (unsigned char *)data);
cv::Mat dst(h, w, CV_8UC3);
cv::cvtColor(src, dst, cv::COLOR_RGBA2RGB);
cv::resize(dst, dst, cv::Size(win_w, win_h));
cv::resize(src, src, cv::Size(win_w, win_h));
env->ReleaseByteArrayElements(in, data, 0);
std::vector<Object> objects;
std::vector<int>res_data;
{
ncnn::MutexLockGuard g(lock);
if (g_yolo != nullptr || g_yolo != NULL ||g_yolo != 0) {
g_yolo->detect(dst, objects, 0.5, 0.5, false);
g_yolo->draw(dst, objects, res_data); // 绘制图像,同时生成结果图
cv::cvtColor(dst, dst, cv::COLOR_RGB2RGBA);
if(g_yolo->getReturnNum() == 2&&!res_data.empty()){
memcpy(res_point, res_data.data(), len * sizeof(int));
// for (int i = 0; i < 4; ++i) {
// __android_log_print(ANDROID_LOG_DEBUG, TAG, "res_point %d", res_point[i]);
// __android_log_print(ANDROID_LOG_DEBUG, TAG, "res_data %d", res_data[i]);
// }
env->ReleaseIntArrayElements(res, res_point, 0);
}
}
}
ANativeWindow_setBuffersGeometry(win, win_w, win_h, AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM);
ANativeWindow_Buffer windowBuffer;
if(int err = ANativeWindow_lock(win, &windowBuffer, nullptr)){
ANativeWindow_release(win);
return;
}
else{
memcpy(windowBuffer.bits, dst.data, windowBuffer.width * windowBuffer.height * 4);
if(int err = ANativeWindow_unlockAndPost(win))
__android_log_print(ANDROID_LOG_DEBUG, "yolov8ncnn", "error code: %s", strerror(err));
}
ANativeWindow_release(win);
return;
}
函数内部完成识别、绘制、以及视频流装载的功能。如有需要可以一起讨论。这里主要涉及到一些图像转换的基本知识。