Appearance
Creating a Preview for the User
As part of your application, it is recommended to present the user with a camera preview, as it helps the user to center his face on the camera. It also allows for the presentation of a face detection bounding graphic (such as a rectangle or oval shape) on the screen.
The following code can be used to create a preview and present a face detection bounding graphic to the user.
1. Create a TextureView element in your XML
The aspect ratio of the images received from the SDK is 4:3. In order to present a preview in the application, a TextureView
element should be added to the screen XML layout file. In order to preserve the same aspect ratio in the UI and prevent image distortion, the TextureView
element is configured with app:layout_constraintDimensionRatio="W, 4:3"
.
For example, see the TextureView
configuration below:
XML
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextureView
android:id="@+id/cameraView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="W, 4:3"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
2. Receive images from the SDK
Images are received from the SDK on a background thread. The application must switch to the UI thread in order to perform UI changes.
Kotlin
override fun onImage(imageData: ImageData) {
runOnUiThread {
handleImageData(imageData)
}
}
Java
public void onImage(ImageData imageData) {
runOnUiThread(() -> {
handleImageData(imageData)
});
}
3. Draw the image and face detection bounding graphic on the TextureView
In this code example, faceDetectionBitmap is a Bitmap asset of the app.
Kotlin
fun handleImageData(imageData: ImageData) {
binding.cameraView.lockCanvas()?.let { canvas ->
// Drawing the bitmap on the TextureView canvas
val image = imageData.image
canvas.drawBitmap(
image,
null,
Rect(0, 0, binding.cameraView.width, binding.cameraView.bottom - binding.cameraView.top),
null
)
// Drawing the face detection bounding rectangle (if not null..)
imageData.roi?.let roi@{ faceDetectionRect ->
// First, scale the SDK face detection rectangle to fit the TextureView size
val targetRect = RectF(faceDetectionRect)
val m = Matrix()
m.postScale(1f, 1f, image.width / 2f, image.height / 2f)
m.postScale(
binding.cameraView.width.toFloat() / image.width.toFloat(),
binding.cameraView.height.toFloat() / image.height.toFloat()
)
m.mapRect(targetRect)
// Then, draw it on the canvas
canvas.drawBitmap(faceDetectionBitmap ?: return@roi, null, targetRect, null)
}
binding.cameraView.unlockCanvasAndPost(canvas)
}
}
Java
public void onImage(ImageData imageData) {
// Drawing the bitmap on the TextureView canvas
Bitmap image = imageData.getImage();
canvas.drawBitmap(
image,
null,
new Rect(0, 0, mBinding.cameraView.getWidth(),
mBinding.cameraView.getBottom() - mBinding.cameraView.getTop()),
null
);
//Drawing the face detection (if not null..)
Rect roi = imageData.getROI();
if (roi != null) {
//First we scale the SDK face detection rectangle to fit the TextureView size
RectF targetRect = new RectF(roi);
Matrix m = new Matrix();
m.postScale(1f, 1f, image.getWidth() / 2f, image.getHeight() / 2f);
m.postScale(
(float)mBinding.cameraView.getWidth() / image.getWidth(),
(float)mBinding.cameraView.getHeight() / image.getHeight()
);
m.mapRect(targetRect);
// Then we draw it on the Canvas
canvas.drawBitmap(faceDetectionBitmap, null, targetRect, null);
}
mBinding.cameraView.unlockCanvasAndPost(canvas);
}
Info
For a complete example of an application preview please refer to the Sample Application code.