Search code examples
androidopencvif-statementimage-processinghaar-classifier

OpenCV in Android Studio - Haar Cascade - How to check if image is detected


I wrote a program that is used to detect bananas using OpenCV's Haar Cascade method.

public class MainActivity extends Activity implements CvCameraViewListener2 {

private static final String TAG = "OCVSample::Activity";
private static final Scalar BANANA_RECT_COLOR = new Scalar(0, 255, 0, 255);
public static final int JAVA_DETECTOR = 0;

private Mat mRgba;
private Mat mGray;
private File mCascadeFile;
private CascadeClassifier mJavaDetectorBanana;
boolean check = false;

private int mDetectorType = JAVA_DETECTOR;
private String[] mDetectorName;

private float mRelativeBananaSize = 0.2f;
private int mAbsoluteBananaSize = 0;

private CameraBridgeViewBase mOpenCvCameraView;

public Button mSpeechButton;
public TextView checkResults;

double xCenter = -1;
double yCenter = -1;

private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
    @Override
    public void onManagerConnected(int status) {
        switch (status) {
            case LoaderCallbackInterface.SUCCESS: {
                Log.i(TAG, "OpenCV Loaded Successfully");

                try {
                    InputStream is = getResources().openRawResource(R.raw.banana4th);
                    File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);
                    mCascadeFile = new File(cascadeDir, "banana4th.xml");
                    FileOutputStream os = new FileOutputStream(mCascadeFile);

                    byte[] buffer = new byte[4096];
                    int bytesRead;
                    while ((bytesRead = is.read(buffer)) != -1) {
                        os.write(buffer, 0, bytesRead);
                    }
                    is.close();
                    os.close();

                    mJavaDetectorBanana = new CascadeClassifier(mCascadeFile.getAbsolutePath());
                    if (mJavaDetectorBanana.empty()) {
                        Log.e(TAG, "Failed to load cascade classifier");
                        mJavaDetectorBanana = null;
                    } else
                        Log.i(TAG, "Loaded cascade classifier from " + mCascadeFile.getAbsolutePath());

                    cascadeDir.delete();
                } catch (IOException e) {
                    e.printStackTrace();
                    Log.e(TAG, "Failed to load cascade. Exception thrown: " + e);
                }
                mOpenCvCameraView.enableFpsMeter();
                mOpenCvCameraView.setCameraIndex(0);
                mOpenCvCameraView.enableView();
            }
            break;
            default: {
                super.onManagerConnected(status);
            }
            break;
        }
    }
};

public MainActivity() {
    mDetectorName = new String[2];
    mDetectorName[JAVA_DETECTOR] = "Java";
    Log.i(TAG, "Instantiated new" + this.getClass());
}

@Override
public void onCreate(Bundle savedInstanceState){
    Log.i(TAG,"Called onCreate");
    super.onCreate(savedInstanceState);
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

    setContentView(R.layout.activity_main);

    mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.fd_activity_surface_view);
    mOpenCvCameraView.setCvCameraViewListener(this);
    mSpeechButton = (Button) findViewById(R.id.ttsBtn);
    checkResults = (TextView) findViewById(R.id.checkResultTB);

    Button backButton = (Button) findViewById(R.id.backBtn);

    backButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent UIActivity = new Intent(MainActivity.this, UiActivity.class);
            startActivity(UIActivity);
        }
    });
    }

@Override
public void onPause() {
    super.onPause();
    if(mOpenCvCameraView!=null)
        mOpenCvCameraView.disableView();
}

@Override
public void onResume() {
    super.onResume();
    if (!OpenCVLoader.initDebug()) {
        Log.d(TAG, "Internal OpenCV library not found. Using OpenCV Manager for initialization");
        OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_3_0, this, mLoaderCallback);
    } else {
        Log.d(TAG, "OpenCV library found inside package. Using it!");
        mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
    }
}

public void onDestroy() {
    super.onDestroy();
    mOpenCvCameraView.disableView();
}

public void onCameraViewStarted(int width, int height) {
    mGray = new Mat();
    mRgba = new Mat();
}

public void onCameraViewStopped() {
    mGray.release();
    mRgba.release();
}

public Mat onCameraFrame(CvCameraViewFrame inputFrame) {

    mRgba = inputFrame.rgba();
    mGray = inputFrame.gray();

    if (mAbsoluteBananaSize == 0) {
        int height = mGray.rows();
        if (Math.round(height * mRelativeBananaSize) > 0) {
            mAbsoluteBananaSize = Math.round(height * mRelativeBananaSize);
        }
    }

    MatOfRect bananas = new MatOfRect();

    if (mDetectorType == JAVA_DETECTOR) {
        if (mJavaDetectorBanana != null) {
            mJavaDetectorBanana.detectMultiScale(mGray, bananas, 1.1, 2, 2, //TODO: objdetect.CV_HAAR_SCALE_IMAGE)
                    new Size(mAbsoluteBananaSize, mAbsoluteBananaSize), new Size());
        }
    } else {
        Log.e(TAG, "Detection method is not selected!");
    }

    Rect[] bananasArray = bananas.toArray();
    for (int i = 0; i < bananasArray.length; i++) {
        Imgproc.rectangle(mRgba, bananasArray[i].tl(), bananasArray[i].br(), BANANA_RECT_COLOR, 3);
        xCenter = (bananasArray[i].x + bananasArray[i].width + bananasArray[i].x) / 2;
        yCenter = (bananasArray[i].y + bananasArray[i].height + bananasArray[i].y) / 2;
    }
    return mRgba;
}

After running the code and a banana is present in the Android device's camera, the banana will be outlined in a rectangle as shown:

Banana Outlined in blue rectangle using the imgproc.rectangle function

After this, I wish to add a button which upon being pressed, will change the text of a textview to say "Banana Detected" if a banana is present on the screen and "Banana Not Detected" if a banana is not present on the screen.

This is where I'm stuck, how do you check if a banana is on screen? I know an if-else must be used but I'm unsure of the conditions needed. Any help is greatly appreciated!


Solution

  • If no bananas are detected, your bananasArray should be empty. In this case, change the TextView by checking if bananasArray contains data.

    (For example, by checking if bananasArray.length > 0)