【问题标题】:OpenCV Assertion Error in detectMultiScaledetectMultiScale 中的 OpenCV 断言错误
【发布时间】:2016-08-02 02:59:20
【问题描述】:

我正在尝试在 OpenCV 中测试面部识别 API。我已经导入了提供的.jar,它正确加载了 DLL。 imageLibIit() 函数将加载 DLL。我还在一个目录中提供了 XML 文件:
src\main\resources\opencv

public boolean faceDetect(String inputFilename, String outputFilename){
    if(!loaded){
        if(!imageLibInit()){ // initializes and loads the dynamic libraries
            return false;
        }
    }
    //TODO @Austin fix image resource issues
    ClassLoader loader = Thread.currentThread().getContextClassLoader();
    String xmlResource = loader.getResource("opencv/haarcascade_frontalface_alt.xml").getPath();
    CascadeClassifier faceDetector = new CascadeClassifier(xmlResource);
    Mat inputImage = Imgcodecs.imread(inputFilename);
    ErrorUtils.println(xmlResource);
    if(inputImage.empty()){
        ErrorUtils.println("image is empty");
        return false;
    }
    MatOfRect facesDetected = new MatOfRect();
    faceDetector.detectMultiScale(inputImage, facesDetected);
    Rect[] detections = facesDetected.toArray();
    ErrorUtils.println("Faces detected in '" + inputFilename + "': " + detections.length);
    for(Rect detection : detections){
        Imgproc.rectangle(
                inputImage,
                new Point(detection.x, detection.y),
                new Point(detection.x + detection.width, detection.y + detection.height),
                new Scalar(0, 0, 255)
        );
    }
    Imgcodecs.imwrite(outputFilename, inputImage);
    return true;
}

我仍然收到错误:

OpenCV Error: Assertion failed (!empty()) in cv::CascadeClassifier::detectMultiScale, file C:\builds\master_PackSlaveAddon-win64-vc12-static\opencv\modules\objdetect\src\cascadedetect.cpp, line 1639

我研究过这个错误,每次解决方案似乎都与资源有关。这很可能是一个非常简单的问题,但我现在被困住了。

【问题讨论】:

  • 看起来你的分类器永远不会被初始化。 xmlResource 变量在加载资源之后和构建级联分类器之前的内容是什么?
  • @DanMašek ErrorUtils 类是一个简单的与调试相关的类,尽管您可能已经推断出这一点。无论如何,它会打印出 XML 文件的路径:"/D:/Programming/workspaces/github/project1/HomeServer/target/classes/opencv/haarcascade_frontalface_alt.xml"
  • 啊哈。我相信问题是路径开头的第一个正斜杠。 OpenCV 内部使用FileStorage 类来加载数据。此类使用fopen 打开文件。我只是在 Visual C++ 中做了一个小测试,它无法打开具有这样路径的文件。删除前导斜杠应该可以解决问题。
  • 查看answer,了解如何以独立于平台的方式解决此问题。
  • 工作就像一个魅力,我的朋友。除非您愿意,否则我会发布答案。

标签: java opencv


【解决方案1】:

查看OpenCV源代码,我们可以发现:

  • 在内部,CascadeClassifier 实现使用类 FileStorage 来加载数据。 [1]

  • FileStorage内部使用函数fopen(...)打开数据文件。 [2] [3]


由于资源加载器 ("/D:/Programming/workspaces/github/project1/HomeServer/target/classes/opencv/ha‌​arcascade_frontalface_alt.xml") 返回的路径有点奇怪,包含前导斜杠,第一个怀疑导致打开文件时出现问题。

我编写了一个简单的小测试来使用 Visual C++ 进行检查:

#include <cstdio>
#include <iostream>

bool try_open(char const* filename)
{
    FILE* f;

    f = fopen(filename, "rb");
    if (f) {
        fclose(f);
        return true;
    }
    return false;
}

int main()
{
    char const* path_1("/e:/foo.txt");
    char const* path_2("e:/foo.txt");

    std::cout << "fopen(\"" << path_1 << "\") -> " << try_open(path_1) << "\n";
    std::cout << "fopen(\"" << path_2 << "\") -> " << try_open(path_2) << "\n";

    return 0;
}

输出:

fopen("/e:/foo.txt") -> 0
fopen("e:/foo.txt") -> 1

因此路径是罪魁祸首。根据this answer,一种平台无关的方法是修改代码如下,生成有效路径:

// ...
ClassLoader loader = Thread.currentThread().getContextClassLoader();
String xmlResource = loader.getResource("opencv/haarcascade_frontalface_alt.xml").getPath();
File file = new File(xmlResource);
xmlResource = file.getAbsolutePath());
// ...
CascadeClassifier faceDetector = new CascadeClassifier(xmlResource);
if(faceDetector.empty()){
    ErrorUtils.println("cascade classifier is empty");
    return false;
}
// ...

【讨论】:

  • 这很好用。另外,我很感激你在 C++ 中这样做,因为我对 Java 比较陌生 :) String xmlResourcePath = new File(loader.getResource("opencv/haarcascade_frontalface_alt.xml").getPath()).getAbsolutePath();
  • 没问题,我已经十多年没有真正写过任何Java了,所以这主要是查找Java文档,然后挖掘OpenCV源代码(因为那里发生了错误)并缩小范围将其简化为可以重现此情况的最小测试用例。
猜你喜欢
  • 2021-02-26
  • 1970-01-01
  • 2016-02-23
  • 2018-05-19
  • 1970-01-01
  • 1970-01-01
  • 2021-06-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多