角点检测不准确

时间:2016-08-18 16:37:37

标签: java opencv corner-detection

我正在尝试检测角落,但我得到的坐标总是偏离中心,并且多次检测到鞍点。

我尝试了cornerHarriscornerMinEigenValpreCornerDetectgoodFeaturesToTrackcornerEigenValsAndVecs,但它们似乎都会导致相同的结果。我没有尝试findChessboardCorners,因为我的角落没有布置在n×m的漂亮网格中,不是所有的马鞍型,还有更多的原因。

我现在拥有的:

鉴于下面的(预处理)相机图像带有一些正,负和鞍角:

demo

cornerHarris(img, energy, 20, 9, 0.1)之后(为了说明的目的,我将blockSize增加到了20,但小值也不起作用)我得到了这张图片:

demo

它似乎检测到10个角,但它们的定位方式很奇怪。我将这张图片叠加在原稿上以显示我的问题:

demo

最高匹配能量点朝向角落内侧偏移,并且有一个指向角落的羽状物。马鞍角似乎会产生四个独立的羽状物。

事实上,当我使用这个能量图像进行角点搜索时,我会得到类似的结果:

demo / demo

我做错了什么?如何在这个模拟图像中准确地检测角落?

demo

[[edit]] MCVE:

public class CornerTest {
    static {
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
    }

    private static Mat energy = new Mat();
    private static Mat idx    = new Mat();

    public static void main(String... args) {
        Mat byteImage = Highgui.imread("KXw7O.png");
        if (byteImage.channels() > 1)
            Imgproc.cvtColor(byteImage, byteImage, Imgproc.COLOR_BGR2GRAY);

        // Preprocess
        Mat floatImage = new Mat();
        byteImage.convertTo(floatImage, CvType.CV_32F);

        // Corner detect
        Mat imageToShow = findCorners(floatImage);

        // Show in GUI
        imageToShow.convertTo(byteImage, CvType.CV_8U);
        BufferedImage bufImage = new BufferedImage(byteImage.width(), byteImage.height(), BufferedImage.TYPE_BYTE_GRAY);
        byte[] imgArray = ((DataBufferByte)bufImage.getRaster().getDataBuffer()).getData();
        byteImage.get(0, 0, imgArray);

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.getContentPane().add(new JLabel(new ImageIcon(bufImage)));
        frame.pack();
        frame.setVisible(true);
    }

    private static Mat findCorners(Mat image) {
        Imgproc.cornerHarris(image, energy, 20, 9, 0.1);

        // Corner-search:

        int minDistance = 16;
        Core.MinMaxLocResult minMaxLoc = Core.minMaxLoc(
                energy.submat(20, energy.rows() - 20, 20, energy.rows() - 20));
        float thr = (float)minMaxLoc.maxVal / 4;

        Mat tmp = energy.reshape(1, 1);
        Core.sortIdx(tmp, idx, 16); // 16 = CV_SORT_EVERY_ROW | CV_SORT_DESCENDING

        int[] idxArray = new int[idx.cols()];
        idx.get(0, 0, idxArray);
        float[] energyArray = new float[idx.cols()];
        energy.get(0, 0, energyArray);

        int n = 0;
        for (int p : idxArray) {
            if (energyArray[p] == -1) continue;
            if (energyArray[p] < thr) break;
            n++;

            int x = p % image.cols();
            int y = p / image.cols();

            // Exclude a disk around this corner from potential future candidates
            int u0 = Math.max(x - minDistance, 0) - x;
            int u1 = Math.min(x + minDistance, image.cols() - 1) - x;
            int v0 = Math.max(y - minDistance, 0) - y;
            int v1 = Math.min(y + minDistance, image.rows() - 1) - y;
            for (int v = v0; v <= v1; v++)
                for (int u = u0; u <= u1; u++)
                    if (u * u + v * v <= minDistance * minDistance)
                        energyArray[p + u + v * image.cols()] = -1;

            // A corner is found!
            Core.circle(image, new Point(x, y), minDistance / 2, new Scalar(255, 255, 255), 1);
            Core.circle(energy, new Point(x, y), minDistance / 2, new Scalar(minMaxLoc.maxVal, minMaxLoc.maxVal, minMaxLoc.maxVal), 1);
        }
        System.out.println("nCorners: " + n);

        // Rescale energy image for display purpose only

        Core.multiply(energy, new Scalar(255.0 / minMaxLoc.maxVal), energy);

//      return image;
        return energy;
    }
}

0 个答案:

没有答案