Passing Bitmap variable to method in extended class

-1

My code implements TFlite and I have two classes:

1) Deals with camera activity and processing of image

2) Deals with specifics of the model and detector.

I have a method in the extended class which runs the model. I am trying to call that method from within the main class. I am new to Java so I don't quite know why I keep getting java.lang.NullPointerException error.

See code below (I will leave lots of white-space and comment around the pieces that are relevant):

Method which makes the call:

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

Full Code:

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


}
java
android
oop
methods
bitmap
asked on Stack Overflow May 27, 2020 by Kyle Marshall • edited May 27, 2020 by Kyle Marshall

1 Answer

1

Change Classifier so that it does not extend anything.

Initialize this object with:

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

before you call the method you need.

answered on Stack Overflow May 27, 2020 by codebod

User contributions licensed under CC BY-SA 3.0