我正在获取从OpenCV回调方法onCameraFrame()提供的Mat图像。这是我从参数传递的CvCameraViewFrame inputFrame中获得的。此回调方法要求将Mat图片返回。
目的是将该Mat图像提供给HoughCircles()方法,以检测相机取景器帧图像中的圆形对象。
此示例中对OpenCV的这种使用是要在Android中使用的Java API版本
问题是,我在onCameraFrame()回调方法中使用的两个方法需要花费一些时间来处理和减慢相机fiewfinder视频帧速率。
Imgproc.GaussianBlur(mGray, mGray, new Size(5, 5), 2, 2);
Imgproc.HoughCircles(mGray, circles, Imgproc.CV_HOUGH_GRADIENT,
1, mGray.rows()/8, 150, 60, 30, 0);
帧速率变化缓慢,尤其是在帧中检测到对象时。我发现提高此帧速率的唯一方法是减小帧大小。这会导致图像质量下降,即使这种变化,帧速率仍然太慢。
如何避免这个问题?我试图将Mat mGray和mRGB对象传递到单独的线程中,然后从onCameraFrame()回调方法内部启动它。使用后台线程不起作用。尝试了Java线程和AsyncTask。
尝试了两种类型的解决方案,
输入一种可能的解决方案
使用带有整数变量的计数器进行尝试,每次调用onCameraFrame()方法时,该变量都会递增,因此只有十个方法之一或二十个方法调用中的一个会启动一个新线程来处理图像HoughCircles。这没有用。
第二种可能的解决方案
我尝试过的另一件事是使用AtomicBoolean或Boolean阻止新线程的启动,直到最后一个线程完成执行为止,这将确保一次仅启动一个后台线程,并且仅一个Mat图像一次由HoughCircles方法处理。由于某些原因,这也不起作用。它显示在下面的示例代码中。
我能够使此圆检测代码正常工作的唯一方法是根本不使用任何后台线程。只需将HoughCircles()方法和所有其他代码(用于检查onCameraFrame()回调方法中的帧)放在同一线程中即可。如前所述,这确实减慢了帧速率,但是正在调用HoughCircles()方法,并且实际上我得到了Log消息以在logcat中显示,该消息显示已检测到或未检测到圆。
如何在不降低相机取景器帧速率的情况下在后台线程上使用它?
public void onCameraViewStarted(int width, int height) {
mGray = new Mat();
mRgba = new Mat();
camera = mOpenCvCameraView.getCamera();
Camera.Parameters params = camera.getParameters();
camera.setParameters(params);
previewStatus = true;
} // onCameraViewStarted
public void onCameraViewStopped() {
previewStatus = false;
mGray.release();
mRgba.release();
} // onCameraviewStopped
1-圆环检测的同步版本,可以工作,但是会降低帧速率
public Mat onCameraFrame(final CvCameraViewFrame inputFrame) {
mRgba = inputFrame.rgba();
mGray = inputFrame.gray();
MatOfRect circles = new MatOfRect();
// doing a gaussian blur prevents getting a lot of false hits
Imgproc.GaussianBlur(mGray, mGray, new Size(5, 5), 2, 2);
// for detection of circles
Imgproc.HoughCircles(mGray, circles, Imgproc.CV_HOUGH_GRADIENT,
1, mGray.rows()/8, 150, 60, 30, 0);
// returns int as number of circles detected
int detected = circles.cols();
// if detected circles is more than zero
// or Animation settings page fragment is not visible on screen
if((detected > 0) {
Log.i("CIRCLE DETECTION", "number circles detected" + circles);
// add action method to be called here on circle detection
} else {
Log.i("CIRCLE DETECTION", "no circles detected");
}
circles.release();
return mRgba;
} // onCameraFrame
2-异步版本的“圈子检测”不起作用
public Mat onCameraFrame(final CvCameraViewFrame inputFrame) {
mRgba = inputFrame.rgba(); // colo
mGray = inputFrame.gray(); // grayscale required for detection
// if detected circles is more than zero
// or Animation settings page fragment is not visible on screen
if((detected > 0)&&(!detectionRunning)) {
// prevent any more Asynchronous task threads from being launched
// until this one is finished running
detectionRunnning = false;
// launnch new Asynchronous task that takes mGray Mat image
// and checks to see of any circles exist by using
// the OpenCV Imgproc.HoughCircles() method, passing
// in the mGray as parameter to the doInBackground() method
// of this class
new CircleTask().execute(mGray);
}
// mRgba must be returned with this callback method to show
// up on screen of viewfinder
return mRgba;
} // onCameraFrame
// background thread task takes Mat image from onCameraFrame and
// runs the HoughCircles method on a background thread so UI thread is not blocked
public class CircleTask extends AsyncTask<Mat, Void, Integer> {
// run detection method in background thread
// takes in parameter in the .execute(Mat mGray) call on the class that is created
@Override
protected Integer doInBackground(Mat... params) {
grayMatImage = params[0];
MatOfRect circles = new MatOfRect();
// doing a gaussian blur prevents getting a lot of false positives
Imgproc.GaussianBlur(grayMatImage, grayMatImage, new Size(5, 5), 2, 2);
// for detection of circles
Imgproc.HoughCircles(grayMatImage, circles, Imgproc.CV_HOUGH_GRADIENT,
1, grayMatImage.rows()/8, 150, 60, 30, 0);
// int detected is the number of circles detected
int detected = circles.cols();
circles.release();
grayMatImage.release();
// this integer is passes to the onPostExecute method below
return detected;
}
// result Integer is passed here after
// this method is run on main UI thread
@Override
protected void onPostExecute(Integer result) {
Log.i("RESULT OF DETECTION", "number of circles detected " + result);
// add methods here to be executed after circle is detected
// stop blocking and allow the next frame to be an
detectionRunning = false;
}
}
最佳答案
两个线程试图访问相同的数据(mGray)。
您没有在胎面中使用grayMatImage参数,可能是应该使用它而不是mGray吗?