安卓 OpenCV:提高检测质量

6

目前我正在开发一款应用程序,它将从照片中检测出圆形。我已经成功编写了代码,但是如果我将手机离PC屏幕稍微远一点,它就会出现假阴性或假阳性的情况。我该如何改进结果?我的意思是,有很多应用程序可以检测小而不清晰的圆形。

[更新]

我在GaussianBlurHoughCircles中调整了数值。将Imgproc.GaussianBlur(grayMat, grayMat, new Size(9, 9), 2, 2);更改为Imgproc.GaussianBlur(grayMat, grayMat, new Size(9, 9), 9, 9);,将双倍的param1 = 70, param2 = 72;更改为double param1 = 50, param2 = 52;可以改善结果,但还不够好。

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

            int colorChannels = (mat.channels() == 3) ? Imgproc.COLOR_BGR2GRAY
                    : ((mat.channels() == 4) ? Imgproc.COLOR_BGRA2GRAY : 1);

            Imgproc.cvtColor(mat, grayMat, colorChannels);


            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;


            int minRadius = 0, maxRadius = 0;

            double param1 = 70, param2 = 72;


            Mat circles = new Mat(bitmap.getWidth(),
                    bitmap.getHeight(), CvType.CV_8UC1);


            Imgproc.HoughCircles(grayMat, circles,
                    Imgproc.CV_HOUGH_GRADIENT, dp, minDist, param1,
                    param2, minRadius, maxRadius);


            int numberOfCircles = 9;

            if (numberOfCircles > circles.cols()){ 
                numberOfCircles = circles.cols();
             }


            for (int i=0; i<numberOfCircles;  i++) {



                double[] circleCoordinates = circles.get(0, i);



                if(circleCoordinates == null){
                break;
                 }



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

                Point center = new Point(x, y);
                android.graphics.Point centerC = new android.graphics.Point(x, y);

                int radius = (int) circleCoordinates[2];



                Core.circle(mat, center, radius, new Scalar(0,
                        255, 0), 4);


                Core.rectangle(mat, new Point(x - 5, y - 5),
                        new Point(x + 5, y + 5),
                        new Scalar(0, 128, 255), -1);

谢谢您的提前帮助。

目前我使用这些A形点来测试代码,但是我想在照片上检测到更小的圆圈。 enter image description here


你尝试过不同的参数组合来测试param1和param2吗? - Mark Miller
没有。你认为我应该如何尝试更改它们?增加参数2吗? - Oleksandr Firsov
我的第一个猜测是降低参数2。你会有更多的假阳性,但我觉得处理假阳性比处理假阴性更容易。其次,尝试减小参数1。这会增加Canny边缘检测器的灵敏度,在寻找在背景中不明显的圆形时可能有用。 - Mark Miller
好的。我会尝试调整数值。你知道如何修复当圆圈少于9个时崩溃的问题吗? - Oleksandr Firsov
已发布答案。如果参数调整有效,请告诉我。 - Mark Miller
3个回答

1

我认为,如果你想仅检测白色圆形,你需要实现颜色检测。这不仅会大大提高检测质量,还会消除许多误报和漏报。使用颜色检测非常简单,因为它已经存在于OpenCV中。为此,请使用Core.inRange函数。您可以在这里找到更多信息。但对您来说可能最好的是遵循这个教程。它是用Python编写的,但易于理解,并且只需要更改几行代码即可使其适用于Android。希望这可以帮助您 :)


嘿,感谢你详细的回答!如果你看一下评论,你会发现我已经想出了同样的解决方案。唉,要是你几天前回复我就好了... - Oleksandr Firsov
那是不是意味着我不会得到奖励?T-T - Oleksandr Firsov
不过,我想你还是值得的。再次感谢。 - Oleksandr Firsov
你能发布可用的Android代码吗,@Olelsandr Firsov? - Pranesh Sahu
不行。代码存档在我的电脑上,找起来很麻烦。但我还记得问题所在。检测不准确是因为你设置了一个非常具体的颜色进行检测。inRange函数允许你包括不仅是这个确切的颜色,还包括它的阴影,从而提高检测的准确性。只需查看链接以获取更多信息。第一个链接无法使用,但从外观上看,它是文档。请前往openCV网站并搜索该函数。 - Oleksandr Firsov

0

试试这个。

  Mat input  = new Mat();
  Mat rgb = new Mat();
  Mat output = new Mat();
  Bitmap bitmap = BitmapFactory.decodeFile(mCurrentImagePath, bitOpts);
  input = Utils.bitmapToMat(bitmap);
  FeatureDetector fast = FeatureDetector.create(FeatureDetector.FAST);
  List<KeyPoint> keypoints = new ArrayList<KeyPoint>();
  fast.detect(input, keypoints);
  Imgproc.cvtColor(input, rgb, Imgproc.COLOR_RGBA2RGB);
  Features2d.drawKeypoints(rgb, keypoints, rgb);
  Imgproc.cvtColor(rgb, output, Imgproc.COLOR_RGB2RGBA);
  Utils.matToBitmap(output, bitmap);
  //SHOW IMAGE
  mImageView.setImageBitmap(bitmap);
  input.release();
  rgb.release();
  output.release();

谢谢你的回答,但我认为我已经解决了这个问题 - 我实现了颜色检测。 - Oleksandr Firsov
@OleksandrFirsov 那么问题出在哪里? - Michele Lacorte

0

通常情况下,将param1和param2设置得更小会放宽识别圆形的阈值,因此会有更多的误报(在没有圆形的地方检测到圆形)和更少的漏报(在有圆形的地方未检测到圆形)。

Param2设置了圆形检测的阈值。如果这个数字更小,一般会检测到更多的圆形。

Param1设置了Canny边缘检测器的灵敏度阈值。如果这个数字更小,比较微弱的圆形就比使用更大的数字更容易被检测到。

与计算机视觉或机器学习中的任何事物一样,如果它不能可靠地工作并且您不知道原因,请尝试更改一些参数。 :-D

当圆形数量少于9个时崩溃是由于将圆形数量硬编码为9。当圆形数量少于9个时,程序会尝试访问Mat数组的边界之外。

我目前没有测试OpenCV的系统,但我可以编写一些代码。我的唯一警告是您可能需要使用circles.rows而不是circles.cols。编辑:另外,如果circles没有0个条目,则circles为空。

int numberOfCircles = 9;
if (circles == null) numberOfCircles = 0;
else if (numberOfCircles > circles.cols) numberOfCircles = circles.cols;

for (int i=0; i<numberOfCircles;  i++) {
    double[] circleCoordinates = circles.get(0, i);
    ...

这段代码有所帮助。部分地解决了问题。现在,如果我有1到x个圆圈,应用程序不会崩溃。但是,如果数量为0,则会崩溃。 - Oleksandr Firsov
好的。我已经修复了崩溃错误,添加了以下代码:if(circleCoordinates == null){ break; } - Oleksandr Firsov
尝试调整minRadius和maxRadius参数。如果您只想找到门上和较小的圆圈,则可以向圆形检测器提供该信息。 - Mark Miller
好的,我想我的问题已经解决了——我正在实现颜色检测,这将消除大多数甚至所有的误报。还是谢谢您。 - Oleksandr Firsov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接