123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327 |
- package com.example.ueberwachungssystem.Detection;
-
- import android.Manifest;
- import android.annotation.SuppressLint;
- import android.content.Context;
- import android.content.pm.PackageManager;
- import android.graphics.ImageFormat;
- import android.media.Image;
- import android.os.CountDownTimer;
- import android.util.Log;
- import android.view.Display;
- import android.view.Surface;
- import android.view.WindowManager;
- import android.widget.ImageView;
- import android.widget.Toast;
-
- import androidx.annotation.NonNull;
- import androidx.annotation.Nullable;
- import androidx.camera.core.CameraSelector;
- import androidx.camera.core.ExperimentalGetImage;
- import androidx.camera.core.ImageAnalysis;
- import androidx.camera.core.ImageProxy;
- import androidx.camera.core.Preview;
- import androidx.camera.core.VideoCapture;
- import androidx.camera.lifecycle.ProcessCameraProvider;
- import androidx.camera.view.PreviewView;
- import androidx.core.app.ActivityCompat;
- import androidx.core.content.ContextCompat;
- import androidx.lifecycle.LifecycleOwner;
-
- import com.google.common.util.concurrent.ListenableFuture;
-
- import org.opencv.android.OpenCVLoader;
- import org.opencv.core.Mat;
- import org.opencv.core.Size;
-
- import java.io.File;
- import java.time.LocalDateTime;
- import java.time.format.DateTimeFormatter;
- import java.util.concurrent.ExecutionException;
-
-
- /**
- * Video Detector inherits some methods from abstract Detector class (more info there)
- * USE FROM MAIN ACTIVITY:
- * VideoDetector vd = new VideoDetector(this);
- * */
-
-
- @ExperimentalGetImage
- public class VideoDetector extends Detector {
- // Calling Activity
- private final Context context;
-
- // Camera Provider
- private ProcessCameraProvider cameraProvider;
- private ImageAnalysis imageAnalysis;
- private VideoCapture videoCapture;
- //private Preview preview;
-
- // Logic
- private boolean isDetecting = false;
- private boolean isRecording = false;
- private boolean allowReportViolation = false;
-
- // Image Processing
- private Mat previousImage = null;
-
- // Debugging
- private ImageView inputImageView = null;
- private ImageView outputImageView = null;
-
- // Recorder
- private File outputDir; // Default: in app files directory
-
-
- // Parameters
- private static final float ALARM_THRESHOLD = 0f; // Percent of pixels changed
- private static final float AREA_THRESHOLD = 10f;
- private static final int DILATE_ITERATIONS = 2;
- private static final float START_DELAY = 20000; // milliseconds
- private static final android.util.Size IMAGE_RES = new android.util.Size(640, 480);
-
-
-
- /** Constructor */
- public VideoDetector(Context context) {
- super();
- this.context = context;
- this.imageAnalysis = setupImageAnalysis();
- this.videoCapture = setupVideoCapture();
- this.outputDir = context.getFilesDir();
- //this.preview = new Preview.Builder().build();
- }
-
- /** Get States */
- public boolean isDetecting() {
- return isDetecting;
- }
- public boolean isRecording(){
- return isRecording;
- }
-
-
- /** Starts the Video Detection */
- @Override
- public void startDetection() {
- // Check States
- if (isDetecting)
- return;
- // Configure Image Analysis
- imageAnalysis = setupImageAnalysis();
- // Open CV startup check
- if (!OpenCVLoader.initDebug()) {
- Log.e("OpenCV", "Unable to load OpenCV!");
- return;
- } else
- Log.d("OpenCV", "OpenCV loaded Successfully!");
- // Get Process Camera Provider and start
- final ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(context);
- cameraProviderFuture.addListener(() -> {
- try {
- cameraProvider = cameraProviderFuture.get();
- isDetecting = true;
- bindCameraProvider();
- } catch (ExecutionException | InterruptedException e) {}
- }, ContextCompat.getMainExecutor(context));
- // Disable Violation Calling for Setup Time
- startViolationTimer(START_DELAY);
- }
-
- /** Starts the Recorder */
- @SuppressLint("RestrictedApi")
- public void startRecording() {
- // Check States
- if (isRecording){
- return;
- }
-
- videoCapture = setupVideoCapture();
-
- final ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(context);
- cameraProviderFuture.addListener(() -> {
- try {
- cameraProvider = cameraProviderFuture.get();
- isRecording = true;
- bindCameraProvider();
-
- File vidFile = new File(context.getFilesDir() + "/" + generateFileName() + ".mp4");
- if (ActivityCompat.checkSelfPermission(context, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
- return;
- }
- videoCapture.startRecording(
- new VideoCapture.OutputFileOptions.Builder(vidFile).build(),
- context.getMainExecutor(),
- new VideoCapture.OnVideoSavedCallback() {
- @Override
- public void onVideoSaved(@NonNull VideoCapture.OutputFileResults outputFileResults) {
- isRecording = false;
- Toast.makeText(context, "video recording saved", Toast.LENGTH_SHORT).show();
- }
- @Override
- public void onError(int videoCaptureError, @NonNull String message, @Nullable Throwable cause) {
- isRecording = false;
- Toast.makeText(context, "video recording failed", Toast.LENGTH_SHORT).show();
- }
- }
- );
- } catch (ExecutionException | InterruptedException ignored) {}
- }, ContextCompat.getMainExecutor(context));
- }
-
- /** Stops the Video Detection */
- @Override
- public void stopDetection() {
- if (!isDetecting || imageAnalysis == null)
- return;
- cameraProvider.unbind(imageAnalysis);
- isDetecting = false;
- allowReportViolation = false;
- }
-
- /** Stops the Recording */
- @SuppressLint("RestrictedApi")
- public void stopRecording(){
- if(!isRecording)
- return;
-
- videoCapture.stopRecording();
- cameraProvider.unbind(videoCapture);
- isRecording = false;
- }
-
- /** Bind Camera Provider */
- private void bindCameraProvider() {
- // Specify which Camera to use
- CameraSelector cameraSelector = new CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build();
- cameraProvider.unbindAll();
- cameraProvider.bindToLifecycle((LifecycleOwner) context, cameraSelector, imageAnalysis, videoCapture);
- }
-
- /** Setup Use Cases */
- private ImageAnalysis setupImageAnalysis() {
- // Configure and create Image Analysis
- ImageAnalysis.Builder builder = new ImageAnalysis.Builder();
- builder.setTargetResolution(IMAGE_RES);
- builder.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST);
- builder.setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_YUV_420_888);
- builder.setTargetRotation(Surface.ROTATION_90);
- ImageAnalysis imageAnalysis = builder.build();
- // Set Analyzer
- imageAnalysis.setAnalyzer(ContextCompat.getMainExecutor(context), imageProxy -> {
- if (imageProxy.getFormat() == ImageFormat.YUV_420_888) {
- Image image = imageProxy.getImage();
- assert image != null;
-
- // Violation Handling
- Mat processed = processImage(imageProxy);
-
- int n = OpenCVHelper.countNonZeroPixels(processed);
- int pixelCount = image.getWidth() * image.getHeight();
- float percentChanged = (float) n / pixelCount;
-
- // Violation Condition
- if (percentChanged * 100 > ALARM_THRESHOLD) {
- if (allowReportViolation)
- reportViolation("Video", percentChanged);
- }
- }
- imageProxy.close();
- });
- return imageAnalysis;
- }
-
- @SuppressLint("RestrictedApi")
- private VideoCapture setupVideoCapture() {
- int rotation = getDisplayRotation();
- return new VideoCapture.Builder()
- .setTargetRotation(rotation)
- .build();
- }
-
- /** Process Image to be used for Motion Detection */
- private Mat processImage(ImageProxy imageProxy){
- if (imageProxy == null)
- return null;
- // Image Transformation
- Mat imageMat = OpenCVHelper.extractYChannel(imageProxy);
- // Show Input Image
- if (inputImageView != null)
- OpenCVHelper.debugMat(imageMat, inputImageView);
- // Preprocess Image
- Mat preprocessed = imageMat;
- preprocessed = OpenCVHelper.addGaussianBlur(preprocessed, new Size(21, 21));
- preprocessed = OpenCVHelper.addBlur(preprocessed, new Size(3, 3));
- // Set Previous Image
- if (previousImage == null) {
- previousImage = preprocessed;
- return null;
- }
- // Process Image
- Mat processed = preprocessed.clone();
- processed = OpenCVHelper.thresholdPixels(processed, previousImage, 25);
-
- for(int i = 0; i < DILATE_ITERATIONS; i++)
- processed = OpenCVHelper.dilateBinaryMat(processed, new Size(3,3));
-
- processed = OpenCVHelper.thresholdContourArea(processed, AREA_THRESHOLD);
- // Output
- previousImage = preprocessed.clone();
- // Show Output Image
- if (outputImageView != null)
- OpenCVHelper.debugMat(processed, outputImageView);
- return processed;
- }
-
-
- /** Debug input and result of processing */
- public void debugProcessing(@NonNull ImageView inputImageView, @NonNull ImageView outputImageView){
- this.inputImageView = inputImageView;
- this.outputImageView = outputImageView;
- }
-
- /**
- private void setPreviewView(@NonNull PreviewView previewView) {
- // Create Preview
- if (this.preview != null)
- this.preview.setSurfaceProvider(previewView.getSurfaceProvider());
- }
- */
-
-
- /** Generate File Name */
- private String generateFileName(){
- // Get the current timestamp
- LocalDateTime currentTime = LocalDateTime.now();
- // Define the format for the timestamp
- DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss");
- // Return the timestamp as a string
- return currentTime.format(formatter);
- }
-
-
- /** Get current Display Rotation */
- private int getDisplayRotation() {
- WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
- Display display = windowManager.getDefaultDisplay();
- return display.getRotation();
- }
-
- /** Start delay until Violation Report is allowed */
- private void startViolationTimer(float setupTime) {
- new CountDownTimer((long) (START_DELAY), 100) {
- @Override
- public void onTick(long millisUntilFinished) {
- }
- @Override
- public void onFinish() {
- allowReportViolation = true;
- }
- }.start();
- }
-
- public void setOutputDir(File outputDir) {
- this.outputDir = outputDir;
- }
- }
|