0

Hi I'm trying to implementing motion detect using opencv on android. I applied sample motion detection code and made jni call. I ran this on android, it works but processed preview is super slow. I removed motion detection process part then preview worked normally. How can I improve the the performance? I added my source code for motion detect and jni. please check and advice me.

    import java.util.ArrayList;
    import java.util.List;

    import org.opencv.android.BaseLoaderCallback;
    import org.opencv.android.CameraBridgeViewBase;
    import org.opencv.android.CameraBridgeViewBase.CvCameraViewFrame;
    import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2;
    import org.opencv.android.LoaderCallbackInterface;
    import org.opencv.android.OpenCVLoader;
    import org.opencv.core.Core;
    import org.opencv.core.CvType;
    import org.opencv.core.Mat;
    import org.opencv.core.MatOfPoint;
    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 android.annotation.SuppressLint;
    import android.app.Activity;
    import android.content.Intent;
    import android.hardware.Camera;
    import android.media.MediaRecorder;
    import android.os.Bundle;
    import android.os.CountDownTimer;
    import android.os.Handler;
    import android.os.Message;
    import android.util.Log;
    import android.view.MotionEvent;
    import android.view.WindowManager;
    import android.widget.TextView;
    import android.widget.Toast;


    public class CameraViewActivity extends Activity implements
    CvCameraViewListener2 {

        private CameraBridgeViewBase m_OpenCvCameraView;
        private Mat m_inputMat;
        private Mat m_dstMat;
        private Mat m_motionAvgMat;
        private Mat m_grayMat;
        private Mat m_diffMat;
        private Mat m_scaleMat;
        private static Mat m_contourKernel;
        private static Mat m_hierarchy;
        private Point m_rectPoint1;
        private Point m_rectPoint2;
        private static Point m_contourPoint;
        private Scalar m_rectColor;
        private Size m_kSize;
        private Size m_frameSize;
        private double m_totalPixels;
        private double m_motionPercent;

        private boolean isRecording = false;
        private boolean isMotionDetect = false;

        private Camera m_Camera;
        private MediaRecorder m_MediaRecorder;
        private Runnable m_Runnable;
        private Handler m_TimerHandler;
        private TextView m_tvTimer;
        private int value = 0;
        private CountDownTimer timer;

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

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

        @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.local_camera_view);
            m_OpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.local_camera_surface_view);
            m_OpenCvCameraView.setCvCameraViewListener(this);
            m_tvTimer = (TextView)findViewById(R.id.tv_timer);
        }


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

        @Override
        public void onResume()
        {
            super.onResume();
            OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_8, this, mLoaderCallback);
        }

        public void onDestroy() {
            super.onDestroy();
            if (m_OpenCvCameraView != null)
                m_OpenCvCameraView.disableView();
            m_inputMat.release();
            m_dstMat.release();
            m_motionAvgMat.release();
            m_grayMat.release();
            m_diffMat.release();
            m_scaleMat.release();
            m_contourKernel.release();
            m_hierarchy.release();
        }

        public void onCameraViewStarted(int width, int height) {
            m_inputMat = new Mat();
            m_dstMat = new Mat();
            m_motionAvgMat = null;
            m_grayMat = new Mat();
            m_diffMat = new Mat();
            m_scaleMat = new Mat();
            m_rectPoint1 = new Point();
            m_rectPoint2 = new Point();
            m_rectColor = new Scalar(0, 255, 0);
            m_kSize = new Size(8, 8);
            m_motionPercent = 0.0;
            m_contourKernel = Imgproc.getStructuringElement(Imgproc.MORPH_DILATE, new Size(3, 3), new Point(1, 1));
            m_hierarchy = new Mat();
            m_contourPoint = new Point(-1, -1);
            startTimer();
        }

        public void startTimer(){

            timer = new CountDownTimer(5 * 1000, 1000) {
                @Override
                public void onTick(long millisUntilFinished) {
                    value++;
                    m_tvTimer.setText("Test Value = " + value);
                }

                @Override
                public void onFinish() {
                    timer.cancel();
                }           
            };
            timer.start();
        }

        public void onCameraViewStopped() {
            m_inputMat.release();
            m_dstMat.release();
            m_motionAvgMat.release();
            m_grayMat.release();
            m_diffMat.release();
            m_scaleMat.release();
            m_contourKernel.release();
            m_hierarchy.release();
        }


        @Override
        public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
            m_inputMat = inputFrame.rgba();
            // TODO Auto-generated method stub
            m_frameSize= m_inputMat.size();
            m_totalPixels = m_frameSize.area();

            GussianBlur(m_inputMat.getNativeObjAddr(), m_dstMat.getNativeObjAddr());
            if (m_motionAvgMat == null) {
                m_motionAvgMat = m_dstMat.clone();
                m_motionAvgMat.convertTo(m_motionAvgMat, CvType.CV_32F);
            }
            AccumulateWeighted(m_dstMat.getNativeObjAddr(), m_motionAvgMat.getNativeObjAddr());
            ConvertScaleAbs(m_motionAvgMat.getNativeObjAddr(), m_scaleMat.getNativeObjAddr());
            Absdiff(m_dstMat.getNativeObjAddr(), m_scaleMat.getNativeObjAddr(), m_diffMat.getNativeObjAddr());
            CvtColor(m_diffMat.getNativeObjAddr(), m_grayMat.getNativeObjAddr());
            Threshold(m_grayMat.getNativeObjAddr(), m_grayMat.getNativeObjAddr());
            m_motionPercent = 100.0 * Core.countNonZero(m_grayMat) / m_totalPixels;

            if (m_motionPercent > 1.0) {
                m_motionAvgMat = m_dstMat.clone();
                m_motionAvgMat.convertTo(m_motionAvgMat, CvType.CV_32F);
                CloneConverTo(m_motionAvgMat.getNativeObjAddr(),m_dstMat.getNativeObjAddr());
            }
            List<Rect> movementLocations = contours(m_grayMat);
            if (m_motionPercent > 1.0) {
                for (Rect rect : movementLocations) {
                    m_rectPoint1.x = rect.x;
                    m_rectPoint1.y = rect.y;
                    m_rectPoint2.x = rect.x + rect.width;
                    m_rectPoint2.y = rect.y + rect.height;
                    Core.rectangle(m_inputMat, m_rectPoint1, m_rectPoint2, m_rectColor, 2);
                }
                isMotionDetect = true;
                m_handler.sendEmptyMessage(MOTION_DETECT);
            }else
            {
                isMotionDetect = false;
            }

            return m_inputMat;

        }

        Handler m_handler = new Handler() {

            @SuppressLint("NewApi")
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                case MOTION_DETECT:            
                    Toast toast = Toast.makeText(CameraViewActivity.this, "Motion detect!!!!", 
                            Toast.LENGTH_SHORT); 
                    toast.show(); 
                    if(isRecording==false)
                    {
                        RecordVideo();
                        isRecording=true;
                    }
                    break;
                }
            }
        };

        public static List<Rect> contours(final Mat source) {
            Imgproc.dilate(source, source, m_contourKernel, m_contourPoint, 15);
            Imgproc.erode(source, source, m_contourKernel, m_contourPoint, 10);
            final List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
            Imgproc.findContours(source, contours, m_hierarchy, Imgproc.RETR_TREE,
                    Imgproc.CHAIN_APPROX_SIMPLE);
            List<Rect> rectList = new ArrayList<Rect>();
            // Convert MatOfPoint to Rectangles
            for (MatOfPoint mop : contours) {
                rectList.add(Imgproc.boundingRect(mop));
            }
            return rectList;
        }
        public native void GussianBlur(long matAddrGr, long matAddrRgba);
        public native void CloneConverTo(long matAddrGr, long matAddrRgba);
        public native void AccumulateWeighted(long matAddrGr, long matAddrRgba);
        public native void ConvertScaleAbs(long matAddrGr, long matAddrRgba);
        public native void Absdiff(long matAddrGr, long matAddrRgba, long matDiff);
        public native void CvtColor(long matAddrGr, long matAddrRgba);
        public native void Threshold(long matAddrGr, long matAddrRgba);
        public native void RecordVideo();
    }

JNI CALL

extern "C" {
JNIEXPORT void JNICALL Java_com_xx_xx_CameraViewActivity_GussianBlur(JNIEnv*, jobject, jlong addrGray, jlong addrRgba);

JNIEXPORT void JNICALL Java_com_xx_xx_CameraViewActivity_GussianBlur(JNIEnv*, jobject, jlong addrGray, jlong addrRgba)
{
Mat& mInput  = *(Mat*)addrGray;
Mat& mDst = *(Mat*)addrRgba;
cv::GaussianBlur(mInput, mDst, cv::Size(3, 3), -1);
}

JNIEXPORT void JNICALL Java_com_xx_xx_CameraViewActivity_CloneConverTo(JNIEnv*, jobject, jlong addrGray, jlong addrRgba);

JNIEXPORT void JNICALL Java_com_xx_xx_CameraViewActivity_CloneConverTo(JNIEnv*, jobject, jlong addrGray, jlong addrRgba)
{
Mat& mDest  = *(Mat*)addrGray;
Mat& mMotionAvgMat = *(Mat*)addrRgba;
mMotionAvgMat = mDest.clone();
}

JNIEXPORT void JNICALL Java_com_xx_xx_CameraViewActivity_AccumulateWeighted(JNIEnv*, jobject, jlong addrGray, jlong addrRgba);

JNIEXPORT void JNICALL Java_com_xx_xx_CameraViewActivity_AccumulateWeighted(JNIEnv*, jobject, jlong addrGray, jlong addrRgba)
{
Mat& mDest  = *(Mat*)addrGray;
Mat& mMortion = *(Mat*)addrRgba;
cv::accumulateWeighted(mDest, mMortion, .03);
}

JNIEXPORT void JNICALL Java_com_xx_xx_CameraViewActivity_ConvertScaleAbs(JNIEnv*, jobject, jlong addrGray, jlong addrRgba);

JNIEXPORT void JNICALL Java_com_xx_xx_CameraViewActivity_ConvertScaleAbs(JNIEnv*, jobject, jlong addrGray, jlong addrRgba)
{
Mat& mMortion  = *(Mat*)addrGray;
Mat& mScale = *(Mat*)addrRgba;
cv::convertScaleAbs(mMortion, mScale);
}

JNIEXPORT void JNICALL Java_com_xx_xx_CameraViewActivity_Absdiff(JNIEnv*, jobject, jlong addrGray, jlong addrRgba, jlong addDiff);

JNIEXPORT void JNICALL Java_com_xx_xx_CameraViewActivity_Absdiff(JNIEnv*, jobject, jlong addrGray, jlong addrRgba, jlong addDiff)
{
Mat& mDest  = *(Mat*)addrGray;
Mat& mScale = *(Mat*)addrRgba;
Mat& mDiff = *(Mat*)addDiff;

cv::absdiff(mDest, mScale, mDiff);
}

JNIEXPORT void JNICALL Java_com_xx_xx_CameraViewActivity_CvtColor(JNIEnv*, jobject, jlong addrGray, jlong addrRgba);

JNIEXPORT void JNICALL Java_com_xx_xx_CameraViewActivity_CvtColor(JNIEnv*, jobject, jlong addrGray, jlong addrRgba)
{
Mat& mDiff  = *(Mat*)addrGray;
Mat& mGray = *(Mat*)addrRgba;
cv::cvtColor(mDiff, mGray, 6);
}

JNIEXPORT void JNICALL Java_com_xx_xx_CameraViewActivity_Threshold(JNIEnv*, jobject, jlong addrGray, jlong addrRgba);

JNIEXPORT void JNICALL Java_com_xx_xx_CameraViewActivity_Threshold(JNIEnv*, jobject, jlong addrGray, jlong addrRgba)
{
Mat& mGray  = *(Mat*)addrGray;
Mat& m_Gray = *(Mat*)addrRgba;
cv::threshold(mGray, m_Gray, 25, 255, 0);
}

1 Answers1

0

Can you give a little more details on if you are running on an emulator or on a real device? If you are running on an Emulator, try installing HAXM(https://software.intel.com/en-us/android/articles/intel-hardware-accelerated-execution-manager) and enable Virtualization Technology on your BIOS. Emulator performance significantly improves with HAXM.

G3M
  • 1,023
  • 8
  • 19