【问题标题】:Using Facemark opencv contrib in android native C++在android原生C++中使用Facemark opencv contrib
【发布时间】:2018-10-18 09:37:00
【问题描述】:

我是 opencv 新手,我正在尝试在我的 android 本机 C++ 应用程序的 opencv contrib 模块中使用 Facemark。但是,我得到了错误

A/libc:致命信号 11 (SIGSEGV),代码 1,tid 中的故障地址 0x1788 21567(my_app)

使用创建 Facemark 实例时

 Ptr<Facemark> facemark = FacemarkLBF::create();

我正在使用https://github.com/chaoyangnz/opencv3-android-sdk-with-contrib opencv 库
这是我的实现 c++

    void
    Java_com_makeover_makeover_1opencv_MainActivity_nativeDetectFaceLandmarks(
            JNIEnv *env,
            jobject , jlong srcAddr, jlong retAddr,
            jstring faceCascadePath, jstring faceYamlPath)
    {
        const char *faceCascadeFile = env->GetStringUTFChars(faceCascadePath,NULL);
        const char *yamlFile = env->GetStringUTFChars(faceYamlPath,NULL);

        LOGI("nativeDetectFace called");
        string cascadePath(faceCascadeFile);

        LOGI("nativeDetectFace called");

        string yamlPath(yamlFile);

        Mat& colorMat = *(Mat*)srcAddr;
        Mat& retValMat = *(Mat*)retAddr;
        Mat gray;

        // Load Face Detector
        CascadeClassifier faceDetector(cascadePath);
        LOGI("cascade file loaded");

        // Create an instance of Facemark
        Ptr<Facemark> facemark = FacemarkLBF::create();

        LOGI("face instance created");


        // Load landmark detector
        facemark->loadModel(yamlPath);

        LOGI("yalm model loaded");

        // Find face
        vector<Rect> faces;
        // Convert frame to grayscale because
        // faceDetector requires grayscale image.
        cvtColor(colorMat, gray, COLOR_BGR2GRAY);

        // Detect faces
        faceDetector.detectMultiScale(gray, faces);

        // Variable for landmarks.
        // Landmarks for one face is a vector of points
        // There can be more than one face in the image. Hence, we
        // use a vector of vector of points.
        vector< vector<Point2f> > landmarks;

        // Run landmark detector
        bool success = facemark->fit(colorMat,faces,landmarks);

        if(success)
        {
            // If successful, render the landmarks on the face
            for(int i = 0; i < landmarks.size(); i++)
            {
                drawLandmarks(colorMat, landmarks[i]);
            }
        }

    }

java实现

    drawFaces.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            Mat colorMat,grayMat;
            colorMat = new Mat();
            grayMat = new Mat();

            Utils.bitmapToMat(bmp,colorMat);

            nativeDetectFaceLandmarks(colorMat.getNativeObjAddr(), grayMat.getNativeObjAddr(),
                    getCascade("face"),getCascade("yaml"));

            Bitmap new_bmp2 = Bitmap.createBitmap(bmp);
            Utils.matToBitmap(colorMat,new_bmp2);

            img_face.setImageBitmap(new_bmp2);

        }
    });

getCascade 方法

    public String getCascade(String cascadeType){
    String fileName;
    File mCascadeFile;
    final InputStream is;
    FileOutputStream os;
    switch (cascadeType){
        case "mouth":
            fileName="haarcascade_mcs_mouth.xml";
            break;
        case "face":
            fileName = "haarcascade_frontalface_alt2.xml";
            break;
        case "right_eye":
            fileName = "haarcascade_mcs_righteye.xml";
            break;

        case "yaml":
            fileName = "lbfmodel.yaml";
            break;


        case "left_eye":
            fileName = "haarcascade_mcs_lefteye.xml";
            break;
        default:
            fileName = null;
    }
    if(fileName==null) {
        return null;
    }
    try {
        is = getResources().getAssets().open(fileName);
        File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);

        mCascadeFile = new File(cascadeDir,fileName);


        os = new FileOutputStream(mCascadeFile);

        byte[] buffer = new byte[4096];
        int bytesRead;
        while ((bytesRead = is.read(buffer)) != -1) {
            os.write(buffer, 0, bytesRead);
        }
        is.close();
        os.close();
        Log.i("TAG", "getCascade: face cascade found");
        return mCascadeFile.getAbsolutePath();
    } catch (IOException e) {
        Log.e("TAG", "face cascade not found", e);
        return null;
    }

}

任何知道我做错了什么或在android native的opencv contrib模块中使用Facemark的更好方法的人

【问题讨论】:

  • 崩溃后的堆栈跟踪是什么? source.android.com/devices/tech/debug
  • link 这是我的堆栈跟踪
  • 从堆栈跟踪中,SIGSEGV 发生在 je_free() 中。你几乎可以肯定在某处破坏了你的堆。您是否在检查每个 JNI 调用的返回值?你怎么知道srcAddrretAddr中的地址是正确的?
  • 可能不相关,但在从输入流读取时尝试传递数组大小:while ((bytesRead = is.read(buffer, 4096)) != -1) 否则您可能会溢出数组

标签: android c++ opencv java-native-interface


【解决方案1】:

到目前为止,我看到的每个教程都以不同的方式实现了此方法,为了澄清这一点,我将介绍适合我的方法。

首先声明facemark下面的方法返回SIGSEGV错误:

Ptr<Facemark> facemark = FacemarkLBF::create();

改为使用:

Ptr<Facemark> facemark = createFacemarkLBF();

其次我看到很多教程使用:

facemark->load(filename);

但正确的语法应该是:

facemark->loadModel(filename);

如果您仍然遇到同样的问题,请点击此链接并下载链接并使用 contrib 获取最新的 SDK:

https://pullrequest.opencv.org/buildbot/export/opencv_releases/

【讨论】:

    猜你喜欢
    • 2015-03-11
    • 2015-07-13
    • 2018-03-11
    • 2014-05-23
    • 2016-07-25
    • 2013-06-14
    • 1970-01-01
    • 1970-01-01
    • 2017-12-15
    相关资源
    最近更新 更多