首页 > 解决方案 > OpenCV 4.1 Java - contourArea() 断言深度失败 == CV_32F || 深度 == CV_32S 用于外壳矩阵

问题描述

我试图从生成的船体点计算船体面积 convexHull()

我遵循了OpenCV Python 教程(因为没有 Java 教程)并摆弄了代码完成。

这是代码:

Imgproc.findContours(patternEdges, patternContours, new Mat(), Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
MatOfInt patternHull = new MatOfInt();
Imgproc.convexHull(patternContours.get(0), patternHull);
Imgproc.contourArea(pickPoints(patternContours.get(0), patternHull)); // fails here

但这会引发以下异常:

Exception in thread "main" CvException [org.opencv.core.CvException: cv::Exception: OpenCV(4.1.2) /home/build/git/opencv/modules/imgproc/src/shapedescr.cpp:274: error: (-215:Assertion failed) npoints >= 0 && (depth == CV_32F || depth == CV_32S) in function 'contourArea']
  at org.opencv.imgproc.Imgproc.contourArea_1(Native Method)
  at org.opencv.imgproc.Imgproc.contourArea(Imgproc.java:1607)
  at com.acme.opencv.Test.main(Test.java:94)

显然矩阵内部数据类型是错误的。但是为什么,以及如何转换它?

我正在使用 OpenCV 4.1.2。

标签: javaopencvopencv-contour

解决方案


问题是,在 Java 中,API 仅实现用原始点矩阵MatOfInt 的索引填充。

这就是Javadoc(直接从 C++ 文档生成)所说的:

hull输出凸包。它是索引的整数向量或点的向量。在第一种情况下,外壳元素是原始数组中凸包点的基于 0 的索引(因为凸包点集是原始点集的子集)。在第二种情况下,包元素是凸包点本身。

(强调我的)

没有“或”。只有MatOfInt,它是原始Point矩阵的索引。

您可以通过这样的辅助函数使用选取的点创建一个新矩阵:

private static MatOfPoint2f pickPoints(MatOfPoint points, MatOfInt indices) {
    Point[] pickedPoints = new Point[indices.rows()];
    int newRow = 0;
    for (int index : indices.toArray()) {
        pickedPoints[newRow++] = new Point(points.get(index, 0));
    }
    return new MatOfPoint2f(pickedPoints);
}

然后使用它:

Imgproc.findContours(patternEdges, patternContours, new Mat(), Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
MatOfInt patternHullIndices = new MatOfInt();
Imgproc.convexHull(patternContours.get(0), patternHullIndices);
Imgproc.contourArea(pickPoints(patternContours.get(0), patternHull));

推荐阅读