Bad performance tracking circles in Android app

asked 2016-06-10 02:55:31 -0500

estensen gravatar image

updated 2016-06-10 02:58:29 -0500

I’m currently building an app that tracks a calibration card with 7 circles and use the colour values from the circles to do some calculations. I’ve tried to build on this tutorial and even though it works the frame rate is really low, even at 640 x 320 on a Nexus 6P. The screen orientation is also in landscape because it didn't fill the screen when it was transposed.

Is there a better way to do this?

public class Detector extends Activity implements CameraBridgeViewBase.CvCameraViewListener2 {

    private static final String  TAG = "OCVSample::Activity";
    private static final int MY_PERMISSIONS_REQUEST_CAMERA_GROUP = 0;
    public final static String EXTRA_CIRCLES = "com.company.app.CIRCLES";

    private Mat mRgba;
    private Mat mGray;
    private Scalar mBlobColorRgba;
    private Scalar mBlobColorHsv;

    private CameraBridgeViewBase mOpenCvCameraView;

    private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
        @Override
        public void onManagerConnected(int status) {
            switch (status) {
                case LoaderCallbackInterface.SUCCESS:
                {
                    Log.i(TAG, "OpenCV loaded successfully");
                    // Load native library after(!) OpenCV initialization
                    //System.loadLibrary("mixed_sample");
                    mOpenCvCameraView.enableView();
                } break;
                default:
                {
                    super.onManagerConnected(status);
                } break;
            }
        }
    };

    public Detector() {
        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);

        ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        Log.i(TAG, String.format("Large memory class: %d MB", activityManager.getLargeMemoryClass()));

        // Here, thisActivity is the current activity
        if (ContextCompat.checkSelfPermission(this,
                Manifest.permission.CAMERA)
                != PackageManager.PERMISSION_GRANTED) {

            if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                    Manifest.permission.CAMERA)) {

            } else {
                ActivityCompat.requestPermissions(this,
                        new String[]{Manifest.permission.CAMERA},
                        MY_PERMISSIONS_REQUEST_CAMERA_GROUP);
            }
        }

        requestWindowFeature(Window.FEATURE_NO_TITLE);

        if (!OpenCVLoader.initDebug()) {
            // Handle initialization error
        }

        // Fullscreen
        if (Build.VERSION.SDK_INT < 16) {
            getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                    WindowManager.LayoutParams.FLAG_FULLSCREEN);
        } else {
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        }

        // Stay on
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        setContentView(R.layout.custom_camera);

        mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.color_blob_detection_activity_surface_view);
        // Compatibility and performance
        // 1280 x 720 => ~3fps
        // 640 x 360 => ~12fps
        mOpenCvCameraView.setMaxFrameSize(640,360);
        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()) {
            OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_1_0, this, mLoaderCallback);
        } else {
            mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
        }
    }

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

    public void onCameraViewStarted(int width, int height) {
        mRgba = new Mat(height, width, CvType.CV_8UC4);
        mGray = new Mat(height, width, CvType.CV_8UC1);
        mBlobColorRgba = new Scalar(255);
        mBlobColorHsv = new Scalar(255);
    }

    public void onCameraViewStopped() {
        mRgba.release();
        mGray.release();
    }

    public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
        mRgba = inputFrame.rgba();
        mGray = inputFrame.gray();

        // Convert to grayscale
        int colorChannels = (mRgba.channels() == 3) ? Imgproc.COLOR_BGR2GRAY
                : ((mRgba.channels() == 4) ? Imgproc.COLOR_BGRA2GRAY : 1);

        // Convert image to grayscale
        Imgproc.cvtColor(mRgba, mGray, colorChannels);

        // Reduce the noise so we avoid false circle detection
        Imgproc.GaussianBlur(mGray, mGray, new Size(9, 9), 2, 2);

        // Use screen size as reference point
        int screen_width = mRgba.width(), screen_height = mRgba.height();

        // Parameters for circle detection accumulator value
        double dp = 1.2d;
        // minimum distance between the center coordinates of detected circles in pixels
        double minDist = 70;

        // min and max radius
        int minRadius = screen_height / 20, maxRadius = screen_height / 3;

        // param1 = gradient value used to handle ...
(more)
edit retag flag offensive close merge delete