Приложение со встроенным API Google Cloud Vision аварийно завершает работу с нулевой ссылкой на объект

1

В настоящее время я работаю над приложением для Android, где хочу интегрировать API Google Cloud Vision и распознавать лица на изображениях.

Код, который я реализовал до сих пор, чтобы сделать эту работу:

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v4.content.FileProvider;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import com.google.api.client.extensions.android.json.AndroidJsonFactory;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.services.vision.v1.Vision;
import com.google.api.services.vision.v1.VisionRequestInitializer;
import com.google.api.services.vision.v1.model.AnnotateImageRequest;
import com.google.api.services.vision.v1.model.BatchAnnotateImagesRequest;
import com.google.api.services.vision.v1.model.BatchAnnotateImagesResponse;
import com.google.api.services.vision.v1.model.FaceAnnotation;
import com.google.api.services.vision.v1.model.Feature;
import com.google.api.services.vision.v1.model.Image;

import org.apache.commons.io.IOUtils;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;

import static org.apache.commons.io.IOUtils.toByteArray;

public class HomeActivity extends AppCompatActivity {

    /* Variables */
    MarshMallowPermission mmp = new MarshMallowPermission(this);


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.home);
        super.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

        Vision.Builder visionBuilder = new Vision.Builder(
                new NetHttpTransport(),
                new AndroidJsonFactory(),
                null);

        visionBuilder.setVisionRequestInitializer(
                new VisionRequestInitializer("AIzaSyCnPwvnEQakkUXpkFaj2TcwJs_E3DPqjm0"));
        final Vision vision = visionBuilder.build();

        // Create new thread
        AsyncTask.execute(new Runnable() {
            @Override
            public void run() {
                // Convert photo to byte array
                InputStream inputStream =
                        getResources().openRawResource(R.raw.apollo9);
                byte[] photoData = new byte[0];
                try {
                    photoData = toByteArray(inputStream);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

                Image inputImage = new Image();
                inputImage.encodeContent(photoData);
                Feature desiredFeature = new Feature();
                desiredFeature.setType("FACE_DETECTION");
                AnnotateImageRequest request = new AnnotateImageRequest();
                request.setImage(inputImage);
                request.setFeatures(Arrays.asList(desiredFeature));
                BatchAnnotateImagesRequest batchRequest =
                        new BatchAnnotateImagesRequest();

                batchRequest.setRequests(Arrays.asList(request));
                BatchAnnotateImagesResponse batchResponse =
                        null;
                try {
                    batchResponse = vision.images().annotate(batchRequest).execute();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                List<FaceAnnotation> faces = batchResponse.getResponses()
                        .get(0).getFaceAnnotations();

                                    // Count faces
                                    int numberOfFaces = faces.size();

                    // Get joy likelihood for each face
                                    String likelihoods = "";
                                    for(int i=0; i<numberOfFaces; i++) {
                                        likelihoods += "\n It is " +
                                                faces.get(i).getJoyLikelihood() +
                                                " that face " + i + " is happy";
                                    }

                    // Concatenate everything
                                    final String message =
                                            "This photo has " + numberOfFaces + " faces" + likelihoods;

                    // Display toast on UI thread
                                    runOnUiThread(new Runnable() {
                                        @Override
                                        public void run() {
                                            Toast.makeText(getApplicationContext(),
                                                    message, Toast.LENGTH_LONG).show();
                                        }
                                    });
            }
        });



        // Check for Permission for Storage
        if (!mmp.checkPermissionForReadExternalStorage()) {
            mmp.requestPermissionForReadExternalStorage();
        }

        // MARK: - CAMERA BUTTON ------------------------------------
        Button camButt = findViewById(R.id.cameraButt);
        camButt.setOnClickListener(new View.OnClickListener() {
          @Override
          public void onClick(View view) {
              if (!mmp.checkPermissionForCamera()) {
                  mmp.requestPermissionForCamera();
              } else { openCamera(); }
        }});


        // MARK: - GALLERY BUTTON ------------------------------------
        Button galleryButt = findViewById(R.id.galleryButt);
        galleryButt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (!mmp.checkPermissionForReadExternalStorage()) {
                    mmp.requestPermissionForReadExternalStorage();
                } else { openGallery(); }
        }});





    }// end onCreate()




    // IMAGE HANDLING METHODS ------------------------------------------------------------------------
    int CAMERA = 0;
    int GALLERY = 1;
    Uri imageURI;
    File file;


    // OPEN CAMERA
    public void openCamera() {
        Intent intent= new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        file = new File(Environment.getExternalStorageDirectory(), "image.jpg");
        imageURI = FileProvider.getUriForFile(getApplicationContext(), getPackageName() + ".provider", file);
        intent.putExtra(MediaStore.EXTRA_OUTPUT, imageURI);
        startActivityForResult(intent, CAMERA);
    }


    // OPEN GALLERY
    public void openGallery() {
        Intent intent = new Intent();
        intent.setType("image/*");
        intent.setAction(Intent.ACTION_GET_CONTENT);
        startActivityForResult(Intent.createChooser(intent, "Select Image"), GALLERY);
    }



    // IMAGE PICKED DELEGATE -----------------------------------
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (resultCode == Activity.RESULT_OK) {
            Bitmap bm = null;

            // Image from Camera
            if (requestCode == CAMERA) {

                try {
                    File f = file;
                    ExifInterface exif = new ExifInterface(f.getPath());
                    int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);

                    int angle = 0;
                    if (orientation == ExifInterface.ORIENTATION_ROTATE_90) { angle = 90; }
                    else if (orientation == ExifInterface.ORIENTATION_ROTATE_180) { angle = 180; }
                    else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) { angle = 270; }
                    Log.i("log-", "ORIENTATION: " + orientation);

                    Matrix mat = new Matrix();
                    mat.postRotate(angle);

                    Bitmap bmp = BitmapFactory.decodeStream(new FileInputStream(f), null, null);
                    bm = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), mat, true);

                    // Get FINAL IMAGE URI
                    Configs.finalImageUri = getImageUri(HomeActivity.this, bm);

                }
                catch (IOException | OutOfMemoryError e) { Log.i("log-", e.getMessage()); }


                // Image from Gallery
            } else if (requestCode == GALLERY) {
                try {
                    bm = MediaStore.Images.Media.getBitmap(getApplicationContext().getContentResolver(), data.getData());

                    // Get FINAL IMAGE URI
                    Configs.finalImageUri = getImageUri(HomeActivity.this, bm);

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

            Log.i("log-", "FINAL IMAGE URI: " + Configs.finalImageUri);
            startActivity(new Intent(HomeActivity.this, ImageEditor.class));
        }

    }
    //---------------------------------------------------------------------------------------------




    // Method to get URI of a stored image
    public Uri getImageUri(Context inContext, Bitmap inImage) {
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
        String path = MediaStore.Images.Media.insertImage(inContext.getContentResolver(), inImage, "image", null);
        return Uri.parse(path);
    }



}// @end

XML файл макета:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".HomeActivity">


    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="50dp"
        android:text="TEXTIFEYE"
        android:textSize="30sp" />

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_below="@+id/textView2"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="10dp"
        android:scaleType="centerCrop"
        app:srcCompat="@drawable/logo" />

    <Button
        android:id="@+id/cameraButt"
        android:layout_width="44dp"
        android:layout_height="44dp"
        android:layout_below="@+id/imageView"
        android:layout_marginTop="50dp"
        android:layout_toStartOf="@+id/imageView"
        android:background="@drawable/camera_butt" />

    <TextView
        android:id="@+id/textView3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignEnd="@+id/cameraButt"
        android:layout_alignStart="@+id/cameraButt"
        android:layout_below="@+id/cameraButt"
        android:text="CAMERA"
        android:textAlignment="center"
        android:textSize="10sp" />

    <Button
        android:id="@+id/galleryButt"
        android:layout_width="44dp"
        android:layout_height="44dp"
        android:layout_alignTop="@+id/cameraButt"
        android:layout_toEndOf="@+id/imageView"
        android:background="@drawable/gallery_butt" />

    <TextView
        android:id="@+id/textView4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignEnd="@+id/galleryButt"
        android:layout_alignStart="@+id/galleryButt"
        android:layout_below="@+id/galleryButt"
        android:text="GALLERY"
        android:textSize="10sp" />
</RelativeLayout>

Сообщение журнала:

java.lang.NullPointerException: Attempt to invoke virtual method 'java.util.List com.google.api.services.vision.v1.model.BatchAnnotateImagesResponse.getResponses()' on a null object reference
    at gmbh.webagenten.textifeye.HomeActivity$1.run(HomeActivity.java:113)
    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
    at java.lang.Thread.run(Thread.java:764)

Я в основном не знаю, почему приложение падает там с нулевой ссылкой на объект, и буду благодарен за любые подсказки и отзывы, спасибо!

Теги:
google-vision

1 ответ

1
Лучший ответ

У вас есть batchResponse = vision.images().annotate(batchRequest).execute(); внутри блока try-catch, что означает, что есть вероятность, что этот оператор не всегда будет выполнен. Вы должны запрашивать batchResponse только тогда, когда уверены, что вышеприведенный оператор выполнялся. Так:

либо переместите код после try-catch внутри блока try следующим образом:

try {
    batchResponse = vision.images().annotate(batchRequest).execute();
    List<FaceAnnotation> faces = batchResponse.getResponses()
                    .get(0).getFaceAnnotations();

    // Count faces
    int numberOfFaces = faces.size();
    .
    .
    .
} 
catch (IOException e) {
    e.printStackTrace();
}

или инициализировать batchResponse с пустым объектом вместо нуля, если это возможно

Ещё вопросы

Сообщество Overcoder
Наверх
Меню