LBP Cascade (OpenCV) 无法在 android studio 模拟器上加载

LBP Cascade (OpenCV) won't load on android studio emulator

我一直在尝试进行一些对象跟踪,并且我设法在 C++ 中使用 OpenCV 3.1 获得了一个不错的 LBP 级联跟踪器 运行。

我想尝试在 phone 上安装这个机器人追踪器 运行,所以我正在尝试将其转移到 AndroidStudio。不幸的是,除了实际的级联加载之外,一切都在工作。我可以让相机在应用程序中拉起,我可以让它显示灰度图像而不是 rgb 图像,等等。只是级联不会加载,所以整个事情都不会起作用。

规格:Android Studio 1.5.1 模拟 API 19 phone(使用 x86 google api),使用 Opencv 3.1.0。

有问题的 CameraActivity 代码在这里 -

package <package name retracted for reasons>;

import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.CameraBridgeViewBase;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewFrame;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;

import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SurfaceView;
import android.view.WindowManager;
import android.widget.Toast;

import java.util.Vector;

import <package name retracted here for reasons>.R;

public class CameraActivity extends Activity implements CameraBridgeViewBase.CvCameraViewListener2 {
    private static final String TAG = "OCVSample::Activity";

    private CameraBridgeViewBase mOpenCvCameraView;
    private boolean              mIsJavaCamera = true;
    private MenuItem             mItemSwitchCamera = null;

    private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
        @Override
        public void onManagerConnected(int status) {
            switch (status) {
                case LoaderCallbackInterface.SUCCESS:
                {
                    Log.i(TAG, "OpenCV loaded successfully");
                    mOpenCvCameraView.enableView();
                } break;
                default:
                {
                    super.onManagerConnected(status);
                } break;
            }
        }
    };

    public CameraActivity() {
        Log.i(TAG, "Instantiated new " + this.getClass());
    }


    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        Log.i(TAG, "called onCreate");
        super.onCreate(savedInstanceState);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        setContentView(R.layout.camera_surface_view);

        mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.tutorial1_activity_java_surface_view);

        mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE);

        mOpenCvCameraView.setCvCameraViewListener(this);


    }

    @Override
    public void onPause()
    {
        super.onPause();
        if (mOpenCvCameraView != null)
            mOpenCvCameraView.disableView();
    }

    @Override
    public void onResume()
    {
        super.onResume();
        if (!OpenCVLoader.initDebug()) {
            Log.d(TAG, "Internal OpenCV library not found. Using OpenCV Manager for initialization");
            OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_0_0, this, mLoaderCallback);
        } else {
            Log.d(TAG, "OpenCV library found inside package. Using it!");
            mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
        }
    }

    public void onDestroy() {
        super.onDestroy();
        if (mOpenCvCameraView != null)
            mOpenCvCameraView.disableView();
    }

    CascadeClassifier robot_cascade;
    public void onCameraViewStarted(int width, int height) {

        Log.d(TAG, "Trying to get robot cascade");

        robot_cascade = new CascadeClassifier(Environment.getExternalStorageDirectory().getAbsolutePath() + "/cascade.xml");
        String robot_cascade_name = Environment.getExternalStorageDirectory().getAbsolutePath() + "/cascade.xml";

        Log.d(TAG, "location is "+robot_cascade_name);

        if(robot_cascade.empty()){
            Log.d(TAG, "--(!)Error loading robot cascade");
        }
        Log.d(TAG, "Made it through loading cascade!");
    }

    public void onCameraViewStopped() {
    }

    public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
        Mat frameGrey = new Mat();
        Mat endFrame = new Mat();
        endFrame = inputFrame.rgba();
        MatOfRect robots = new MatOfRect();
        Imgproc.cvtColor(inputFrame.rgba(), frameGrey, Imgproc.COLOR_BGRA2GRAY);
        Imgproc.equalizeHist(frameGrey, frameGrey);

        /*robot_cascade.detectMultiScale(frameGrey, robots, 1.2, 120, 0, new Size(200, 200), new Size(300, 300));
        Log.d(TAG, "Found %x robots" + robots.toArray().length);

        for (Rect rect : robots.toArray()) {
            Imgproc.rectangle(endFrame, new Point(rect.x, rect.y), new Point(rect.x + rect.width, rect.y + rect.height), new Scalar(0, 255, 0));
            Log.d(TAG, "Robot at point ( %x , %x )"+(rect.x+rect.width/2)+(rect.y+rect.height/2));
        } */

        return endFrame;
        //return inputFrame.rgba();
    }
}

现在,我在 cascade.detectMultiScale 不起作用时将其注释掉了。 运行 它产生:

01-26 21:07:42.085 2296-2296/? D/OCVSample::Activity: Trying to get robot cascade  
01-26 21:07:42.085 2296-2296/? D/OCVSample::Activity: location is /storage/sdcard/cascade.xml  
01-26 21:07:42.085 2296-2296/? D/OCVSample::Activity: --(!)Error loading robot cascade   
01-26 21:07:42.085 2296-2296/? D/OCVSample::Activity: Made it through loading cascade!

然后它愉快地进入 onCameraFrame 方法,目前只输出它得到的东西(我已经能够使用它来获得灰度等等)

问题似乎出在 onCameraViewStared class -

public void onCameraViewStarted(int width, int height) {

        Log.d(TAG, "Trying to get robot cascade");
        robot_cascade = new CascadeClassifier(Environment.getExternalStorageDirectory().getAbsolutePath() + "/cascade.xml");
        String robot_cascade_name = Environment.getExternalStorageDirectory().getAbsolutePath() + "/cascade.xml";

        Log.d(TAG, "location is "+robot_cascade_name);

        if(robot_cascade.empty()){
            Log.d(TAG, "--(!)Error loading robot cascade");
        }
        Log.d(TAG, "Made it through loading cascade!");
    }

机器人级联总是空着。

我确定 cascade.xml 实际上在模拟的 phone 上 - 如果我通过 adb 检查,它说那里很冷,而且 android 设备监视器也显示它在那里。

我唯一能想到的是ADM说权限是-rwxrwx---,但是我在清单文件中有WRITE_EXTERNAL_STORAGEREAD_EXTERNAL_STORAGE权限,所以我想那样就好了。 (虽然我可能完全错了,如果我错了请纠正我)。

以防万一它很重要,我确实尝试 chmod cascade.xml 被任何用户(不仅仅是所有者和组)read/writable,但它一直给我"Bad Mode" 不管我怎么努力。 sd 挂载为 read/writeable(因为我首先能够将文件推送到 sd 卡上),而且我在 su 中,所以我不知道为什么它不让我这样做。

编辑:chmod 有非常奇怪的行为 - 它基本上不会做任何事情并安静地失败,或者它会说它是一个只读文件系统......即使我可以文件和目录并删除它们没问题。

编辑 x2:将文件移动到 /data/local,它仍然不起作用,但 chmod 处理了它,所以现在我拥有所有权限。仍在尝试弄清楚为什么级联不会加载它。

是的,无法加载肯定在模拟 SD 卡上的级联。

所以,让它在模拟器上运行(终于)。显然模拟器上的 SD 卡根本不允许 chmod 工作,所以我将文件移动到 data/local。然后我将所有内容更改为从 ("./data/local/cascade.xml") 读取,并在创建级联分类器后添加 robot_cascade.load(".data/local/cascade.xml);。然后我取消注释实际使用级联的东西,它工作得很漂亮。

所以,新的 onCameraViewStarted 方法 -

public void onCameraViewStarted(int width, int height) {
    Log.d(TAG, "Prog: Trying to get robot cascade");

    File file = new File("./data/local/cascade.xml");
    boolean fileExists = file.exists();
    String fileDoesExist = String.valueOf(fileExists);

    Log.d(TAG, "Prog: Does the cascade file exist? "+fileDoesExist);

    robot_cascade = new CascadeClassifier("./data/local/cascade.xml");
    robot_cascade.load("./data/local/cascade.xml");
    String robot_cascade_name = "./data/local/cascade.xml";

    Log.d(TAG, "Prog: location is "+robot_cascade_name);

    if(robot_cascade.empty()){
        Log.d(TAG, "Prog: --(!)Error loading robot cascade");
    } else {
        Log.d(TAG, "Prog: --Holy smite the cascade is actually there praise the sun");
    }
    Log.d(TAG, "Prog: Made it through loading cascade!");
}

当然,现在我正试图让它在 phone 上运行而不是模拟,但这是行不通的,但这是另一个问题的问题。