You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

CameraSensor.java 6.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. package com.example.greenwatch.sensors;
  2. import android.content.Context;
  3. import android.graphics.ImageFormat;
  4. import android.media.Image;
  5. import android.os.Handler;
  6. import android.util.Size;
  7. import androidx.camera.core.CameraSelector;
  8. import androidx.camera.core.ImageAnalysis;
  9. import androidx.camera.lifecycle.ProcessCameraProvider;
  10. import androidx.core.content.ContextCompat;
  11. import androidx.lifecycle.LifecycleOwner;
  12. import androidx.lifecycle.MutableLiveData;
  13. import java.nio.ByteBuffer;
  14. public class CameraSensor {
  15. private final MutableLiveData<Boolean> mVideoAlarmDetected = new MutableLiveData<>();
  16. private static CameraSensor cameraSensorInstance;
  17. private boolean videoAlarmDetected;
  18. private boolean isMotionDetected;
  19. private ByteBuffer previousBuffer;
  20. private int previousWidth;
  21. private int previousHeight;
  22. private final int threshold = 50;
  23. private int startX;
  24. private int startY;
  25. private int endX;
  26. private int endY;
  27. private static final long ALARM_RESET_DELAY = 5000;
  28. private Runnable alarmResetRunnable;
  29. private final Handler alarmResetHandler = new Handler();
  30. private CameraSensor() {
  31. videoAlarmDetected = false;
  32. }
  33. public static synchronized CameraSensor getInstance() {
  34. if (cameraSensorInstance == null){
  35. cameraSensorInstance = new CameraSensor();
  36. }
  37. return cameraSensorInstance;
  38. }
  39. public MutableLiveData<Boolean> getVideoAlarmDetectedValue() {
  40. setMutableLiveDataVideoAlarmDetected();
  41. return mVideoAlarmDetected;
  42. }
  43. private void setMutableLiveDataVideoAlarmDetected() {
  44. mVideoAlarmDetected.setValue(videoAlarmDetected);
  45. }
  46. public void bindImageAnalysis(ProcessCameraProvider cameraProvider, LifecycleOwner lifecycleOwner, Context context) {
  47. ImageAnalysis.Builder builder = new ImageAnalysis.Builder();
  48. builder.setTargetResolution(new Size(640, 480));
  49. builder.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST);
  50. ImageAnalysis imageAnalysis = builder.build();
  51. imageAnalysis.setAnalyzer(
  52. ContextCompat.getMainExecutor(context),
  53. imageProxy -> {
  54. int imageFormat = imageProxy.getFormat();
  55. if (imageFormat == ImageFormat.YUV_420_888) {
  56. Image currentImage = imageProxy.getImage();
  57. if (previousHeight != 0) {
  58. assert currentImage != null;
  59. isMotionDetected = compareFrames(currentImage);
  60. }
  61. assert currentImage != null;
  62. Image.Plane[] planes = currentImage.getPlanes();
  63. ByteBuffer buffer = planes[0].getBuffer().duplicate();
  64. previousBuffer = ByteBuffer.allocateDirect(buffer.remaining());
  65. previousBuffer.put(buffer);
  66. previousWidth = currentImage.getWidth();
  67. previousHeight = currentImage.getHeight();
  68. currentImage.close();
  69. if (isMotionDetected) {
  70. videoAlarmDetected = true;
  71. if(alarmResetRunnable != null) {
  72. alarmResetHandler.removeCallbacks(alarmResetRunnable);
  73. }
  74. alarmResetRunnable = this::resetAlarmStatus;
  75. alarmResetHandler.postDelayed(alarmResetRunnable, ALARM_RESET_DELAY);
  76. }
  77. checkAlarmCondition();
  78. }
  79. imageProxy.close();
  80. });
  81. CameraSelector cameraSelector = new CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build();
  82. cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, imageAnalysis);
  83. }
  84. private boolean compareFrames(Image currentImage) {
  85. Image.Plane[] planes = currentImage.getPlanes();
  86. ByteBuffer currentBuffer = planes[0].getBuffer();
  87. int currentWidth = currentImage.getWidth();
  88. int currentHeight = currentImage.getHeight();
  89. int yRowStride = planes[0].getRowStride();
  90. int yPixelStride = planes[0].getPixelStride();
  91. if (previousWidth != currentWidth || previousHeight != currentHeight) {
  92. return false;
  93. }
  94. int blockSize = kleinstesQuadrat(previousHeight, previousWidth) / 8;
  95. int numBlocksX = currentWidth / blockSize;
  96. int numBlocksY = currentHeight / blockSize;
  97. for (int blockY = 0; blockY < numBlocksY; blockY++) {
  98. for (int blockX = 0; blockX < numBlocksX; blockX++) {
  99. startX = blockX * blockSize;
  100. startY = blockY * blockSize;
  101. endX = startX + blockSize;
  102. endY = startY + blockSize;
  103. float currentLuminance = berechneMittlereLuminanz(currentBuffer, yRowStride, yPixelStride);
  104. float previousLuminance = berechneMittlereLuminanz(previousBuffer, yRowStride, yPixelStride);
  105. int pixelDifference = Math.abs((int) previousLuminance - (int) currentLuminance);
  106. if (pixelDifference > threshold) {
  107. System.out.println(pixelDifference);
  108. return true;
  109. }
  110. }
  111. }
  112. return false;
  113. }
  114. private float berechneMittlereLuminanz(ByteBuffer buffer, int rowStride, int pixelStride) {
  115. int sumLuminance = 0;
  116. int countPixels = 0;
  117. for (int row = startY; row < endY; row++) {
  118. for (int col = startX; col < endX; col++) {
  119. int bufferIndex = row * rowStride + col * pixelStride;
  120. int currentPixel = buffer.get(bufferIndex) & 0xFF;
  121. sumLuminance += currentPixel;
  122. countPixels++;
  123. }
  124. }
  125. return (float) sumLuminance / countPixels;
  126. }
  127. private int kleinstesQuadrat(int height, int width) {
  128. if (height == width) {
  129. return height;
  130. } else if (height > width) {
  131. return kleinstesQuadrat(height - width, width);
  132. } else {
  133. return kleinstesQuadrat(height, width - height);
  134. }
  135. }
  136. private void resetAlarmStatus() {
  137. videoAlarmDetected = false;
  138. alarmResetRunnable = null;
  139. }
  140. public void checkAlarmCondition() {
  141. if (videoAlarmDetected && !mVideoAlarmDetected.getValue()) {
  142. setMutableLiveDataVideoAlarmDetected();
  143. }
  144. else if (!videoAlarmDetected && mVideoAlarmDetected.getValue()){
  145. setMutableLiveDataVideoAlarmDetected();
  146. }
  147. }
  148. }