diff --git a/Neues Textdokument.txt b/Neues Textdokument.txt deleted file mode 100644 index e69de29..0000000 diff --git a/app/build.gradle b/app/build.gradle index 631248a..4d7dcc8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -36,4 +36,13 @@ dependencies { testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' + + // Required for CameraX + def camerax_version = "1.2.2" + implementation "androidx.camera:camera-core:${camerax_version}" + implementation "androidx.camera:camera-camera2:${camerax_version}" + implementation "androidx.camera:camera-lifecycle:${camerax_version}" + implementation "androidx.camera:camera-video:${camerax_version}" + implementation "androidx.camera:camera-view:${camerax_version}" + implementation "androidx.camera:camera-extensions:${camerax_version}" } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index cef8f3d..36b1460 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,9 @@ + + + cameraProviderFuture = ProcessCameraProvider.getInstance(context); + //Check for Camera availability + cameraProviderFuture.addListener(() -> { + try { + cameraProvider = cameraProviderFuture.get(); + bindAnalysis(cameraProvider); + isDetectionRunning = true; + previousBuffer = null; + } catch (ExecutionException | InterruptedException e) { + // No errors need to be handled for this Future. This should never be reached. + } + },ContextCompat.getMainExecutor(context)); + } + + + /** + * Stops the Video Detection + * */ + @Override + public void stopDetection() { + if (!isDetectionRunning) + return; + cameraProvider.unbindAll(); + isDetectionRunning = false; + } + + + /** + * Set PreviewView to show video feed while detecting + * this is optional and does not need to be called + * */ + public void setPreviewView(PreviewView previewView) { + this.previewView = previewView; + } + + + /** + * Binds the Luminosity Analyzer (configure and run Analysis) + * @param cameraProvider: CameraProvider of Context passed by Constructor + * */ + private void bindAnalysis(@NonNull ProcessCameraProvider cameraProvider) { + // Configure and create Image Analysis + ImageAnalysis.Builder builder = new ImageAnalysis.Builder(); + builder.setTargetResolution(new Size(640, 480)); + builder.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST); + builder.setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_YUV_420_888); + 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; + + // Changed Pixel Detection + int pixelChanged = getChangedPixelCount(image); + int width = image.getWidth(); + int height = image.getHeight(); + + float percentPixelChanged = (float) 100f * pixelChanged / (width * height); + + if (percentPixelChanged > ALARM_THRESHOLD) + reportViolation("0", "Video", percentPixelChanged); + } + imageProxy.close(); + }); + // Create Preview + Preview preview = new Preview.Builder().build(); + // Specify which Camera to use + CameraSelector cameraSelector = new CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build(); + // Update PreviewView if set + if (previewView != null) + preview.setSurfaceProvider(previewView.getSurfaceProvider()); + + cameraProvider.bindToLifecycle((LifecycleOwner) context, cameraSelector, imageAnalysis, preview); + } + + + + /** + * Calculate Amount of Pixels changed using a threshold + * @param image + * */ + private int getChangedPixelCount(Image image) { + Image.Plane[] planes = image.getPlanes(); + ByteBuffer buffer = planes[0].getBuffer(); + + if (previousBuffer == null) { + previousBuffer = ByteBuffer.allocate(buffer.capacity()); + buffer.rewind(); + previousBuffer.put(buffer); + previousBuffer.rewind(); + return 0; + } + + int width = image.getWidth(); + int height = image.getHeight(); + + int yRowStride = image.getPlanes()[0].getRowStride(); + int yPixelStride = image.getPlanes()[0].getPixelStride(); + + int changedPixelCount = 0; + + // Count changed pixels + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; x++) { + int index = (y * yRowStride) + (x * yPixelStride); + int luminosity = (buffer.get(index) & 0xff); + int previousLuminosity = (previousBuffer.get(index) & 0xff); + int diff = Math.abs(luminosity - previousLuminosity); + if (diff > PIXEL_THRESHOLD) + changedPixelCount++; + } + } + + // Reset and copy Byte Buffer + buffer.rewind(); + previousBuffer.rewind(); + previousBuffer.put(buffer); + + return changedPixelCount; + } +}