簡體   English   中英

MLKit Object 檢測未檢測到物體

[英]MLKit Object Detection is not detecting objects

Google 的 MLKit(沒有 Firebase)是新的,所以我遇到了麻煩。 我試圖在這里遵循這個例子: https://developers.google.com/ml-kit/vision/object-detection/custom-models/android

該應用程序可以正常打開,並且相機可以正常工作(例如,我可以看到東西)。 但實際檢測似乎不起作用。

我是否缺少實際檢測 object 的部分代碼? 還是 CameraX 或 ImageInput 的實現有問題?

package com.example.mlkitobjecttest;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.camera.core.Camera;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.CameraX;
import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.ImageProxy;
import androidx.camera.core.Preview;
import androidx.camera.core.impl.PreviewConfig;
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.content.pm.PackageManager;
import android.graphics.Rect;
import android.media.Image;
import android.os.Bundle;
import android.text.Layout;
import android.util.Rational;
import android.util.Size;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.mlkit.common.model.LocalModel;
import com.google.mlkit.vision.common.InputImage;
import com.google.mlkit.vision.objects.DetectedObject;
import com.google.mlkit.vision.objects.ObjectDetection;
import com.google.mlkit.vision.objects.ObjectDetector;
import com.google.mlkit.vision.objects.custom.CustomObjectDetectorOptions;

import org.w3c.dom.Text;

import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MainActivity extends AppCompatActivity {

    private class YourAnalyzer implements ImageAnalysis.Analyzer {

        @Override
        @androidx.camera.core.ExperimentalGetImage
        public void analyze(ImageProxy imageProxy) {

            Image mediaImage = imageProxy.getImage();
            if (mediaImage != null) {
                InputImage image =
                        InputImage.fromMediaImage(mediaImage, imageProxy.getImageInfo().getRotationDegrees());
                // Pass image to an ML Kit Vision API
                // ...
                LocalModel localModel =
                        new LocalModel.Builder()
                                .setAssetFilePath("mobilenet_v1_1.0_128_quantized_1_default_1.tflite")
                                // or .setAbsoluteFilePath(absolute file path to tflite model)
                                .build();

                CustomObjectDetectorOptions customObjectDetectorOptions =
                        new CustomObjectDetectorOptions.Builder(localModel)
                                .setDetectorMode(CustomObjectDetectorOptions.SINGLE_IMAGE_MODE)
                                .enableMultipleObjects()
                                .enableClassification()
                                .setClassificationConfidenceThreshold(0.5f)
                                .setMaxPerObjectLabelCount(3)
                                .build();

                ObjectDetector objectDetector =
                        ObjectDetection.getClient(customObjectDetectorOptions);

                objectDetector
                        .process(image)
                        .addOnFailureListener(new OnFailureListener() {
                            @Override
                            public void onFailure(@NonNull Exception e) {
                                //Toast.makeText(getApplicationContext(), "Fail. Sad!", Toast.LENGTH_SHORT).show();
                                //textView.setText("Fail. Sad!");
                                imageProxy.close();
                            }
                        })
                        .addOnSuccessListener(new OnSuccessListener<List<DetectedObject>>() {
                            @Override
                            public void onSuccess(List<DetectedObject> results) {

                                for (DetectedObject detectedObject : results) {
                                    Rect box = detectedObject.getBoundingBox();


                                    for (DetectedObject.Label label : detectedObject.getLabels()) {
                                        String text = label.getText();
                                        int index = label.getIndex();
                                        float confidence = label.getConfidence();
                                        textView.setText(text);
                                        


                                }}
                                imageProxy.close();
                            }
                        });

            }
            //ImageAnalysis.Builder.fromConfig(new ImageAnalysisConfig).setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST);

        }

    }


    PreviewView prevView;
    private ListenableFuture<ProcessCameraProvider> cameraProviderFuture;
    private ExecutorService executor = Executors.newSingleThreadExecutor();
    TextView textView;

    private int REQUEST_CODE_PERMISSIONS = 101;
    private String[] REQUIRED_PERMISSIONS = new String[]{"android.permission.CAMERA"};
   /* @NonNull
    @Override
    public CameraXConfig getCameraXConfig() {
        return CameraXConfig.Builder.fromConfig(Camera2Config.defaultConfig())
                .setCameraExecutor(ContextCompat.getMainExecutor(this))
                .build();
    }
*/
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        prevView = findViewById(R.id.viewFinder);
        textView = findViewById(R.id.scan_button);

        if(allPermissionsGranted()){
            startCamera();
        }else{
            ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS);
        }

    }

    private void startCamera() {
        cameraProviderFuture = ProcessCameraProvider.getInstance(this);
        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.
                }
            }
        }, ContextCompat.getMainExecutor(this));


    }

    void bindPreview(@NonNull ProcessCameraProvider cameraProvider) {

        Preview preview = new Preview.Builder()
                .build();

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

        preview.setSurfaceProvider(prevView.createSurfaceProvider());

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


    }



    private boolean allPermissionsGranted() {
        for(String permission: REQUIRED_PERMISSIONS){
            if(ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED){
                return false;
            }
        }
        return true;
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

        if(requestCode == REQUEST_CODE_PERMISSIONS){
            if(allPermissionsGranted()){
                startCamera();
            } else{
                Toast.makeText(this, "Permissions not granted by the user.", Toast.LENGTH_SHORT).show();
                this.finish();
            }
        }
    }

}

未檢測到任何內容,因為您定義了tflite model 文件的錯誤路徑。 您的模擬器或物理設備無法解析給定路徑,因為它在移動設備上不存在: C:\\Users\\dude\\Documents\\mlkitobjecttest\\app\\src\\main\\assets\\mobilenet_v1_1.0_128_quantized_1_default_1.tflite

將 model mobilenet_v1_1.0_128_quantized_1_default_1.tflite復制到應用程序項目src/main目錄下的assets目錄中。

如果您沒有該目錄,只需創建一個名為assets的新目錄。

最后它應該是這樣的:

項目的 src 目錄結構

之后修復LocalModel初始化代碼:

LocalModel localModel =
    new LocalModel.Builder()
    .setAssetFilePath("mobilenet_v1_1.0_128_quantized_1_default_1.tflite")
    // or .setAbsoluteFilePath(absolute file path to tflite model)
    .build();

更新:又發現一個問題

ImageAnalysis實例未綁定到CameraProvider

...
ImageAnalysis imageAnalysis = ...
    
Camera camera = cameraProvider.bindToLifecycle((LifecycleOwner)this, cameraSelector, preview); // imageAnalysis is not used

要修復它,只需將imageAnalysis變量作為最后一個參數傳遞給bindToLifecycle方法:

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

第二次更新:又發現一個問題

MLKit 無法處理圖像,因為它在處理過程中或處理開始之前已關閉。 我說的是在public void analyze(ImageProxy imageProxy)內部聲明的imageProxy.close()代碼行。

Java close()方法的文檔:

/**
 * Free up this frame for reuse.
 * <p>
 * After calling this method, calling any methods on this {@code Image} will
 * result in an {@link IllegalStateException}, and attempting to read from
 * or write to {@link ByteBuffer ByteBuffers} returned by an earlier
 * {@link Plane#getBuffer} call will have undefined behavior. If the image
 * was obtained from {@link ImageWriter} via
 * {@link ImageWriter#dequeueInputImage()}, after calling this method, any
 * image data filled by the application will be lost and the image will be
 * returned to {@link ImageWriter} for reuse. Images given to
 * {@link ImageWriter#queueInputImage queueInputImage()} are automatically
 * closed.
 * </p>
 */

要修復將imageProxy.close()移動到失敗和成功偵聽器中的問題:

objectDetector
    .process(image)
    .addOnFailureListener(new OnFailureListener() {
        @Override
        public void onFailure(@NonNull Exception e) {
            Toast.makeText(getApplicationContext(), "Fail. Sad!", Toast.LENGTH_LONG).show();
            ...
            imageProxy.close();
        }
    })
    .addOnSuccessListener(new OnSuccessListener<List<DetectedObject>>() {
        @Override
        public void onSuccess(List<DetectedObject> results) {
            Toast.makeText(getBaseContext(), "Success...", Toast.LENGTH_LONG).show();
            ...
            imageProxy.close();
        }
    });

使用來自 Tensorflow 的圖像分類 model對固定解決方案進行測試,測試成功。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM