Передача переменной Bitmap в метод в расширенном классе - PullRequest
0 голосов
/ 27 мая 2020

Мой код реализует TFlite, и у меня есть два класса:

1) Занимается работой камеры и обработкой изображения

2) Имеет дело со спецификой модели и детектора.

У меня есть метод в расширенном классе, который запускает модель. Я пытаюсь вызвать этот метод из основного класса. Я новичок в Java, поэтому я не совсем понимаю, почему я продолжаю получать ошибку java .lang.NullPointerException.

См. Код ниже (я оставлю много пробелов и буду комментировать части релевантные):

Метод, выполняющий вызов:

// Class was called
Classifier classifier;

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        // Called when image was captured from camera

        // ...
        // Obtains bitmap image from camera and processes it to a new Bitmap variable: rotatedBitmap
        // ...

/* Here is where the issue begins.
I can obtain the processed image and set it to my ImageView no problem, so the variable rotatedBitmap
is NOT null. But when I try to pass it to classifier.recognizeImage() it throws the null pointer error
and crashes the app
*/ 
        if (resultCode == RESULT_OK) {
            // Set the image captured to our ImageView
            mImageView.setImageBitmap(rotatedBitmap);

            if (rotatedBitmap != null) {
                float[][] result = classifier.recognizeImage(rotatedBitmap); // Says that rotatedBitmap is null

                // Display results
                String message = Arrays.toString(result[0]);
                Snackbar mySnackbar = Snackbar.make(findViewById(R.id.myCoordinatorLayout), message,
                        Snackbar.LENGTH_SHORT);
                mySnackbar.show();
            }
        }
    }

Полный код:

public class CameraActivity extends AppCompatActivity {

    private static final int PERMISSION_CODE = 1000;
    private static final int IMAGE_CAPTURE_CODE = 1001;

    Classifier classifier;

    Button mCaptureBtn;
    ImageView mImageView;

    Uri image_uri;
    public Bitmap rotatedBitmap;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mImageView = findViewById(R.id.image_view);
        mCaptureBtn = findViewById(R.id.capture_image_btn);

        mCaptureBtn.setOnClickListener(new View.OnClickListener() {
            // 1: Create the button
            // 2: Create an instance of OnClickListener to wait for the click
            // 3: Override the onClick method
            @Override
            public void onClick(View v) {
                // If the operating system is newer or equal to Marshmello
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    // Check for permissions
                    if (checkSelfPermission(Manifest.permission.CAMERA) ==
                            PackageManager.PERMISSION_DENIED ||
                            checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) ==
                                    PackageManager.PERMISSION_DENIED) {
                        // Permission not enables so request it
                        String[] permission = {Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE};
                        requestPermissions(permission, PERMISSION_CODE);
                    } else {
                        // Permission already granted
                        openCamera();
                    }
                } else {
                    openCamera();
                }
            }
        });
    }

    private void openCamera() {
        // ContentValues creates a set-type object that can store values that ContentResolver can access
        ContentValues values = new ContentValues();

        // Store values
        values.put(MediaStore.Images.Media.TITLE, "New Picture");
        values.put(MediaStore.Images.Media.DESCRIPTION, "From the camera");

        // Obtain the uri(uniform resource identifier) using the ContentValues previously made
        image_uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
        // Camera intent
        Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        // The EXTRA_OUTPUT constraint outputs the full-sized image data to the uri
        cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, image_uri);

        if (cameraIntent.resolveActivity(getPackageManager()) != null) {
            startActivityForResult(cameraIntent, IMAGE_CAPTURE_CODE);
        }
    }

    // Handling permission request
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        // THis method is called whenever the user presses allow or deny from the Perm Req prompt
        switch (requestCode){
            case PERMISSION_CODE:{
                if (grantResults.length > 0 && grantResults[0] ==
                        PackageManager.PERMISSION_GRANTED) {
                    // permission from popup was granted
                    openCamera();
                }
                else {
                    // permission from popup was denied
                    Toast.makeText(this, "Permission denied...", Toast.LENGTH_SHORT).show();
                }
    }
}
    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        // Called when image was captured from camera


        // Obtain the image from the uri
        Bitmap bitmap = null;
        int orientation;

        // Make sure we have an image_uri
        try {
            // Convert uri to an InputStream
            InputStream in = getContentResolver().openInputStream(image_uri);
            // Obtain Exif info from the InputStream
            ExifInterface ei = new ExifInterface(in);

            // Get bitmap depending on version
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {
                try {
                    bitmap = ImageDecoder.decodeBitmap(ImageDecoder.createSource(getContentResolver(), image_uri));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } else {
                try {
                    bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), image_uri);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            // Obtain orientation information from image
            orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                    ExifInterface.ORIENTATION_UNDEFINED);

            // Rotate the image (if needed) to portrait mode
            switch (orientation) {
                case ExifInterface.ORIENTATION_ROTATE_90:
                    rotatedBitmap = rotateImage(bitmap, 90);
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    rotatedBitmap = rotateImage(bitmap, 180);
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    rotatedBitmap = rotateImage(bitmap, 270);
                    break;
                case ExifInterface.ORIENTATION_NORMAL:
                default:
                    rotatedBitmap = bitmap;
            }
        }
        catch (IOException e) {
            e.printStackTrace();
        }





/* Here is where the issue begins.
I can obtain the processed image and set it to my ImageView no problem, so the variable rotatedBitmap
is NOT null. But when I try to pass it to classifier.recognizeImage() it throws the null pointer error
and crashes the app
*/ 
        if (resultCode == RESULT_OK) {
            // Set the image captured to our ImageView
            //mImageView.setImageURI(image_uri);
            mImageView.setImageBitmap(rotatedBitmap);

            if (rotatedBitmap != null) {
                float[][] result = classifier.recognizeImage(rotatedBitmap);
                String message = Arrays.toString(result[0]);
                Snackbar mySnackbar = Snackbar.make(findViewById(R.id.myCoordinatorLayout), message,
                        Snackbar.LENGTH_SHORT);
                mySnackbar.show();
            }
        }
    }







    public static Bitmap rotateImage(Bitmap source, float angle) {
        Matrix matrix = new Matrix();
        matrix.postRotate(angle);
        return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(),
                matrix, true);
    }
}


public class Classifier extends CameraActivity {

    private int inputSize = 300;
    private int pixelSize = 3;
    private int imageMean = 0;
    private float imageStd = 255.0f;
    private int maxResult = 3;
    private float threshHold = 0.4f;

    private List<String> labelList;
    private Interpreter interpreter;

    public static final String PREFIX = "stream2file";
    public static final String SUFFIX = ".tmp";


    public File stream2file (InputStream in) throws IOException {
        final File tempFile = File.createTempFile(PREFIX, SUFFIX);
        tempFile.deleteOnExit();
        try (FileOutputStream out = new FileOutputStream(tempFile)) {
            IOUtils.copy(in, out);
        }
        return tempFile;
    }



    public void init() {
        Interpreter.Options options = new Interpreter.Options();
        options.setNumThreads(5);
        options.setUseNNAPI(true);

        // Obtain the model from assets folder
        final AssetManager assets = getApplicationContext().getAssets();
        try {
            InputStream in = assets.open("detect.tflite");
            File file = stream2file(in);
            interpreter = new Interpreter(file, options);
            labelList = loadLabels("labelmap.txt", assets);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public List loadLabels(String labelPath, AssetManager assetManager) throws IOException {
        InputStream in = assetManager.open("labelmap.txt");
        BufferedReader br = new BufferedReader(new InputStreamReader(in));

        List outList = new ArrayList();
        String line;
        while( (line = br.readLine()) != null)
        {
            outList.add(line);
            }
        return outList;
    }




/*
Here is the recognizeImage method that I wish to call from the CameraActivity class.
-
-
-
*/
    public float[][] recognizeImage(final Bitmap bitmap) {
        // Scale the bitmap to the appropriate shape
        Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, inputSize, inputSize, false);
        ByteBuffer byteBuffer = convertBitmapToByteBuffer(scaledBitmap);
        final float[][] result = new float[1][labelList.size()];
        interpreter.run(byteBuffer, result);
        return result;

    }





    public ByteBuffer convertBitmapToByteBuffer(Bitmap bitmap) {
        //bitmap = Bit
        // Preallocate memory for bytebuffer
        ByteBuffer byteBuffer = ByteBuffer.allocate(4*inputSize*inputSize*pixelSize);
        byteBuffer.order(ByteOrder.nativeOrder());

        // Initialize pixel data array and populate from bitmap
        int [] intArray = new int[inputSize*inputSize];
        bitmap.getPixels(intArray, 0, bitmap.getWidth(), 0 , 0,
                bitmap.getWidth(), bitmap.getHeight());

        int pixel = 0;      // pixel indexer
        for (int i=0; i<inputSize; i++) {
            for (int j=0; j<inputSize; j++) {
                int input = intArray[pixel++];

                byteBuffer.putFloat((((input >> 16 & 0x000000FF) - imageMean) / imageStd));
                byteBuffer.putFloat((((input >> 8 & 0x000000FF) - imageMean) / imageStd));
                byteBuffer.putFloat((((input & 0x000000FF) - imageMean) / imageStd));
            }
        }
        return byteBuffer;
    }


}

1 Ответ

1 голос
/ 27 мая 2020

Измените Classifier, чтобы он ничего не расширял.

Инициализируйте этот объект с помощью:

Classifier classifier = new Classifier();
classifier.init();

перед вызовом нужного вам метода.

...