如何针对特定区域进行Android运动检测

时间:2017-08-20 06:54:01

标签: java android

尝试根据this project制作动作检测应用。目的是通过比较两个图像使应用程序在检测到运动时拍照。到目前为止,该应用程序运行正常。

要求:

指定自定义视图的检测区域。因此,仅当通过计算检测区域在定义区域内检测到运动时才捕获图像。

到目前为止我做了什么:

创建一个可移动的自定义视图,就像裁剪视图一样,每次移动视图时,尺寸(Rect)都会保存在首选项中。

什么不行:

自定义视图内的动作检测无效。我相信必须根据自定义视图的大小裁剪位图才能进行比较。 在检测线程中,我尝试从首选项设置widthheight,例如: private int width = Prefe.DetectionArea.width(); private int height = Prefe.DetectionArea.height();

但它没有用。请帮助我解释如何实现这一点,以便根据自定义视图的大小进行运动检测。任何帮助表示赞赏。

项目源代码:https://drive.google.com/drive/folders/0B7-oKqt7w49mbTR6VWZYVURmVms

MotionDetectionActivity.java

public class MotionDetectionActivity extends SensorsActivity {

private static final String TAG = "MotionDetectionActivity";
private static long mReferenceTime = 0;
private static IMotionDetection detector = null;
public static MediaPlayer song;
public static Vibrator mVibrator;

private static SurfaceView preview = null;
private static SurfaceHolder previewHolder = null;
private static Camera camera = null;
private static boolean inPreview = false;
private static AreaDetectorView mDetector;
private static FrameLayout layoutDetectorArea;
static FrameLayout layoutMain;
static View mView;
private static volatile AtomicBoolean processing = new AtomicBoolean(false);

/**
 * {@inheritDoc}
 */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    setContentView(R.layout.main);

    mVibrator = (Vibrator)this.getSystemService(VIBRATOR_SERVICE);
    layoutMain=(FrameLayout)findViewById(R.id.layoutMain);
    preview = (SurfaceView) findViewById(R.id.preview);
    previewHolder = preview.getHolder();
    previewHolder.addCallback(surfaceCallback);
    previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    mView=layoutMain;
    mDetector= (AreaDetectorView) findViewById(R.id.viewDetector);
    layoutDetectorArea=(FrameLayout) findViewById(R.id.layoutDetectArea);

    ToggleButton toggle = (ToggleButton) findViewById(R.id.simpleToggleButton);
    toggle.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            if (isChecked) {
                // The toggle is enabled


            } else {
                // The toggle is disabled
            }
        }
    });


    if (Preferences.USE_RGB) {
        detector = new RgbMotionDetection();
    } else if (Preferences.USE_LUMA) {
        detector = new LumaMotionDetection();
    } else {
        // Using State based (aggregate map)
        detector = new AggregateLumaMotionDetection();
    }
}

/**
 * {@inheritDoc}
 */
@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
}

/**dd:
 * Song play # 1
 * Camera callback
 *
 * {@inheritDoc}
 */
@Override
public void onPause() {
    super.onPause();
    if(song!=null && song.isPlaying())
    {
        song.stop();}

    camera.setPreviewCallback(null);
    if (inPreview) camera.stopPreview();
    inPreview = false;
    camera.release();
    camera = null;
}

/**
 * {@inheritDoc}
 */
@Override
public void onResume() {
    super.onResume();

    camera = Camera.open();
}

private PreviewCallback previewCallback = new PreviewCallback() {

    /**
     * {@inheritDoc}
     */
    @Override
    public void onPreviewFrame(byte[] data, Camera cam) {
        if (data == null) return;
        Camera.Size size = cam.getParameters().getPreviewSize();
        if (size == null) return;

        if (!GlobalData.isPhoneInMotion()) {
            DetectionThread thread = new DetectionThread(data, size.width, size.height);
            thread.start();
        }
    }
};

private SurfaceHolder.Callback surfaceCallback = new SurfaceHolder.Callback() {

    /**
     * {@inheritDoc}
     */
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        try {

            camera.setPreviewDisplay(previewHolder);
            camera.setPreviewCallback(previewCallback);
        } catch (Throwable t) {
            Log.e("Prek", "Exception in setPreviewDisplay()", t);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        if(camera != null) {
            Camera.Parameters parameters = camera.getParameters();
            parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
            Camera.Size size = getBestPreviewSize(width, height, parameters);
            if (size != null) {
                parameters.setPreviewSize(size.width, size.height);
                Log.d(TAG, "Using width=" + size.width + " height=" + size.height);
            }
            camera.setParameters(parameters);
            camera.startPreview();
            inPreview = true;
        }
        //AreaDetectorView.InitDetectionArea();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        // Ignore
    }
};

private static Camera.Size getBestPreviewSize(int width, int height, Camera.Parameters parameters) {
    Camera.Size result = null;

    for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
        if (size.width <= width && size.height <= height) {
            if (result == null) {
                result = size;
            } else {
                int resultArea = result.width * result.height;
                int newArea = size.width * size.height;

                if (newArea > resultArea) result = size;
            }
        }
    }

    return result;
}

//***************Detection Class******************//

private final class DetectionThread extends Thread {

    private byte[] data;
    private int width;
    private int height;

    public DetectionThread(byte[] data, int width, int height) {
        this.data = data;
        this.width = width;
        this.height = height;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void run() {
        if (!processing.compareAndSet(false, true)) return;

        // Log.d(TAG, "BEGIN PROCESSING...");
        try {
            // Previous frame
            int[] pre = null;
            if (Preferences.SAVE_PREVIOUS) pre = detector.getPrevious();

            // Current frame (with changes)
            // long bConversion = System.currentTimeMillis();
            int[] img = null;
            if (Preferences.USE_RGB) {
                img = ImageProcessing.decodeYUV420SPtoRGB(data, width, height);
            } else {
                img = ImageProcessing.decodeYUV420SPtoLuma(data, width, height);
            }


            // Current frame (without changes)
            int[] org = null;
            if (Preferences.SAVE_ORIGINAL && img != null) org = img.clone();

            if (img != null && detector.detect(img, width, height)) {


                // The delay is necessary to avoid taking a picture while in
                // the
                // middle of taking another. This problem can causes some
                // phones
                // to reboot.
                long now = System.currentTimeMillis();
                if (now > (mReferenceTime + Preferences.PICTURE_DELAY)) {
                    mReferenceTime = now;

                    //mVibrator.vibrate(10);

                    Bitmap previous = null;
                    if (Preferences.SAVE_PREVIOUS && pre != null) {
                        if (Preferences.USE_RGB) previous = ImageProcessing.rgbToBitmap(pre, width, height);
                        else previous = ImageProcessing.lumaToGreyscale(pre, width, height);
                    }

                    Bitmap original = null;
                    if (Preferences.SAVE_ORIGINAL && org != null) {
                        if (Preferences.USE_RGB) original = ImageProcessing.rgbToBitmap(org, width, height);
                        else original = ImageProcessing.lumaToGreyscale(org, width, height);
                    }

                    Bitmap bitmap = null;
                    if (Preferences.SAVE_CHANGES) {
                        if (Preferences.USE_RGB) bitmap = ImageProcessing.rgbToBitmap(img, width, height);
                        else bitmap = ImageProcessing.lumaToGreyscale(img, width, height);
                    }
                    Log.i(TAG, "Saving.. previous=" + previous + " original=" + original + " bitmap=" + bitmap);
                    Looper.prepare();
                    new SavePhotoTask().execute(previous, original, bitmap);
                } else {
                    Log.i(TAG, "Not taking picture because not enough time has passed since the creation of the Surface");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            processing.set(false);
        }
        // Log.d(TAG, "END PROCESSING...");
        processing.set(false);
    }
};

private static final class SavePhotoTask extends AsyncTask<Bitmap, Integer, Integer> {

    /**
     * {@inheritDoc}
     */
    @Override
    protected Integer doInBackground(Bitmap... data) {
        for (int i = 0; i < data.length; i++) {
            Bitmap bitmap = data[i];
            String name = String.valueOf(System.currentTimeMillis());
            if (bitmap != null) save(name, bitmap);
        }
        return 1;
    }

    private void save(String name, Bitmap bitmap) {
        File photo = new File(Environment.getExternalStorageDirectory(), name + ".jpg");
        if (photo.exists()) photo.delete();

        try {
            FileOutputStream fos = new FileOutputStream(photo.getPath());
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
            fos.close();
        } catch (java.io.IOException e) {
            Log.e("PictureDemo", "Exception in photoCallback", e);
        }
    }
}
}

AreaDetectorView.java

public class  AreaDetectorView extends LinearLayout {

public static int Width;
public static int Height;

private static Paint BoxPaint = null;
private static Paint TextPaint = null;
private static Paint ArrowPaint = null;
private static Path mPath = null;
private static Rect mRect = null;
private static int lastX, lastY = 0;
private static boolean mBoxTouched = false;
private static boolean mArrowTouched = false;
private static Context mContext;
private static int ArrowWidth = 0;
private static Paint BoxPaint2 = null;

public AreaDetectorView(Context context) {
    super(context);
    mContext = context;
}
//attrs was not there
public AreaDetectorView(Context context, AttributeSet attrs) {
    super(context,attrs);
    mContext = context;
    // TODO Auto-generated constructor stub
    if (!this.getRootView().isInEditMode()) {
        ArrowWidth =GetDisplayPixel(context, 30);
    }

    //InitDetectionArea();

    InitMemberVariables();
    setWillNotDraw(false);
}
public static int GetDisplayPixel(Context paramContext, int paramInt)
{
    return (int)(paramInt * paramContext.getResources().getDisplayMetrics().density + 0.5F);
}

public static void InitMemberVariables() {
    if (BoxPaint == null) {
        BoxPaint = new Paint();
        BoxPaint.setAntiAlias(true);
        BoxPaint.setStrokeWidth(2.0f);
        //BoxPaint.setStyle(Style.STROKE);
        BoxPaint.setStyle(Style.FILL_AND_STROKE);
        BoxPaint.setColor(ContextCompat.getColor(mContext, R.color.bwff_60));
    }
    if (ArrowPaint == null) {
        ArrowPaint = new Paint();
        ArrowPaint.setAntiAlias(true);
        ArrowPaint.setColor(ContextCompat.getColor(mContext,R.color.redDD));
        ArrowPaint.setStyle(Style.FILL_AND_STROKE);
    }
    if (TextPaint == null) {
        TextPaint = new Paint();
        TextPaint.setColor(ContextCompat.getColor(mContext,R.color.yellowL));
        TextPaint.setTextSize(16);
        //txtPaint.setTypeface(lcd);
        TextPaint.setStyle(Style.FILL_AND_STROKE);
    }
    if (mPath == null) {
        mPath = new Path();
    } else {
        mPath.reset();
    }
    if (mRect == null) {
        mRect = new Rect();
    }

    if (BoxPaint2 == null) {
        BoxPaint2 = new Paint();
        BoxPaint2.setAntiAlias(true);
        BoxPaint2.setStrokeWidth(2.0f);
        //BoxPaint.setStyle(Style.STROKE);
        BoxPaint2.setStyle(Style.STROKE);
        BoxPaint2.setColor(ContextCompat.getColor(mContext,R.color.bwff_9e));
    }

}

public static void InitDetectionArea() {
    try {
        int w = Prefe.DetectionArea.width();
        int h = Prefe.DetectionArea.height();
        int x = Prefe.DetectionArea.left;
        int y = Prefe.DetectionArea.top;

        // ver 2.6.0
        if (Prefe.DetectionArea.left == 1
                && Prefe.DetectionArea.top == 1
                && Prefe.DetectionArea.right == 1
                && Prefe.DetectionArea.bottom == 1) {

            w = Prefe.DisplayWidth / 4;
            h = Prefe.DisplayHeight / 3;

            // ver 2.5.9
            w = Width / 4;
            h = Height / 3;

            Prefe.DetectorWidth = w;    //UtilGeneralHelper.GetDisplayPixel(this, 100);
            Prefe.DetectorHeight = h;   //UtilGeneralHelper.GetDisplayPixel(this, 100);

            x = (Prefe.DisplayWidth / 2) - (w / 2);
            y = (Prefe.DisplayHeight / 2) - (h / 2);

            // ver 2.5.9
            x = (Width / 2) - (w / 2);
            y = (Height / 2) - (h / 2);

        }

        //Prefe.DetectionArea = new Rect(x, x, x + Prefe.DetectorWidth, x + Prefe.DetectorHeight);
        Prefe.DetectionArea = new Rect(x, y, x + w, y + h);

        Prefe.gDetectionBitmapInt = new int[Prefe.DetectionArea.width() * Prefe.DetectionArea.height()];
        Prefe.gDetectionBitmapIntPrev = new int[Prefe.DetectionArea.width() * Prefe.DetectionArea.height()];

    } catch (Exception e) {
        e.printStackTrace();
    }
}

public static void SetDetectionArea(int x, int y, int w, int h) {
    try {
        Prefe.DetectionArea = new Rect(x, y, w, h);

    } catch (Exception e) {
        e.printStackTrace();
    }
}

private void DrawAreaBox(Canvas canvas) {
    try {
    } catch (Exception e) {
        e.printStackTrace();
    }
}

@Override
protected void dispatchDraw(Canvas canvas) {
    try {
        if (this.getRootView().isInEditMode()) {
            super.dispatchDraw(canvas);
            return;
        }

        //canvas.save(Canvas.MATRIX_SAVE_FLAG);
        //Prefe.DetectionAreaOrient = UtilGeneralHelper.GetDetectRectByOrientation();

        canvas.drawColor(0);
        mPath.reset();

        canvas.drawRect(Prefe.DetectionArea, BoxPaint);

        mPath.moveTo(Prefe.DetectionArea.right - ArrowWidth, Prefe.DetectionArea.bottom);
        mPath.lineTo(Prefe.DetectionArea.right, Prefe.DetectionArea.bottom - ArrowWidth);
        mPath.lineTo(Prefe.DetectionArea.right, Prefe.DetectionArea.bottom);
        mPath.lineTo(Prefe.DetectionArea.right - ArrowWidth, Prefe.DetectionArea.bottom);
        mPath.close();
        canvas.drawPath(mPath, ArrowPaint);

        mPath.reset();
        //canvas.drawRect(Prefe.DetectionAreaOrient, BoxPaint2);
        //canvas.drawRect(Prefe.DetectionAreaOrientPort, BoxPaint2);

        TextPaint.setTextSize(16);
        //TextPaint.setLetterSpacing(2);

        TextPaint.setColor(ContextCompat.getColor(mContext,R.color.bwff));

        TextPaint.getTextBounds(getResources().getString(R.string.str_detectarea), 0, 1, mRect);
        canvas.drawText(getResources().getString(R.string.str_detectarea),
                Prefe.DetectionArea.left + 4,
                Prefe.DetectionArea.top + 4 + mRect.height(),
                TextPaint);
        int recH = mRect.height();

        TextPaint.setStrokeWidth(1.2f);
        TextPaint.setTextSize(18);
        TextPaint.setColor(ContextCompat.getColor(mContext,R.color.redD_9e));
        TextPaint.getTextBounds(getResources().getString(R.string.str_dragandmove), 0, 1, mRect);
        canvas.drawText(getResources().getString(R.string.str_dragandmove),
                Prefe.DetectionArea.left + 4,
                Prefe.DetectionArea.top + 20 + mRect.height()*2,
                TextPaint);

        TextPaint.getTextBounds(getResources().getString(R.string.str_scalearea), 0, 1, mRect);
        canvas.drawText(getResources().getString(R.string.str_scalearea),
                Prefe.DetectionArea.left + 4,
                Prefe.DetectionArea.top + 36 + mRect.height()*3,
                TextPaint);

        super.dispatchDraw(canvas);
        //canvas.restore();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

@Override
protected void onDraw(Canvas canvas) {
    try {
        super.onDraw(canvas);
        invalidate();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {

    }
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    boolean retValue = true;
    int X = (int)event.getX();
    int Y = (int)event.getY();



    //AppMain.txtLoc.setText(String.valueOf(X) + ", " + String.valueOf(Y));

    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            mBoxTouched = TouchedInBoxArea(X, Y);

            //AppMain.txtLoc.setText("BoxTouched: " + String.valueOf(mBoxTouched));

            if (!mBoxTouched) break;

            lastX = X;
            lastY = Y;

            BoxPaint.setStyle(Style.FILL_AND_STROKE);
            BoxPaint.setColor(ContextCompat.getColor(mContext,R.color.redD_9e));

            mArrowTouched = TouchedInArrow(X, Y);
            //AppMain.txtLoc.setText("ArrowTouched: " + String.valueOf(mBoxTouched));

            if (mArrowTouched) {
                ArrowPaint.setColor(ContextCompat.getColor(mContext,R.color.bwff_9e));
            }

            break;

        case MotionEvent.ACTION_MOVE:
            if (!mBoxTouched) break;

            int moveX = X - lastX;
            int moveY = Y - lastY;

            //AppMain.txtLoc.setText("Move X, Y: " + String.valueOf(moveX) + "," + String.valueOf(moveY));
            if (!mArrowTouched) {
                if (Prefe.DetectionArea.left + moveX < 0) {
                    break;
                }
//              if (Prefe.DetectionArea.right + moveX > Prefe.gDisplay.getWidth()) {
//                  break;
//              }
                // ver 2.5.9
                if (Prefe.DetectionArea.right + moveX > Width) {
                    break;
                }
                if (Prefe.DetectionArea.top + moveY < 0) {
                    break;
                }
//              if (Prefe.DetectionArea.bottom + moveY > Prefe.gDisplay.getHeight()) {
//                  break;
//              }
                // ver 2.5.9
                if (Prefe.DetectionArea.bottom + moveY > Height) {
                    break;
                }
            }

            if (mArrowTouched) {
                if ((Prefe.DetectionArea.width() + moveX) < ArrowWidth * 2){
                    break;
                }
                if ((Prefe.DetectionArea.height() + moveY) < ArrowWidth * 2) {
                    break;
                }
                Prefe.DetectionArea.right += moveX;
                Prefe.DetectionArea.bottom += moveY;
                //Log.i("DBG", "W,H: " + String.valueOf(Prefe.DetectionArea.width()) + "," + String.valueOf(Prefe.DetectionArea.height()));
            } else {
                Prefe.DetectionArea.left += moveX;
                Prefe.DetectionArea.right += moveX;
                Prefe.DetectionArea.top += moveY;
                Prefe.DetectionArea.bottom += moveY;
            }

            lastX = X;
            lastY = Y;

            //AppMain.txtLoc.setText(String.valueOf(Prefe.DetectionArea.left) + ", " + String.valueOf(Prefe.DetectionArea.top));
            break;

        case MotionEvent.ACTION_UP:
            mBoxTouched = false;
            mArrowTouched = false;
            //BoxPaint.setStyle(Style.STROKE);
            BoxPaint.setStyle(Style.FILL_AND_STROKE);
            BoxPaint.setColor(ContextCompat.getColor(mContext,R.color.bwff_60));
            ArrowPaint.setColor(ContextCompat.getColor(mContext,R.color.redDD));

            //AppMain.txtLoc.setText(String.valueOf(Prefe.DetectionArea.left) + ", " + String.valueOf(Prefe.DetectionArea.top));

            if (Prefe.DetectionArea.left < 0) {
                Prefe.DetectionArea.left = 0;
            }
//          if (Prefe.DetectionArea.right > Prefe.gDisplay.getWidth()) {
//              Prefe.DetectionArea.right = Prefe.gDisplay.getWidth();
//          }
            // ver 2.5.9
            if (Prefe.DetectionArea.right > Width) {
                Prefe.DetectionArea.right = Width;
            }
            if (Prefe.DetectionArea.top < 0) {
                Prefe.DetectionArea.top = 0;
            }
//          if (Prefe.DetectionArea.bottom > Prefe.gDisplay.getHeight()) {
//              Prefe.DetectionArea.bottom = Prefe.gDisplay.getHeight();
//          }
            if (Prefe.DetectionArea.bottom > Height) {
                Prefe.DetectionArea.bottom = Height;
            }

            Prefe.gDetectionBitmapInt = new int[Prefe.DetectionArea.width() * Prefe.DetectionArea.height()];
            Prefe.gDetectionBitmapIntPrev = new int[Prefe.DetectionArea.width() * Prefe.DetectionArea.height()];
            //Prefe.gDetectionBitmapInt = null;
            //Prefe.gDetectionBitmapIntPrev = null;

            String area = String.valueOf(Prefe.DetectionArea.left)
                    + "," + String.valueOf(Prefe.DetectionArea.top)
                    + "," + String.valueOf(Prefe.DetectionArea.right)
                    + "," + String.valueOf(Prefe.DetectionArea.bottom);

           // UtilGeneralHelper.SavePreferenceSetting(Prefe.gContext, Prefe.PREF_DETECTION_AREA_KEY, area);
            //Saving the value
            SharedPrefsUtils.setStringPreference(mContext.getApplicationContext(), Prefe.PREF_DETECTION_AREA_KEY, area);
            Log.v("TAG", SharedPrefsUtils.getStringPreference(mContext.getApplicationContext(),Prefe.PREF_DETECTION_AREA_KEY));


            break;
    }

    invalidate();
    return retValue;
}

private boolean TouchedInBoxArea(int x, int y) {
    boolean retValue = false;
    try {

        if (x > Prefe.DetectionArea.left && x < Prefe.DetectionArea.right) {
            if (y > Prefe.DetectionArea.top && y < Prefe.DetectionArea.bottom) {
                retValue = true;
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return retValue;
}

private boolean TouchedInArrow(int x, int y) {
    boolean retValue = false;
    try {

        if (x > Prefe.DetectionArea.right - ArrowWidth && x < Prefe.DetectionArea.right) {
            if (y > Prefe.DetectionArea.bottom - ArrowWidth && y < Prefe.DetectionArea.bottom) {
                retValue = true;
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return retValue;
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);
    setMeasuredDimension(width, height);
    Width = width;
    Height = height;
    InitDetectionArea();
}

@Override
protected void onFinishInflate() {
    super.onFinishInflate();
}

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    // TODO Auto-generated method stub
    for (int i = 0; i < this.getChildCount()-1; i++){
        (this.getChildAt(i)).layout(l, t, r, b);
    }

    if (changed) {
        // check width height
        if (r != Width || b != Height) {
            // size does not match
        }
    }
}
}

Prefe.java

public class Prefe extends Application{
...
public static final String PREF_DETECTION_AREA_KEY = "pref_detection_area_key";
}
static{
...
DetectionArea = new Rect(1, 1, 1, 1);
}
}

0 个答案:

没有答案