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);
}