检测中的检测

这个例子使用 Dice 和骰子上的黑点(点子)作为我们的对象。由于示例很长,首先解释一些关键概念对于理解示例至关重要。

理解第一个示例“获取静态图像,检测其中的项目,然后输出结果”。对于理解这个例子至关重要,特别是 OpenCV 如何绘制矩形。

看一下下图:

StackOverflow 文档

我们将使用子成像方法,我们使用检测到的区域作为应用更多检测的基础。只有当一个对象永远位于我们可以检测到的另一个对象中时,例如我们骰子上的点数,这才有可能。这种方法有几个好处:

  • 在扫描整个图像时,我们只需要扫描我们知道对象所在的区域。
  • 消除检测区域外任何误报的可能性。

我们首先在整个图像上应用一个级联分类器扫描,为我们提供一个包含我们大对象的 MatOfRect 对象(在本例中为骰子)。然后我们迭代 toArray() 对象给出的 toArray() 对象提供的 Rect[] 数组。此 Rect 对象用于创建临时 Mat 对象,该对象从原始图像裁剪Rect 对象的属性(x, y, width, height),然后我们可以在临时 Mat 对象上执行检测。换句话说,我们告诉分类器仅对图像的骰子部分执行检测,并且我们通过使用从对整个图像执行检测获得的 Rect 对象来指定每个骰子的位置。

然而,Rect 对象(点子)具有相对于其骰子的属性,而不是图像本身。为了解决这个问题,当我们想要将矩形绘制到显示点位置的实际图像时,我们将 dice.xdice.y 添加到 start Point

import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;
import org.opencv.videoio.VideoCapture;

public class Classifier {

    private CascadeClassifier diceCascade =
        new CascadeClassifier("res/newMethod/diceCascade.xml");
    private CascadeClassifier pipCascade =
        new CascadeClassifier("res/newMethod/pipCascade6.xml");
    private VideoCapture vc = new VideoCapture();
    private Mat image;

    public void openVC(int index) {
        vc.open(index);
    }

    public void closeVC() {
        vc.close();
    }

    public Mat getNextImage() {
        image = new Mat();
        vc.read(image); // Sets the matrix to the current livestream frame.
        
        MatOfRect diceDetections = new MatOfRect(); // Output container
    
        // See syntax for explainations on addition parameters
        diceCascade.detectMultiScale(image, diceDetections, 1.1, 4, 0, new Size(20, 20),
            new Size(38, 38));
        
        // Iterates for every Dice ROI
        for (int i = 0; i < diceDetections.toArray().length; i++) {
            Rect diceRect = diceDetections.toArray()[i];
            
            // Draws rectangles around our detected ROI
            Point startingPoint = new Point(diceRect.x, diceRect.y);
            Point endingPoint = new Point(diceRect.x + diceRect.width,
                diceRect.y + diceRect.height);
            Imgproc.rectangle(image, startingPoint, endingPoint, new Scalar(255, 255, 0));
            
            MatOfRect pipDetections = new MatOfRect();
            
            pipCascade.detectMultiScale(image.submat(diceRect), pipDetections, 1.01, 4, 0,
                new Size(2, 2), new Size(10, 10));
            
            // Gets the number of detected pips and draws a cricle around the ROI
            for (int y = 0; y < pipDetections.toArray().length; y++) {
                // Provides the relative position of the pips to the dice ROI
                Rect pipRect = pipDetections.toArray()[y];
                
                // See syntax explaination
                // Draws a circle around our pips
                Point center = new Point(diceRect.x + pipRect.x + pipRect.width / 2,
                    diceRect.y + pipRect.y + pipRect.height / 2);
                Imgproc.ellipse(image, center, new Size(pipRect.width / 2, pipRect.height / 2),
                     0, 0, 360, new Scalar(255, 0, 255), 1, 0, 0);
            }
        }
        
        return image;
    }
}

getNextImage() 函数返回一个 Mat 对象,该对象与发布的其他示例一起可以被不断调用,并且可以转换为 BufferImage,以提供显示检测的直播。