首页 > 解决方案 > 如何将此项目更改为 OpenCV 实时人脸检测应用程序?

问题描述

Project是一个与我的 Project 相同的实时图像处理器,但它使用两个值,即输入和输出(我记得这些项目使用框架进行这样的处理)。我改变了它的 native-lib.cpp 文件

#include <jni.h>
#include "opencv2/objdetect.hpp"
#include "opencv2/highgui.hpp"
#include <android/log.h>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>

#define TAG "NativeLib"

using namespace std;
using namespace cv;

extern "C" {
//void detect(Mat& input);
void JNICALL Java_com_example_nativeopencvandroidtemplate_MainActivity_adaptiveThresholdFromJNI(JNIEnv *env, jobject instance, jlong inputAddr, jlong outputAddr) {

    Mat &input = *(Mat *) inputAddr;
    Mat &output = *(Mat *) outputAddr;

    clock_t begin = clock();

    cv::adaptiveThreshold(input, output, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV, 21, 5);

    double total_time = double (clock() - begin ) / CLOCKS_PER_SEC;
    __android_log_print(ANDROID_LOG_INFO, TAG, "adaptiveThreshold computation time = %f seconds\n",  total_time);
}
}

对此

#include <jni.h>
#include "opencv2/objdetect.hpp"
#include "opencv2/highgui.hpp"
#include <android/log.h>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>



using namespace std;
using namespace cv;

extern "C" {
void detect(Mat &input);
void JNICALL
Java_com_example_nativeopencvandroidtemplate_MainActivity_adaptiveThresholdFromJNI(JNIEnv *env, jobject instance,
                                                                                   jlong inputAddr) {

    Mat &input = *(Mat *) inputAddr;
    detect(input);
 }
void detect(Mat &input) {
    String face_cascade_name = "/storage/emulated/0/ony.xml";
    String eyes_cascade_name = "/storage/emulated/0/moe.xml";
    CascadeClassifier face_cascade;
    CascadeClassifier eyes_cascade;


    if (!face_cascade.load(face_cascade_name)) {
        printf("--(!)Error loading\n");
        return;
    };
    if (!eyes_cascade.load(eyes_cascade_name)) {
        printf("--(!)Error loading\n");
        return;
    };


    std::vector<Rect> faces;
    Mat frame_gray;


    cvtColor( input, frame_gray, COLOR_RGB2GRAY );
    equalizeHist(frame_gray, frame_gray);

    //-- Detect faces
    face_cascade.detectMultiScale(frame_gray, faces, 1.1, 2, 0 | CASCADE_SCALE_IMAGE, Size(30, 30));

    for (size_t i = 0; i < faces.size(); i++) {
        Point center(faces[i].x + faces[i].width * 0.5, faces[i].y + faces[i].height * 0.5);
        ellipse(input, center, Size(faces[i].width * 0.5, faces[i].height * 0.5), 0, 0, 360, Scalar(255, 0, 255), 4, 8,
                0);

        Mat faceROI = frame_gray(faces[i]);
        std::vector<Rect> eyes;

        //-- In each face, detect eyes
        eyes_cascade.detectMultiScale(faceROI, eyes, 1.1, 2, 0 | CASCADE_SCALE_IMAGE, Size(30, 30));

        for (size_t j = 0; j < eyes.size(); j++) {
            Point center(faces[i].x + eyes[j].x + eyes[j].width * 0.5, faces[i].y + eyes[j].y + eyes[j].height * 0.5);
            int radius = cvRound((eyes[j].width + eyes[j].height) * 0.25);
            circle(input, center, radius, Scalar(255, 0, 0), 4, 8, 0);
        }
    }
}
}

但是在我的手机中,黑屏可能持续了五秒钟,并且应用程序反复停止。

注意:同步和构建已成功,在我更改 cpp 文件之前,应用程序已成功运行

请帮助我了解我的项目。

谢谢

标签: androidc++opencvjava-native-interface

解决方案


在这里,您对 C++ 方法Java_com_example_nativeopencvandroidtemplate_MainActivity_adaptiveThresholdFromJNI的定义进行了一些更改,因此您必须在 Kotlin 端反映这些更改,因为此方法是使用 JNI从您的MainActivity.kt调用的。这是您必须在MainActivity.kt中调整的代码:

class MainActivity : Activity(), CameraBridgeViewBase.CvCameraViewListener2 {

    ...

    override fun onCameraFrame(inputFrame: CameraBridgeViewBase.CvCameraViewFrame): Mat {
        val mat = inputFrame.gray()

        adaptiveThresholdFromJNI(mat.nativeObjAddr)

        return mat
    }

    private external fun adaptiveThresholdFromJNI(matAddr: Long)

    ...

}

在这里, adaptiveThresholdFromJNI被调整为只处理一个参数(就像您对 C++ 等效项所做的那样),然后从onCameraFrame返回一个参数以显示在屏幕上。

我在您的 C++ 代码中看到您尝试做的第一件事是将输入的Mat转换为gray,但这不是必需的,因为传递给您的 C++ 代码的Matval mat = inputFrame.gray()已经是灰色的(请参阅 参考资料)。

如果您想保持您的 C++ 代码完整,您还可以使用val mat = inputFrame.rgba().


推荐阅读