在OpenCV中无阻塞地从回调方法获取图像

时间:2014-05-08 05:01:11

标签: java android multithreading opencv camera

我正在获取OpenCV回调方法onCameraFrame()提供的Mat图像。这是我从CvCameraViewFrame输入参数传递的inputFrame。此回调方法需要返回Mat图像。

目的是将此Mat图像提供给HoughCircles()方法,以检测相机取景器框架图像中的圆形对象。

此示例中对OpenCV的使用是在Android

中使用的Java API版本

问题是我在onCameraFrame()回调方法中使用的两种方法需要时间来处理并降低相机视频帧速率。

 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()方法时递增,因此只有十分之一或20个方法调用中的一个将启动一个新线程来处理图像HoughCircles。这没用。

输入两个可能的解决方案

我尝试的另一件事是使用AtomicBoolean或Boolean来阻止新线程的启动,直到最后一个线程完成执行为止。这将确保一次只启动一个后台线程,并且仅一个Mat图像由HoughCircles方法一次处理。由于某种原因,这也不起作用。它显示在下面的示例代码中。

我能够让这个圆检测代码工作的唯一方法就是不要使用任何后台线程。只是将HoughCircles()方法和所有其余代码用于检查同一线程中onCameraFrame()回调方法中的帧。如前所述,这确实会降低帧速率,但HoughCircles()方法正在调用,我实际上会在logcat中显示Log消息,显示检测到的圆圈或未检测到圆圈。

如何在不降低相机取景器帧速率的情况下让它在后台线程上工作?

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 - ASynchRONOUS版本的圆形检测,不起作用

   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;

   }

   }

1 个答案:

答案 0 :(得分:0)

两个线程试图访问相同的数据(mGray)。

你没有在胎面上使用grayMatImage参数,可能应该用它代替mGray吗?