xuning

实现人像检测

@@ -55,7 +55,16 @@ class MainViewModel(application: Application) : AndroidViewModel(application) { @@ -55,7 +55,16 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
55 ), 55 ),
56 ) 56 )
57 57
58 - private val processor = OpencvVideoProcessor() 58 + private val processor = OpencvVideoProcessor().apply {
  59 + // Load model before processing to avoid unsupported overlay
  60 + // modelId: 0=mobilenetv3, sizeId: 6=640, intraInter:1, postproc:0(fast), cpuGpu:0(CPU)
  61 + try {
  62 + val ok = loadModel(application.assets, 0, 0, 1, 0, 0)
  63 + android.util.Log.d("MainViewModel", "OpencvVideoProcessor.loadModel result=$ok")
  64 + } catch (t: Throwable) {
  65 + android.util.Log.e("MainViewModel", "loadModel failed", t)
  66 + }
  67 + }
59 68
60 private var cameraProvider: CameraCapturerUtils.CameraProvider? = null 69 private var cameraProvider: CameraCapturerUtils.CameraProvider? = null
61 70
@@ -38,6 +38,9 @@ public class OpencvVideoProcessor extends NoDropVideoProcessor { @@ -38,6 +38,9 @@ public class OpencvVideoProcessor extends NoDropVideoProcessor {
38 } 38 }
39 } 39 }
40 40
  41 + // Load model before processing to avoid unsupported overlay
  42 + public native boolean loadModel(android.content.res.AssetManager mgr, int modelId, int sizeId, int intraInterId, int postprocId, int cpuGpu);
  43 +
41 // Core native that processes I420 in/out fully in cpp 44 // Core native that processes I420 in/out fully in cpp
42 private static native boolean processI420ToI420( 45 private static native boolean processI420ToI420(
43 ByteBuffer y, int yStride, 46 ByteBuffer y, int yStride,
@@ -287,6 +287,93 @@ JNIEXPORT jboolean JNICALL Java_io_livekit_android_track_processing_video_RVMNcn @@ -287,6 +287,93 @@ JNIEXPORT jboolean JNICALL Java_io_livekit_android_track_processing_video_RVMNcn
287 return JNI_TRUE; 287 return JNI_TRUE;
288 } 288 }
289 289
  290 +// duplicate loadModel for OpencvVideoProcessor
  291 +JNIEXPORT jboolean JNICALL Java_io_livekit_android_track_processing_video_OpencvVideoProcessor_loadModel(JNIEnv* env, jobject thiz, jobject assetManager, jint modelid, jint sizeid, jint intrainterid, jint postprocid, jint cpugpu)
  292 +{
  293 + if (modelid < 0 || modelid > 1 || sizeid < 0 || sizeid > 6 || intrainterid < 0 || intrainterid > 1 || postprocid < 0 || postprocid > 2 || cpugpu < 0 || cpugpu > 2)
  294 + {
  295 + return JNI_FALSE;
  296 + }
  297 +
  298 + AAssetManager* mgr = AAssetManager_fromJava(env, assetManager);
  299 +
  300 + __android_log_print(ANDROID_LOG_DEBUG, "ncnn", "loadModel %p (OpencvVideoProcessor)", mgr);
  301 +
  302 + const char* modeltypes[2] =
  303 + {
  304 + "mobilenetv3",
  305 + "resnet50"
  306 + };
  307 +
  308 + const int sizetypes[7] =
  309 + {
  310 + 256,
  311 + 320,
  312 + 384,
  313 + 448,
  314 + 512,
  315 + 576,
  316 + 640
  317 + };
  318 +
  319 + std::string parampath = std::string("rvm_") + modeltypes[(int)modelid] + ".ncnn.param";
  320 + std::string modelpath = std::string("rvm_") + modeltypes[(int)modelid] + ".ncnn.bin";
  321 + bool use_gpu = (int)cpugpu == 1;
  322 + bool use_turnip = (int)cpugpu == 2;
  323 +
  324 + {
  325 + ncnn::MutexLockGuard g(lock);
  326 +
  327 + {
  328 + // reset inter feats
  329 + g_feats.r1.release();
  330 + g_feats.r2.release();
  331 + g_feats.r3.release();
  332 + g_feats.r4.release();
  333 +
  334 + static int old_modelid = 0;
  335 + static int old_cpugpu = 0;
  336 + if (modelid != old_modelid || cpugpu != old_cpugpu)
  337 + {
  338 + delete g_rvm;
  339 + g_rvm = 0;
  340 + }
  341 + old_modelid = modelid;
  342 + old_cpugpu = cpugpu;
  343 +
  344 + ncnn::destroy_gpu_instance();
  345 +
  346 + if (use_turnip)
  347 + {
  348 + ncnn::create_gpu_instance("libvulkan_freedreno.so");
  349 + }
  350 + else if (use_gpu)
  351 + {
  352 + ncnn::create_gpu_instance();
  353 + }
  354 +
  355 + if (!g_rvm)
  356 + {
  357 + g_rvm = new RVM;
  358 +
  359 + g_rvm->load(mgr, parampath.c_str(), modelpath.c_str(), use_gpu || use_turnip);
  360 + }
  361 + g_rvm->set_model_type((int)modelid);
  362 + g_rvm->set_target_size(sizetypes[(int)sizeid]);
  363 + g_rvm->set_intra_inter((int)intrainterid);
  364 +
  365 + if (postprocid == 0)
  366 + g_rvm->set_postproc_mode(false, true, false);
  367 + if (postprocid == 1)
  368 + g_rvm->set_postproc_mode(false, false, true);
  369 + if (postprocid == 2)
  370 + g_rvm->set_postproc_mode(true, false, false);
  371 + }
  372 + }
  373 +
  374 + return JNI_TRUE;
  375 +}
  376 +
290 // public native boolean openCamera(int facing); 377 // public native boolean openCamera(int facing);
291 JNIEXPORT jboolean JNICALL Java_io_livekit_android_track_processing_video_RVMNcnn_openCamera(JNIEnv* env, jobject thiz, jint facing) 378 JNIEXPORT jboolean JNICALL Java_io_livekit_android_track_processing_video_RVMNcnn_openCamera(JNIEnv* env, jobject thiz, jint facing)
292 { 379 {
@@ -498,24 +585,41 @@ JNIEXPORT jboolean JNICALL Java_io_livekit_android_track_processing_video_Opencv @@ -498,24 +585,41 @@ JNIEXPORT jboolean JNICALL Java_io_livekit_android_track_processing_video_Opencv
498 585
499 // Wrap as a single-channel Mat (H + H/2) x W and convert to BGR 586 // Wrap as a single-channel Mat (H + H/2) x W and convert to BGR
500 cv::Mat i420_mat(height + height / 2, width, CV_8UC1, i420_in.data()); 587 cv::Mat i420_mat(height + height / 2, width, CV_8UC1, i420_in.data());
501 - cv::Mat bgr;  
502 - cv::cvtColor(i420_mat, bgr, cv::COLOR_YUV2BGR_I420); 588 + cv::Mat rgb;
  589 + cv::cvtColor(i420_mat, rgb, cv::COLOR_YUV2RGB_I420);
  590 + // Rotate to upright orientation for the model
  591 + if (rotation == 90) {
  592 + cv::rotate(rgb, rgb, cv::ROTATE_90_CLOCKWISE);
  593 + } else if (rotation == 180) {
  594 + cv::rotate(rgb, rgb, cv::ROTATE_180);
  595 + } else if (rotation == 270) {
  596 + cv::rotate(rgb, rgb, cv::ROTATE_90_COUNTERCLOCKWISE);
  597 + }
503 598
504 // Process with RVM 599 // Process with RVM
505 { 600 {
506 ncnn::MutexLockGuard g(lock); 601 ncnn::MutexLockGuard g(lock);
507 if (g_rvm) { 602 if (g_rvm) {
508 cv::Mat fgr, pha, seg; 603 cv::Mat fgr, pha, seg;
509 - g_rvm->detect(bgr, g_feats, fgr, pha, seg);  
510 - g_rvm->draw(bgr, fgr, pha, seg); 604 + g_rvm->detect(rgb, g_feats, fgr, pha, seg);
  605 + g_rvm->draw(rgb, fgr, pha, seg);
511 } else { 606 } else {
512 - draw_unsupported(bgr); 607 + draw_unsupported(rgb);
  608 + }
513 } 609 }
  610 +
  611 + // Rotate back to original orientation before returning to I420
  612 + if (rotation == 90) {
  613 + cv::rotate(rgb, rgb, cv::ROTATE_90_COUNTERCLOCKWISE);
  614 + } else if (rotation == 180) {
  615 + cv::rotate(rgb, rgb, cv::ROTATE_180);
  616 + } else if (rotation == 270) {
  617 + cv::rotate(rgb, rgb, cv::ROTATE_90_CLOCKWISE);
514 } 618 }
515 619
516 // Convert back to I420 620 // Convert back to I420
517 cv::Mat i420_out; 621 cv::Mat i420_out;
518 - cv::cvtColor(bgr, i420_out, cv::COLOR_BGR2YUV_I420); 622 + cv::cvtColor(rgb, i420_out, cv::COLOR_RGB2YUV_I420);
519 if (i420_out.empty() || i420_out.cols != width || i420_out.rows != height + height / 2) 623 if (i420_out.empty() || i420_out.cols != width || i420_out.rows != height + height / 2)
520 return JNI_FALSE; 624 return JNI_FALSE;
521 625