6

Can anybody show me how to draw a rectangle over cameraX preview? I tried implementing a custom view as suggested by past stack overflow answers that were written in kotlin but it does not seemed to be working for me when I attempted to convert it into Java.

XML File

<?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"
    android:id="@+id/my_root">

    <com.example.cameraxxx.RectOverlay
        android:id="@+id/rectOverlay"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.camera.view.PreviewView
        android:id="@+id/previewView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:contentDescription="preview_area"
        android:importantForAccessibility="no"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="1.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.0">

    </androidx.camera.view.PreviewView>


    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="13dp"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="@+id/previewView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        tools:visibility="visible" />


</androidx.constraintlayout.widget.ConstraintLayout>

MainActivity Extract

imageAnalysis.setAnalyzer(executor, new ImageAnalysis.Analyzer() {
            @SuppressLint("UnsafeExperimentalUsageError")
            @Override
            public void analyze(@NonNull ImageProxy imageProxy) {
                int rotationDegrees = imageProxy.getImageInfo().getRotationDegrees();
                FaceDetectorOptions realTimeOpts =
                        new FaceDetectorOptions.Builder()
                                .setPerformanceMode(1).enableTracking()
                                .build();
                
                Image mediaImage = imageProxy.getImage();
                if(mediaImage != null) {
                    InputImage image = InputImage.fromMediaImage(mediaImage,imageProxy.getImageInfo().getRotationDegrees());
                    FaceDetector detector = FaceDetection.getClient(realTimeOpts);
                    Task<List<Face>> result =
                            detector.process(image)
                                    .addOnSuccessListener(
                                            new OnSuccessListener<List<Face>>() {
                                                @Override
                                                public void onSuccess(List<Face> faces) {
                                                    // Task completed successfully
                                                    // ...
                                                    if(faces.size() !=0){
                                                        rectOverlay.setAlpha(1f);
                                                        Toast.makeText(MainActivity.this,"Face detected",Toast.LENGTH_SHORT).show();
                                                        Canvas canvas = new Canvas();
                                                        for (Face face: faces){
                                                            rectOverlay.drawOverlay(face,canvas);
                                                        }

                                                    }
                                                }
                                            })
                                    .addOnFailureListener(
                                            new OnFailureListener() {
                                                @Override
                                                public void onFailure(@NonNull Exception e) {
                                                    // Task failed with an exception
                                                    // ...
                                                    Log.d("y123","nno face");
                                                }
                                            })
                                    .addOnCompleteListener(
                                            new OnCompleteListener<List<Face>>() {
                                                @Override
                                                public void onComplete(@NonNull Task<List<Face>> task) {
                                                    imageProxy.close();
                                                }
                                            });
                }
            }
        });
        cameraProvider.bindToLifecycle((LifecycleOwner) this, cameraSelector, imageAnalysis, preview);
        preview.setSurfaceProvider(mPreviewView.createSurfaceProvider());
    }

RectOverlay Class

package com.example.cameraxxx;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;

import androidx.annotation.Nullable;

import com.google.mlkit.vision.face.Face;

public class RectOverlay extends View {

    private Paint paint;

    public RectOverlay(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        paint = new Paint();
        paint.setColor(Color.RED);
        paint.setStrokeWidth(10);
        paint.setStyle(Paint.Style.FILL);
    }

    public void drawOverlay(Face face, Canvas canvas){
        canvas.drawRect(face.getBoundingBox().left,face.getBoundingBox().top, face.getBoundingBox().right, face.getBoundingBox().bottom, paint);
        invalidate();

    }
}
Howden
  • 61
  • 1
  • 3
  • 2
    The overlay's width and height should be the same as those of `PreviewView`, i.e. The overlay should fill its parent. So instead of `wrap_content`, use `0dp` so that the constraints are set on the view. Also, set the overlay after `PreviewView` in the xml layout file. – Husayn Hakeem Sep 25 '20 at 16:01
  • What do you mean by "does not seemed to be working"? Are you getting build or runtime errors and if so, what do they say? For reference, you can use this [MLKit Sample](https://github.com/googlesamples/mlkit/blob/08c3e1fbe66b06d6d6daed1a3c61e26aad2f512d/android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/java/objectdetector/ObjectDetectorProcessor.java#L64) that draws a bounding box around each detected object: – topher217 Oct 09 '20 at 00:51
  • check https://stackoverflow.com/a/68208561/1961442 – Bruce Jul 01 '21 at 13:30

1 Answers1

0
  1. Use match_parent in width and height of RectOverlay in XML
  2. Place the RectOverlay below the PreviewView in XML