在 Android 中使用 OpenCV 检测图像中的圆

Detect Circle in image using OpenCV in Android

我正在开发一个 android 应用程序,其中 我必须检测现有图像上的圆圈,从画廊浏览或从相机捕获。浏览/捕获的图像将显示在 ImageView 上。顺便说一句,我正在使用 OpenCVAndroid Library 并且我正确地编译了它。

对我的 android 应用程序有任何帮助,我读过 C、C++ 等关于检测圆圈的内容,但我无法理解它,因为 android 的语言不同。

谢谢。

更新

好吧……我就是这样用的。

            if (requestCode == 1) { //Take Photo from Android Camera..

            File f = new File(Environment.getExternalStorageDirectory().toString());
            for (File temp : f.listFiles()) {
                if (temp.getName().equals("temp.jpg")) {
                    f = temp;
                    break;
                }
            }
            try {
                Bitmap bitmap;
                BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();

                bitmap = BitmapFactory.decodeFile(f.getAbsolutePath(),
                        bitmapOptions);

                // bitmap = Bitmap.createScaledBitmap(bitmap, 70, 70, true);



                String path = android.os.Environment
                        .getExternalStorageDirectory()
                        + File.separator
                        + "Phoenix" + File.separator + "default";
                f.delete();
                OutputStream outFile = null;
                File file = new File(path, String.valueOf(System.currentTimeMillis()) + ".jpg");
                try {
                    outFile = new FileOutputStream(file);
                    bitmap.compress(Bitmap.CompressFormat.JPEG, 85, outFile);
                    outFile.flush();
                    outFile.close();
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (Exception e) {
                    e.printStackTrace();
                }

                                    /* convert bitmap to mat */
                Mat mat = new Mat(bitmap.getWidth(), bitmap.getHeight(),
                        CvType.CV_8UC1);
                Mat grayMat = new Mat(bitmap.getWidth(), bitmap.getHeight(),
                        CvType.CV_8UC1);

                Utils.bitmapToMat(bitmap, mat);

                  /* convert to grayscale */
                int colorChannels = (mat.channels() == 3) ? Imgproc.COLOR_BGR2GRAY
                        : ((mat.channels() == 4) ? Imgproc.COLOR_BGRA2GRAY : 1);

                Imgproc.cvtColor(mat, grayMat, colorChannels);

                /* reduce the noise so we avoid false circle detection */
                Imgproc.GaussianBlur(grayMat, grayMat, new Size(9, 9), 2, 2);

                // accumulator value
                double dp = 1.2d;
                // minimum distance between the center coordinates of detected circles in pixels
                double minDist = 20;

               // min and max radii (set these values as you desire)
                int minRadius = 0, maxRadius = 0;

               // param1 = gradient value used to handle edge detection
              // param2 = Accumulator threshold value for the
              // cv2.CV_HOUGH_GRADIENT method.
              // The smaller the threshold is, the more circles will be
              // detected (including false circles).
              // The larger the threshold is, the more circles will
              // potentially be returned.
                double param1 = 70, param2 = 72;

              /* create a Mat object to store the circles detected */
                Mat circles = new Mat(bitmap.getWidth(),
                        bitmap.getHeight(), CvType.CV_8UC1);

              /* find the circle in the image */
                Imgproc.HoughCircles(grayMat, circles,
                        Imgproc.CV_HOUGH_GRADIENT, dp, minDist, param1,
                        param2, minRadius, maxRadius);

              /* get the number of circles detected */
                int numberOfCircles = (circles.rows() == 0) ? 0 : circles.cols();

              /* draw the circles found on the image */
                for (int i=0; i<numberOfCircles; i++) {


              /* get the circle details, circleCoordinates[0, 1, 2] = (x,y,r)
               * (x,y) are the coordinates of the circle's center*/
                                      double[] circleCoordinates = circles.get(0, 0);


                    int x = (int) circleCoordinates[0], y = (int) circleCoordinates[1];

                    Point center = new Point(x, y);

                    int radius = (int) circleCoordinates[2];

/* circle's outline */
                    Core.circle(mat, center, radius, new Scalar(0,
                            255, 0), 4);

/* circle's center outline */
                    Core.rectangle(mat, new Point(x - 5, y - 5),
                            new Point(x + 5, y + 5),
                            new Scalar(0, 128, 255), -1);
                }

              /* convert back to bitmap */
                Utils.matToBitmap(mat, bitmap);
                viewImage.setImageBitmap(bitmap);
            } catch (Exception e) {
                e.printStackTrace();
            }

        }

我 运行 我的应用程序使用上面的代码,我的 Android phone 在我从相机拍照后崩溃并且我在 logcat 中有这个错误:

          02-10 06:54:15.773    8914-8914/com.example.cloud.circle E/AndroidRuntime﹕ FATAL EXCEPTION: main

java.lang.UnsatisfiedLinkError: n_Mat
        at org.opencv.core.Mat.n_Mat(Native Method)
        at org.opencv.core.Mat.<init>(Mat.java:477)
        at com.example.cloud.circle.Image.onActivityResult(Image.java:152)
        at android.app.Activity.dispatchActivityResult(Activity.java:3908)
        at android.app.ActivityThread.deliverResults(ActivityThread.java:2532)
        at android.app.ActivityThread.handleSendResult(ActivityThread.java:2578)
        at android.app.ActivityThread.access00(ActivityThread.java:117)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:965)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:130)
        at android.app.ActivityThread.main(ActivityThread.java:3687)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:507)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:625)
        at dalvik.system.NativeStart.main(Native Method)

请帮助我。谢谢

可以找到圆检测的详细解释here and here(虽然Java中没有)。

我在下面提供了一个用于圆圈检测的示例代码片段,这些代码片段来自我上面提供的 2 个链接。代码有注释,所以很容易理解。我假设图像位图bitmap已经有你要分析的图像。

/* convert bitmap to mat */
Mat mat = new Mat(bitmap.getWidth(), bitmap.getHeight(),
        CvType.CV_8UC1);
Mat grayMat = new Mat(bitmap.getWidth(), bitmap.getHeight(),
        CvType.CV_8UC1);

Utils.bitmapToMat(bitmap, mat);

/* convert to grayscale */
int colorChannels = (mat.channels() == 3) ? Imgproc.COLOR_BGR2GRAY
        : ((mat.channels() == 4) ? Imgproc.COLOR_BGRA2GRAY : 1);

Imgproc.cvtColor(mat, grayMat, colorChannels);

/* reduce the noise so we avoid false circle detection */
Imgproc.GaussianBlur(grayMat, grayMat, new Size(9, 9), 2, 2);

// accumulator value
double dp = 1.2d;
// minimum distance between the center coordinates of detected circles in pixels
double minDist = 100;

// min and max radii (set these values as you desire)
int minRadius = 0, maxRadius = 0;

// param1 = gradient value used to handle edge detection
// param2 = Accumulator threshold value for the
// cv2.CV_HOUGH_GRADIENT method.
// The smaller the threshold is, the more circles will be
// detected (including false circles).
// The larger the threshold is, the more circles will
// potentially be returned.
double param1 = 70, param2 = 72;

/* create a Mat object to store the circles detected */
Mat circles = new Mat(bitmap.getWidth(),
        bitmap.getHeight(), CvType.CV_8UC1);

/* find the circle in the image */
Imgproc.HoughCircles(grayMat, circles,
        Imgproc.CV_HOUGH_GRADIENT, dp, minDist, param1,
        param2, minRadius, maxRadius);

/* get the number of circles detected */
int numberOfCircles = (circles.rows() == 0) ? 0 : circles.cols();

/* draw the circles found on the image */
for (int i=0; i<numberOfCircles; i++) {


/* get the circle details, circleCoordinates[0, 1, 2] = (x,y,r)
 * (x,y) are the coordinates of the circle's center
 */
    double[] circleCoordinates = circles.get(0, i);


    int x = (int) circleCoordinates[0], y = (int) circleCoordinates[1];

    Point center = new Point(x, y);

    int radius = (int) circleCoordinates[2];

    /* circle's outline */
    Core.circle(mat, center, radius, new Scalar(0,
            255, 0), 4);

    /* circle's center outline */
    Core.rectangle(mat, new Point(x - 5, y - 5),
            new Point(x + 5, y + 5),
            new Scalar(0, 128, 255), -1);
}

/* convert back to bitmap */
Utils.matToBitmap(mat, bitmap);

更新

为了防止 UnsatisfiedLinkError,在使用 OpenCV 库函数之前,请确保加载库文件,如下所示:

if (!OpenCVLoader.initDebug()) {
    Log.e(TAG, "Cannot connect to OpenCV Manager");
}