title: Motion detect using opencv on android
body: <p>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.  </p>
  
  <pre><code>    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 &gt; 1.0) {
                  m_motionAvgMat = m_dstMat.clone();
                  m_motionAvgMat.convertTo(m_motionAvgMat, CvType.CV_32F);
                  CloneConverTo(m_motionAvgMat.getNativeObjAddr(),m_dstMat.getNativeObjAddr());
              }
              List&lt;Rect&gt; movementLocations = contours(m_grayMat);
              if (m_motionPercent &gt; 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&lt;Rect&gt; contours(final Mat source) {
              Imgproc.dilate(source, source, m_contourKernel, m_contourPoint, 15);
              Imgproc.erode(source, source, m_contourKernel, m_contourPoint, 10);
              final List&lt;MatOfPoint&gt; contours = new ArrayList&lt;MatOfPoint&gt;();
              Imgproc.findContours(source, contours, m_hierarchy, Imgproc.RETR_TREE,
                      Imgproc.CHAIN_APPROX_SIMPLE);
              List&lt;Rect&gt; rectList = new ArrayList&lt;Rect&gt;();
              // 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();
      }
  </code></pre>
  
  <p>JNI CALL</p>
  
  <pre><code>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&amp; mInput  = *(Mat*)addrGray;
  Mat&amp; 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&amp; mDest  = *(Mat*)addrGray;
  Mat&amp; 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&amp; mDest  = *(Mat*)addrGray;
  Mat&amp; 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&amp; mMortion  = *(Mat*)addrGray;
  Mat&amp; 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&amp; mDest  = *(Mat*)addrGray;
  Mat&amp; mScale = *(Mat*)addrRgba;
  Mat&amp; 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&amp; mDiff  = *(Mat*)addrGray;
  Mat&amp; 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&amp; mGray  = *(Mat*)addrGray;
  Mat&amp; m_Gray = *(Mat*)addrRgba;
  cv::threshold(mGray, m_Gray, 25, 255, 0);
  }
  </code></pre>