Не удается нарисовать оверлей на входном изображении с помощью Google ML?

ФОН

Мое приложение, использующее CameraX и Google ML Kit, написано на Java. Назначение приложения - обнаружение объектов с помощью предварительного просмотра камеры в реальном времени. Я реализовал ML Kit, используя это руководство с метким названием Обнаружение и отслеживание объектов с помощью ML Kit на Android (опция базовой модели) для обнаружения объектов в последовательных кадрах в приложении. Конечная цель моего кода состоит в том, чтобы объекты обнаруживались в реальном времени вот так:

введите описание изображения здесь

ПРОБЛЕМА

Несмотря на то, что приложение было успешно запущено, оно не могло наносить надписи на дисплей, несмотря на то, что для этого был введен код. Само приложение способно обнаруживать объекты, просто отсутствует визуальное отображение. Фактически, все, что присутствует в приложении, - это только мой предварительный просмотр камеры, без ограничивающей рамки, охватывающей какой-либо обнаруженный объект. В моем коде, показанном ниже, указано поле, и я понимаю, что я должен нарисовать boundingBox сам, и мой вопрос конкретно нацелен на то, как я буду пытаться его нарисовать.

КОД

public class MainActivity extends AppCompatActivity  {

    private ListenableFuture<ProcessCameraProvider> cameraProviderFuture;
    private class YourAnalyzer implements ImageAnalysis.Analyzer {

        @Override
        @ExperimentalGetImage
        public void analyze(ImageProxy imageProxy) {
            Image mediaImage = imageProxy.getImage();
            if (mediaImage != null) {
                //Log.d("TAG", "mediaImage is throwing null");
                InputImage image =
                        InputImage.fromMediaImage(mediaImage, imageProxy.getImageInfo().getRotationDegrees());
                //Pass image to an ML Kit Vision API
                //...

                ObjectDetectorOptions options =
                        new ObjectDetectorOptions.Builder()
                                .setDetectorMode(ObjectDetectorOptions.STREAM_MODE)
                                .enableClassification()  // Optional
                                .build();

                ObjectDetector objectDetector = ObjectDetection.getClient(options);

                objectDetector.process(image)
                        .addOnSuccessListener(detectedObjects -> {
                            Log.d("TAG", "onSuccess" + detectedObjects.size());
                            for (DetectedObject detectedObject : detectedObjects) {
                                Rect boundingBox = detectedObject.getBoundingBox();
                                Integer trackingId = detectedObject.getTrackingId();
                                for (DetectedObject.Label label : detectedObject.getLabels()) {
                                    String text = label.getText();
                                    int index = label.getIndex();
                                    float confidence = label.getConfidence();
                                }
                            }
                        })
                        .addOnFailureListener(e -> Log.e("TAG", e.getLocalizedMessage()))
                        .addOnCompleteListener(result -> imageProxy.close());
            }
        }
    }


    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        cameraProviderFuture = ProcessCameraProvider.getInstance(this);

        PreviewView previewView = findViewById(R.id.previewView);

        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));
    }

    void bindPreview(@NonNull ProcessCameraProvider cameraProvider) {

        PreviewView previewView = findViewById(R.id.previewView);
        Preview preview = new Preview.Builder()
                .build();

        CameraSelector cameraSelector = new CameraSelector.Builder()
                .requireLensFacing(CameraSelector.LENS_FACING_BACK)
                .build();

        preview.setSurfaceProvider(previewView.getSurfaceProvider());

        ImageAnalysis imageAnalysis =
                new ImageAnalysis.Builder()
                        .setTargetResolution(new Size(1280,720))
                        .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
                        .build();
        imageAnalysis.setAnalyzer(ContextCompat.getMainExecutor(this), new YourAnalyzer());

        Camera camera = cameraProvider.bindToLifecycle((LifecycleOwner)this, cameraSelector, preview, imageAnalysis);
    }
}

Я должен добавить, что здесь был аналогичный вопрос, который столкнулся с аналогичной проблемой, хотя разница между нашими вопросами заключается в том, что этот пользователь использовал пользовательскую модель детектора объектов, тогда как я использовал базовую модель. Кроме того, этот пользователь смог решить свою проблему, выбрав оптимальную модель TensorFlow, которая была бы совместима с их уже установленным кодом.

Любая информация, необходимая для дополнения этого вопроса, будет предоставлена ​​по запросу.



ПОПЫТКИ

ПОПЫТКА 1 [12 июня 2021 г.]: я добавил следующий код в метод onSuccess, используя этот ответ StackOverflow, чтобы попытаться нарисовать оверлей на моем дисплее приложения, и задаетесь вопросом, почему эта попытка не сработала?

.addOnSuccessListener(detectedObjects -> {
                            Log.d("TAG", "onSuccess" + detectedObjects.size());
                            for (DetectedObject detectedObject : detectedObjects) {
                                Rect boundingBox = detectedObject.getBoundingBox();
                                int left = boundingBox.left;
                                int top = boundingBox.top;
                                int right = boundingBox.right;
                                int bottom = boundingBox.bottom;

                                ShapeDrawable drawable = new ShapeDrawable();
                                drawable.getPaint().setColor(Color.RED);
                                drawable.getPaint().setStyle(Paint.Style.STROKE);
                                drawable.getPaint().setStrokeWidth(5f);
                                
                                Integer trackingId = detectedObject.getTrackingId();
                                for (DetectedObject.Label label : detectedObject.getLabels()) {
                                    String text = label.getText();
                                    int index = label.getIndex();
                                    float confidence = label.getConfidence();
                                }
                            }
                        })

person RunMildew    schedule 11.05.2021    source источник


Ответы (1)


С помощью ограничивающей рамки и метки, возвращаемых API MLKit, вам нужно будет нарисовать оверлей в своем приложении, чтобы отобразился пользовательский интерфейс. Вы можете использовать это mlkit vision_quickstart graphic в качестве справочного материала.

person Chenxi Song    schedule 11.05.2021
comment
Итак, у меня есть вопросы по использованию этого для справки. Строки 102-111 инструктируют нас по рисованию ограничивающего прямоугольника с помощью «translateX» и «translateY», которые отображаются красным цветом. Похоже, они используют JavaFX. Поскольку я использую только CameraX и Google ML Kit, нужно ли мне устанавливать JavaFX SDK? или есть ли способ обойти это? - person RunMildew; 12.05.2021
comment
Кроме того, если это возможно, не могли бы вы подробнее рассказать о том, где я буду рисовать координаты наложения в моем проекте? Придется ли мне вообще создавать новое действие для наложения или я могу проверить его координаты в основном действии, в котором на данный момент написана вся программа? - person RunMildew; 15.06.2021