Android Studio 中的 OpenCV - Haar Cascade - 如何检查是否检测到图像
OpenCV in Android Studio - Haar Cascade - How to check if image is detected
我编写了一个程序,用于使用 OpenCV 的 Haar Cascade 方法检测香蕉。
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;
}
在 运行 代码和香蕉出现在 Android 设备的相机中后,香蕉的轮廓将显示在矩形中,如下所示:
Banana Outlined in blue rectangle using the imgproc.rectangle function
在此之后,我希望添加一个按钮,按下该按钮后,如果屏幕上有香蕉,文本视图的文本将更改为 "Banana Detected",如果屏幕上有香蕉,则为 "Banana Not Detected"屏幕上没有。
这就是我卡住的地方,你如何检查屏幕上是否有香蕉?我知道必须使用 if-else,但我不确定所需的条件。非常感谢任何帮助!
如果没有检测到香蕉,您的 bananasArray
应该是空的。
在这种情况下,通过检查 bananasArray
是否包含数据来更改 TextView
。
(例如,通过检查是否 bananasArray.length > 0
)
我编写了一个程序,用于使用 OpenCV 的 Haar Cascade 方法检测香蕉。
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;
}
在 运行 代码和香蕉出现在 Android 设备的相机中后,香蕉的轮廓将显示在矩形中,如下所示:
Banana Outlined in blue rectangle using the imgproc.rectangle function
在此之后,我希望添加一个按钮,按下该按钮后,如果屏幕上有香蕉,文本视图的文本将更改为 "Banana Detected",如果屏幕上有香蕉,则为 "Banana Not Detected"屏幕上没有。
这就是我卡住的地方,你如何检查屏幕上是否有香蕉?我知道必须使用 if-else,但我不确定所需的条件。非常感谢任何帮助!
如果没有检测到香蕉,您的 bananasArray
应该是空的。
在这种情况下,通过检查 bananasArray
是否包含数据来更改 TextView
。
(例如,通过检查是否 bananasArray.length > 0
)