OpenCV 在 Python 和 HOG 对象检测的 C++ 实现中的不同结果

Different results from OpenCV in Python and C++ implementations for HOG object detection

我已经使用 OpenCV 在 Python 和 C++ 中实现了 HOG 人脸检测器。我试图使两个实现中的代码完全相同。但是,我在这两个方面都得到了不同的结果。在 Python 中它工作正常,但是在 C++ 中它显示完全错误的结果。下面是它们的输出示例(第一个在 Python 中,第二个在 C++ 中):

首先,我为这两个实现训练了一个 OpenCV 线性 SVM 分类器,并将它们保存在 XML 文件(模型文件)中。然后,我使用 this code for Python implementation and this code 从模型(XML 文件)中提取系数(用于在测试过程中自定义 HOG 检测器)用于 C++ 实现。也就是说,这些系数将在测试过程中作为函数 setSVMDetector(const std::vector< float > input_coefficients) 的输入。

理想情况下,这些系数应该相同,因为它们是从同一数据集计算并使用 OpenCV 计算的。我通过将它们保存在两种实现的文本文件中来手动检查这些系数值,发现它们几乎相同。因此,我希望我未来定制的 HOG 检测器在两种实现中的工作方式几乎相同。

下面是使用这两种实现检测测试图像中人脸的测试代码。

Python 实施:

import cv2
im = cv2.imread("..\test_imgs\1.png", 0) # test image
hog = cv2.HOGDescriptor((96, 128), (16,16), (8,8), (8,8), 9)

coeffs = pickle.load(open("coeffs_from_model")) # load coeffs already computed from model
hog.setSVMDetector( np.array(coeffs)) # customize HOG detector

found, w = hog.detectMultiScale(im,  winStride=(8,8), padding=(32,32), scale=4.05)
draw_detections(im, found_filtered) # method for drawing BBs on image

C++ 实现:

cv::Mat im = cv::imread("..\test_imgs\1.png", 0);
cv::HOGDescriptor hog(cv::Size(96, 128), cv::Size(16, 16), cv::Size(8, 8), cv::Size(8, 8), 9);

LinearSVM svm; // check the link 
svm.load(model.c_str());

std::vector<float> coeffs;
svm.getSupportVector(coeffs); // compute coeffs from model

hog.setSVMDetector(coeffs); // customize HOG detector

std::vector<cv::Rect> found; // holds the detected BBs
hog.detectMultiScale(im, found, 0, cv::Size(8, 8), cv::Size(32, 32), 4.05); 
drawLocations(im, found, cv::Scalar(0, 255, 0)); // method for drawing BBs on the image. 

为了检查为C++计算的系数是否不正确。我在 Python 实现中使用了它们,有趣的是,它们的工作原理完全相同。所以,现在我不明白为什么尽管具有正确的系数,但 C++ 实现中的 HOG 对象仍无法正常工作。

我在 C++ 中使用了与 Python 相同的 HOG 对象初始化,并且在两个实现中保持代码几乎相同,因为它们都使用相同的 OpenCV。

我现在得到答案了。上面写的两个代码都是正确的。问题在于用于训练的标签。我在两个实现中都使用“0”(面部 class)和“1”(非面部 class)作为标签。

对于 Python 实现,这个标签工作正常,但是,对于 C++ 实现,它似乎必须是“+1”(面对 class)和“-1”(非面部 class),因为我发现它 here。在该示例中,在源代码的末尾,labels 提供为:

// Set up training data
float labels[4] = {1.0, -1.0, -1.0, -1.0};
Mat labelsMat(4, 1, CV_32FC1, labels);