@@ -38,6 +38,11 @@ dependencies { | |||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' | |||
// Required for CameraX | |||
implementation 'androidx.camera:camera-core:1.2.2' | |||
implementation 'androidx.camera:camera-camera2:1.2.2' | |||
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}" | |||
} |
@@ -2,38 +2,69 @@ package com.example.ueberwachungssystem; | |||
import androidx.annotation.NonNull; | |||
import androidx.appcompat.app.AppCompatActivity; | |||
import androidx.camera.core.Camera; | |||
import androidx.camera.core.CameraSelector; | |||
import androidx.camera.core.ImageAnalysis; | |||
import androidx.camera.core.ImageProxy; | |||
import androidx.camera.core.Preview; | |||
import androidx.camera.lifecycle.ProcessCameraProvider; | |||
import androidx.camera.view.PreviewView; | |||
import androidx.core.app.ActivityCompat; | |||
import androidx.core.content.ContextCompat; | |||
import androidx.camera.core.ExperimentalGetImage; | |||
import androidx.lifecycle.LifecycleOwner; | |||
import android.Manifest; | |||
import android.app.AlertDialog; | |||
import android.content.DialogInterface; | |||
import android.content.pm.PackageManager; | |||
import android.graphics.ImageFormat; | |||
import android.media.Image; | |||
import android.os.Bundle; | |||
import android.util.Log; | |||
import android.util.Size; | |||
import android.view.View; | |||
import android.widget.Button; | |||
import android.widget.TextView; | |||
import android.widget.Toast; | |||
import com.google.common.util.concurrent.ListenableFuture; | |||
import java.nio.ByteBuffer; | |||
import java.util.concurrent.ExecutionException; | |||
@ExperimentalGetImage | |||
public class MainActivity extends AppCompatActivity { | |||
private static final int CAMERA_PERMISSION_REQUEST_CODE = 101; | |||
private PreviewView previewView; | |||
private TextView textView; | |||
private Button previewButton; | |||
private Boolean cameraPreviewIsRunning = false; | |||
@Override | |||
protected void onCreate(Bundle savedInstanceState) { | |||
super.onCreate(savedInstanceState); | |||
setContentView(R.layout.activity_main); | |||
textView = findViewById(R.id.textView); | |||
previewView = findViewById(R.id.previewView); | |||
previewButton = findViewById(R.id.previewButton); | |||
VideoDetector vd = new VideoDetector(this); | |||
Button B1 = findViewById(R.id.B1); | |||
B1.setOnClickListener(new View.OnClickListener() { | |||
previewButton.setOnClickListener(new View.OnClickListener() { | |||
@Override | |||
public void onClick(View v) { | |||
getCameraAccess(); | |||
getCameraAccess(); | |||
if (isCameraAccessAllowed()) | |||
vd.runImageAnalysis(); | |||
} | |||
}); | |||
} | |||
private boolean isCameraAccessAllowed() { | |||
return ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED; | |||
} | |||
@@ -57,17 +88,38 @@ public class MainActivity extends AppCompatActivity { | |||
} | |||
} | |||
private void showDialogue(String message) { | |||
new AlertDialog.Builder(this) | |||
.setMessage(message) | |||
.setPositiveButton("OK", new DialogInterface.OnClickListener() { | |||
@Override | |||
public void onClick(DialogInterface dialog, int which) { | |||
requestPermissions(new String[] {Manifest.permission.CAMERA}, CAMERA_PERMISSION_REQUEST_CODE); | |||
private void previewCamera() { | |||
// Request Camera Access | |||
getCameraAccess(); | |||
// Return when Camera Access not allowed or Camera Preview is running | |||
if (!isCameraAccessAllowed() || cameraPreviewIsRunning) | |||
return; | |||
// Camera Preview is running | |||
cameraPreviewIsRunning = true; | |||
// Request Camera Provider | |||
final ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(this); | |||
//Check for Camera availability | |||
cameraProviderFuture.addListener(new Runnable() { | |||
@Override | |||
public void run() { | |||
try { | |||
ProcessCameraProvider cameraProvider = cameraProviderFuture.get(); | |||
bindPreview(cameraProvider); | |||
} catch (ExecutionException | InterruptedException e) { | |||
// No errors need to be handled for this Future. This should never be reached. | |||
} | |||
}) | |||
.setNegativeButton("Cancel", null) | |||
.create() | |||
.show(); | |||
} | |||
},ContextCompat.getMainExecutor(this)); | |||
} | |||
private void bindPreview(@NonNull ProcessCameraProvider cameraProvider) { | |||
// Create Preview | |||
Preview preview = new Preview.Builder().build(); | |||
// Specify which Camera to use | |||
CameraSelector cameraSelector = new CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build(); | |||
// Connect Preview to PreviewView | |||
preview.setSurfaceProvider(previewView.getSurfaceProvider()); | |||
Camera camera = cameraProvider.bindToLifecycle((LifecycleOwner)this, cameraSelector, preview); | |||
} | |||
} |
@@ -0,0 +1,106 @@ | |||
package com.example.ueberwachungssystem; | |||
import android.content.Context; | |||
import android.graphics.ImageFormat; | |||
import android.media.Image; | |||
import android.util.Log; | |||
import android.util.Size; | |||
import androidx.annotation.NonNull; | |||
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.lifecycle.ProcessCameraProvider; | |||
import androidx.core.content.ContextCompat; | |||
import androidx.lifecycle.LifecycleOwner; | |||
import com.google.common.util.concurrent.ListenableFuture; | |||
import java.nio.ByteBuffer; | |||
import java.util.concurrent.ExecutionException; | |||
@ExperimentalGetImage | |||
public class VideoDetector { | |||
private final Context context; | |||
private float currentLuminosity; | |||
public VideoDetector(Context context) { | |||
this.context = context; | |||
} | |||
public void runImageAnalysis() { | |||
// Request Camera Provider | |||
final ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(context); | |||
//Check for Camera availability | |||
cameraProviderFuture.addListener(new Runnable() { | |||
@Override | |||
public void run() { | |||
try { | |||
ProcessCameraProvider cameraProvider = cameraProviderFuture.get(); | |||
bindImageAnalysis(cameraProvider); | |||
} catch (ExecutionException | InterruptedException e) { | |||
// No errors need to be handled for this Future. This should never be reached. | |||
} | |||
} | |||
},ContextCompat.getMainExecutor(context)); | |||
} | |||
private void bindImageAnalysis(@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); | |||
ImageAnalysis imageAnalysis = builder.build(); | |||
// Set Analyzer | |||
imageAnalysis.setAnalyzer(ContextCompat.getMainExecutor(context), new ImageAnalysis.Analyzer() { | |||
@Override | |||
public void analyze(@NonNull ImageProxy imageProxy) { | |||
if (imageProxy.getFormat() == ImageFormat.YUV_420_888) { | |||
Image image = imageProxy.getImage(); | |||
assert image != null; | |||
float luminosity = calculateLuminosity(image); | |||
currentLuminosity = luminosity; | |||
Log.d("Video Detector", String.valueOf(luminosity)); | |||
} | |||
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(); | |||
// Connect Preview to PreviewView | |||
cameraProvider.bindToLifecycle((LifecycleOwner) context, cameraSelector, imageAnalysis, preview); | |||
} | |||
private float calculateLuminosity (Image image) { | |||
int width = image.getWidth(); | |||
int height = image.getHeight(); | |||
Image.Plane[] planes = image.getPlanes(); | |||
ByteBuffer luminosityBuffer = planes[0].getBuffer(); | |||
int yRowStride = image.getPlanes()[0].getRowStride(); | |||
int yPixelStride = image.getPlanes()[0].getPixelStride(); | |||
int luminosity; | |||
float sum = 0; | |||
for (int y = 0; y < height; ++y) { | |||
for (int x = 0; x < width; x++) { | |||
int index = (y * yRowStride) + (x * yPixelStride); | |||
luminosity = (luminosityBuffer.get(index) & 0xff); | |||
sum += luminosity; | |||
} | |||
} | |||
return sum / (width * height); | |||
} | |||
} |
@@ -10,6 +10,7 @@ | |||
tools:context=".MainActivity"> | |||
<TextView | |||
android:id="@+id/textView" | |||
android:layout_width="wrap_content" | |||
android:layout_height="wrap_content" | |||
android:text="Hello World!" | |||
@@ -19,11 +20,16 @@ | |||
app:layout_constraintTop_toTopOf="parent" /> | |||
<Button | |||
android:id="@+id/B1" | |||
android:id="@+id/previewButton" | |||
android:layout_width="wrap_content" | |||
android:layout_height="wrap_content" | |||
android:text="Button" | |||
tools:layout_editor_absoluteX="156dp" | |||
tools:layout_editor_absoluteY="189dp" /> | |||
<androidx.camera.view.PreviewView | |||
android:id="@+id/previewView" | |||
android:layout_width="match_parent" | |||
android:layout_height="match_parent" /> | |||
</LinearLayout> |