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;
}
}
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.
User contributions licensed under CC BY-SA 3.0