CameraX Preview + ImageAnalysis
Useful :
https://developer.android.com/training/camerax/preview
https://medium.com/@sdptd20/exploring-ocr-capabilities-of-ml-kit-using-camera-x-9949633af0fe
In the CameraX library, the Preview is a use case that provides a camera preview stream for the camera preview, so the user can view the photo they will be taking.
CameraX API is not just to make the preview and take pictures more easily, you can also apply image analysis in a very simple way. You can define a custom class that implements the ImageAnalysis.Analyzer interface, which will be called with incoming camera frames. So you can receive image data and perform custom analysis processing.
The dependencies :
// CameraX core library using the camera2 implementation
def camerax_version = "1.0.1"
// The following line is optional, as the core library is included indirectly by camera-camera2
implementation "androidx.camera:camera-core:${camerax_version}"
implementation "androidx.camera:camera-camera2:${camerax_version}"
// If you want to additionally use the CameraX Lifecycle library
implementation "androidx.camera:camera-lifecycle:${camerax_version}"
// If you want to additionally use the CameraX View class
implementation "androidx.camera:camera-view:1.0.0-alpha27"
// If you want to additionally use the CameraX Extensions library
implementation "androidx.camera:camera-extensions:1.0.0-alpha27"
NOTE : Also Mention the Camera Permission in the Manifest file otherwise the Preview wont work
EXAMPLE 1 ]
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.camera.view.PreviewView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/previewView_main"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
package com.deepesh.testapp;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.camera.core.Camera;
import androidx.camera.core.CameraSelector;
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.lifecycle.LifecycleOwner;
import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.concurrent.ExecutionException;
public class MainActivity extends AppCompatActivity {
PreviewView previewView_main;
ListenableFuture<ProcessCameraProvider> cameraProviderFuture;
private final int CAMERA_REQUEST_CODE = 101;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
previewView_main = findViewById(R.id.previewView_main);
ask_permissions();
}
private void load_camera_preview() {
cameraProviderFuture = ProcessCameraProvider.getInstance(this);
cameraProviderFuture.addListener(() -> {
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.
}
}, ContextCompat.getMainExecutor(this));
}
private void bindPreview(ProcessCameraProvider cameraProvider) {
Preview preview = new Preview.Builder()
.build();
CameraSelector cameraSelector = new CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.build();
preview.setSurfaceProvider(previewView_main.getSurfaceProvider());
Camera camera = cameraProvider.bindToLifecycle((LifecycleOwner) this, cameraSelector, preview);
}
private void ask_permissions() {
// asks camera permission to the user.
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
String[] permissions = {Manifest.permission.CAMERA};
ActivityCompat.requestPermissions(this, permissions, CAMERA_REQUEST_CODE);
}
// if permission already granted then load camera preview
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
load_camera_preview();
}
}
// Called when a request permission is denied or accepted.
// Load camera preview in both cases
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == CAMERA_REQUEST_CODE && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
load_camera_preview();
} else {
load_camera_preview();
}
}
}
Drawing a Rectangular frame/shape on camera preview
package com.deepesh.testapp;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.camera.core.Camera;
import androidx.camera.core.CameraSelector;
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.lifecycle.LifecycleOwner;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.concurrent.ExecutionException;
public class MainActivity extends AppCompatActivity {
PreviewView previewView_main;
ListenableFuture<ProcessCameraProvider> cameraProviderFuture;
private final int CAMERA_REQUEST_CODE = 101;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
previewView_main = findViewById(R.id.previewView_main);
ask_permissions();
}
private void load_camera_preview() {
cameraProviderFuture = ProcessCameraProvider.getInstance(this);
cameraProviderFuture.addListener(() -> {
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.
}
}, ContextCompat.getMainExecutor(this));
draw_preview_rectangle();
}
private void bindPreview(ProcessCameraProvider cameraProvider) {
Preview preview = new Preview.Builder()
.build();
CameraSelector cameraSelector = new CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.build();
preview.setSurfaceProvider(previewView_main.getSurfaceProvider());
Camera camera = cameraProvider.bindToLifecycle((LifecycleOwner) this, cameraSelector, preview);
}
private void ask_permissions() {
// asks camera permission to the user.
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
String[] permissions = {Manifest.permission.CAMERA};
ActivityCompat.requestPermissions(this, permissions, CAMERA_REQUEST_CODE);
}
// if permission already granted then load camera preview
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
load_camera_preview();
}
}
// Called when a request permission is denied or accepted.
// Load camera preview in both cases
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == CAMERA_REQUEST_CODE && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
load_camera_preview();
} else {
load_camera_preview();
}
}
//=============================================================================
public class Box extends View {
private Paint paint = new Paint();
Box(Context context) {
super(context);
}
@Override
protected void onDraw(Canvas canvas) { // Override the onDraw() Method
super.onDraw(canvas);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.GREEN);
paint.setStrokeWidth(4);
//centerint x0 = previewView_main.getWidth() / 2;//draw guide box
int y0 = previewView_main.getHeight() / 2;
int dx = previewView_main.getHeight() / 6;
int dy = previewView_main.getHeight() / 8;
canvas.drawRect(x0 - dx, y0 - dy, x0 + dx, y0 + dy, paint);
}
}
private void draw_preview_rectangle() {
Box box = new Box(this);
addContentView(box, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
}
}
========================================================================
ImageAnalysis.Analyzer
https://developer.android.com/reference/androidx/camera/core/ImageAnalysis.Analyzer
https://developer.android.com/training/camerax/analyze
https://stackoverflow.com/questions/59606400/imageanalysis-analyzer-only-fires-once
Convert Image to Bitmap :
https://stackoverflow.com/questions/56772967/converting-imageproxy-to-bitmap
NOTES :
For the executor parameter initiate a new executor like this :
ExecutorService cameraExecutor = Executors.newSingleThreadExecutor();
Also it is important to close the image inside the analyse() method or the ImageAnalysis will run only once and then stop.
image.close();Taking a Camera Preview Stream and using ImageAnalysis to process or do something with those camera frames.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.deepesh.testapp">
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.TestApp">
<activity
android:screenOrientation="portrait"
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
package com.deepesh.testapp;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AlertDialog;
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.lifecycle.LifecycleOwner;
import android.Manifest;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraManager;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MainActivity extends AppCompatActivity {
PreviewView previewView_main;
ListenableFuture<ProcessCameraProvider> cameraProviderFuture;
CameraSelector cameraSelector;
Preview preview;
ProcessCameraProvider cameraProvider;
ExecutorService cameraExecutor;
private final int CAMERA_REQUEST_CODE = 101;
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
previewView_main = findViewById(R.id.previewView_main);
cameraExecutor = Executors.newSingleThreadExecutor();
cameraProviderFuture = ProcessCameraProvider.getInstance(this);
cameraSelector = new CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.build();
preview = new Preview.Builder().build();
try {
cameraProvider = cameraProviderFuture.get();
} catch (ExecutionException | InterruptedException e) {
// This should never be reached.
}
ask_permissions();
}
//=============================================================================
private void load_camera_preview() {
cameraProviderFuture.addListener(() -> {
bindPreview(cameraProvider);
}, ContextCompat.getMainExecutor(this));
draw_preview_rectangle();
}
private void bindPreview(ProcessCameraProvider cameraProvider) {
preview.setSurfaceProvider(previewView_main.getSurfaceProvider());
// ImageAnalysis for processing camera preview frames
ImageAnalysis imageAnalysis =
new ImageAnalysis.Builder()
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build();
imageAnalysis.setAnalyzer(cameraExecutor, new ImageAnalysis.Analyzer() {
@Override
public void analyze(@NonNull ImageProxy image) {
// Write your Image processing code here
Log.d("TAG", "IMAGE : " + image.getImageInfo().getRotationDegrees());
image.close();
}
});
cameraProvider.bindToLifecycle((LifecycleOwner) this, cameraSelector, imageAnalysis,preview);
}
private void ask_permissions() {
// asks camera permission to the user.
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) !=
PackageManager.PERMISSION_GRANTED) {
String[] permissions = {Manifest.permission.CAMERA};
ActivityCompat.requestPermissions(this, permissions, CAMERA_REQUEST_CODE);
}
// if permission already granted then load camera preview
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) ==
PackageManager.PERMISSION_GRANTED) {
load_camera_preview();
}
}
// Called when a request permission is denied or accepted.
// Load camera preview in both cases
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == CAMERA_REQUEST_CODE && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
load_camera_preview();
} else {
load_camera_preview();
}
}
//=============================================================================
public class Box extends View {
private Paint paint = new Paint();
Box(Context context) {
super(context);
}
@Override
protected void onDraw(Canvas canvas) { // Override the onDraw() Method
super.onDraw(canvas);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.GREEN);
paint.setStrokeWidth(4);
//center
int x0 = getWidth() / 2;
int y0 = getHeight() / 2;
int dx = getHeight() / 6;
int dy = getHeight() / 8;
//draw guide box
canvas.drawRect(x0 - dx, y0 - dy, x0 + dx, y0 + dy, paint);
}
}
private void draw_preview_rectangle() {
Box box = new Box(this);
addContentView(box, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
}
}
Comments
Post a Comment