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!
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
)