|
|
@@ -1,6 +1,9 @@ |
|
|
|
package com.example.ueberwachungssystem.Detection; |
|
|
|
|
|
|
|
import android.Manifest; |
|
|
|
import android.app.Activity; |
|
|
|
import android.content.Context; |
|
|
|
import android.content.pm.PackageManager; |
|
|
|
import android.graphics.Bitmap; |
|
|
|
import android.graphics.ImageFormat; |
|
|
|
import android.media.Image; |
|
|
@@ -14,6 +17,7 @@ import androidx.camera.core.ExperimentalGetImage; |
|
|
|
import androidx.camera.core.ImageAnalysis; |
|
|
|
import androidx.camera.core.Preview; |
|
|
|
import androidx.camera.lifecycle.ProcessCameraProvider; |
|
|
|
import androidx.core.app.ActivityCompat; |
|
|
|
import androidx.core.content.ContextCompat; |
|
|
|
import androidx.lifecycle.LifecycleOwner; |
|
|
|
|
|
|
@@ -47,17 +51,20 @@ public class VideoDetector extends Detector { |
|
|
|
|
|
|
|
// Calling Activity |
|
|
|
private final Context context; |
|
|
|
// Permission handling |
|
|
|
private static final int CAMERA_PERMISSION_REQUEST_CODE = 3691; |
|
|
|
// Camera Provider |
|
|
|
private ProcessCameraProvider cameraProvider; |
|
|
|
private Boolean isDetectionRunning = false; |
|
|
|
// Detection |
|
|
|
private Mat previousImage = null; |
|
|
|
private boolean isDetectionRunning = false; |
|
|
|
|
|
|
|
// Debugging |
|
|
|
private Mat previousImage = null; |
|
|
|
public ImageView imageView1 = null; |
|
|
|
public ImageView imageView2 = null; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Parameters |
|
|
|
private static final float PIXEL_THRESHOLD = 40f; // Luminosity (brightness channel of YUV_420_888) |
|
|
|
private static final int BLUR_KERNEL_SIZE = 5; |
|
|
@@ -79,6 +86,15 @@ public class VideoDetector extends Detector { |
|
|
|
this.context = context; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* Get State of the Detector |
|
|
|
*/ |
|
|
|
public boolean isRunning() { |
|
|
|
return isDetectionRunning; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* Starts the Video Detection |
|
|
|
* */ |
|
|
@@ -87,6 +103,10 @@ public class VideoDetector extends Detector { |
|
|
|
if (isDetectionRunning) |
|
|
|
return; |
|
|
|
|
|
|
|
if (!isCameraAccessAllowed()){ |
|
|
|
getCameraAccess(); |
|
|
|
} |
|
|
|
|
|
|
|
// Open CV startup check |
|
|
|
if (!OpenCVLoader.initDebug()) { |
|
|
|
Log.e("OpenCV", "Unable to load OpenCV!"); |
|
|
@@ -121,6 +141,19 @@ public class VideoDetector extends Detector { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* Permission handling |
|
|
|
*/ |
|
|
|
private boolean isCameraAccessAllowed() { |
|
|
|
return ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED; |
|
|
|
} |
|
|
|
|
|
|
|
private void getCameraAccess() { |
|
|
|
if (!isCameraAccessAllowed()) |
|
|
|
ActivityCompat.requestPermissions((Activity) context, new String[]{android.Manifest.permission.CAMERA}, CAMERA_PERMISSION_REQUEST_CODE); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* Binds the Luminosity Analyzer (configure and run Analysis) |
|
|
|
* @param cameraProvider: CameraProvider of Context passed by Constructor |
|
|
@@ -177,6 +210,12 @@ public class VideoDetector extends Detector { |
|
|
|
}.start(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* Process Image to be used for Motion Detection |
|
|
|
* |
|
|
|
* @param image: OpenCV Mat file that should be processed |
|
|
|
*/ |
|
|
|
private Mat processImage(Mat image){ |
|
|
|
if (previousImage == null) { |
|
|
|
previousImage = image; |
|
|
@@ -184,7 +223,7 @@ public class VideoDetector extends Detector { |
|
|
|
} |
|
|
|
|
|
|
|
Mat mat = addGaussianBlur(image, BLUR_KERNEL_SIZE); |
|
|
|
mat = thresholdPixels(mat, previousImage, PIXEL_THRESHOLD); |
|
|
|
mat = thresholdPixels(mat, previousImage); |
|
|
|
mat = dilateNonZero(mat, DILATE_KERNEL_SIZE); |
|
|
|
mat = thresholdContourArea(mat, CONTOUR_THRESHOLD); |
|
|
|
|
|
|
@@ -192,6 +231,12 @@ public class VideoDetector extends Detector { |
|
|
|
return mat; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Convert Android Image to OpenCV Mat file with only y-Channel |
|
|
|
* |
|
|
|
* @param img: Android Image |
|
|
|
* @return yChannel of Image in OpenCV Mat Format |
|
|
|
*/ |
|
|
|
private Mat extractYChannel(@NonNull Image img) { |
|
|
|
ByteBuffer yBuffer = img.getPlanes()[0].getBuffer(); |
|
|
|
byte[] yData = new byte[yBuffer.remaining()]; |
|
|
@@ -203,17 +248,28 @@ public class VideoDetector extends Detector { |
|
|
|
return yMat; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private Mat thresholdPixels(Mat inputMat, Mat previousImage, float luminosityThreshold){ |
|
|
|
/** |
|
|
|
* Threshold all Pixels |
|
|
|
* @param inputMat: Input Image |
|
|
|
* @param previousImage: previous Image (openCV Mat) |
|
|
|
* @return Binary Mat Image |
|
|
|
*/ |
|
|
|
private Mat thresholdPixels(Mat inputMat, Mat previousImage){ |
|
|
|
Mat diffImage = new Mat(); |
|
|
|
Core.absdiff(inputMat, previousImage, diffImage); |
|
|
|
|
|
|
|
Mat binaryMat = new Mat(); |
|
|
|
Imgproc.threshold(diffImage, binaryMat, luminosityThreshold, 255, Imgproc.THRESH_BINARY); |
|
|
|
Imgproc.threshold(diffImage, binaryMat, VideoDetector.PIXEL_THRESHOLD, 255, Imgproc.THRESH_BINARY); |
|
|
|
|
|
|
|
return binaryMat; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Dilate Pixels of Binary Image |
|
|
|
* @param inputMat: Input Image |
|
|
|
* @param kernelSize: kernel Size |
|
|
|
* @return binary Image with dilated Pixels |
|
|
|
*/ |
|
|
|
private Mat dilateNonZero(Mat inputMat, int kernelSize){ |
|
|
|
Mat dilatedMat = new Mat(); |
|
|
|
Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new org.opencv.core.Size(kernelSize, kernelSize)); |
|
|
@@ -221,12 +277,25 @@ public class VideoDetector extends Detector { |
|
|
|
return dilatedMat; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Add Gaussian Blur to OpenCV Mat Image |
|
|
|
* @param inputMat: Input Image |
|
|
|
* @param kernelSize: kernel Size |
|
|
|
* @return Mat Image |
|
|
|
*/ |
|
|
|
private Mat addGaussianBlur(Mat inputMat, int kernelSize){ |
|
|
|
Mat outputMat = new Mat(); |
|
|
|
Imgproc.GaussianBlur(inputMat, outputMat, new org.opencv.core.Size(kernelSize, kernelSize), 0); |
|
|
|
return outputMat; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
* Filter Contour Areas by Size |
|
|
|
* @param inputMat: Input Image |
|
|
|
* @param areaThreshold: Threshold |
|
|
|
* @return Binary Mat Image |
|
|
|
*/ |
|
|
|
private Mat thresholdContourArea(Mat inputMat, float areaThreshold){ |
|
|
|
List<MatOfPoint> contours = new ArrayList<>(); |
|
|
|
Mat hierarchy = new Mat(); |
|
|
@@ -246,6 +315,11 @@ public class VideoDetector extends Detector { |
|
|
|
return outputMat; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Count all Pixels that are non Zero |
|
|
|
* @param inputImage: Input Image in OpenCV Mat Format |
|
|
|
* @return Count of Pixels that are non zero |
|
|
|
*/ |
|
|
|
private int countNonZeroPixels(Mat inputImage) { |
|
|
|
if (inputImage != null) |
|
|
|
return Core.countNonZero(inputImage); |
|
|
@@ -253,6 +327,11 @@ public class VideoDetector extends Detector { |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Show OpenCV Mat on ImageView |
|
|
|
* @param mat: current OpenCV Mat Image |
|
|
|
* @param imageView: ImageView xml-Element |
|
|
|
*/ |
|
|
|
private void debugMat(Mat mat, ImageView imageView) { |
|
|
|
if (imageView == null || mat == null) |
|
|
|
return; |