OpenCV3.4.1自定义训练线性SVM适配HOG detectMultiScale问题
I’ve dealt with this exact frustration when moving from OpenCV 2 to 3—those old LinearSVM class tricks don’t work anymore because OpenCV 3 completely refactored its machine learning module. Let’s walk through how to get your custom-trained SVM working with HOG’s detectMultiScale.
Why the Old Method Fails
OpenCV 3 replaced the standalone LinearSVM class with a unified cv::ml::SVM interface. The direct access to raw SVM vectors you relied on in OpenCV 2 is gone; instead, you have to explicitly extract the decision function parameters (weights and bias) and format them correctly for the HOG descriptor.
Step-by-Step Solution
1. Load Your Trained SVM (OpenCV 3 Style)
First, forget the old LinearSVM class—use the cv::ml::SVM loader instead. Make sure you include the correct headers:
#include <opencv2/ml/ml.hpp> #include <opencv2/hog.hpp> // Load the trained SVM cv::Ptr<cv::ml::SVM> svm = cv::ml::SVM::load("/home/pi/trainedSVM.xml");
2. Extract SVM Parameters for HOG
HOG’s detector expects a specific vector format: the first element is the negative bias term (-rho), followed by the negative of the SVM’s weight vector (-w). Here’s how to compute that:
// Get support vectors and decision function details cv::Mat supportVectors = svm->getSupportVectors(); cv::Mat alpha, svIndices; double rho = svm->getDecisionFunction(0, alpha, svIndices); // Calculate the weight vector w (sum of alpha_i * support_vector_i) cv::Mat w = cv::Mat::zeros(supportVectors.cols, 1, CV_64F); for (int i = 0; i < supportVectors.rows; ++i) { w += alpha.at<double>(i) * supportVectors.row(i).t(); } // Construct the HOG detector vector: [-rho, -w[0], -w[1], ..., -w[n]] cv::Mat hogDetector(1, supportVectors.cols + 1, CV_64F); hogDetector.at<double>(0) = -rho; cv::Mat wRow = w.t(); wRow.copyTo(hogDetector.colRange(1, supportVectors.cols + 1)); // Convert to float (HOG works well with float precision) hogDetector.convertTo(hogDetector, CV_32F);
3. Attach the Detector to HOG and Run Detection
Make sure your HOG descriptor uses the exact same parameters (window size, block size, cell size, bin count, etc.) that you used during SVM training. Then set the detector and run detectMultiScale:
// Initialize HOG with your training parameters (adjust these to match your setup!) cv::HOGDescriptor hog( cv::Size(64, 128), // Window size (match training) cv::Size(16, 16), // Block size cv::Size(8, 8), // Block stride cv::Size(8, 8), // Cell size 9 // Number of bins ); // Set the custom detector hog.setSVMDetector(hogDetector); // Run detection on your image std::vector<cv::Rect> detections; hog.detectMultiScale( yourInputImage, // Your input image detections, 0.0, // Hit threshold (adjust for sensitivity) cv::Size(8, 8), // Win stride cv::Size(32, 32), // Padding 1.05, // Scale factor 2 // Group threshold );
Critical Notes to Avoid Headaches
- Use Linear Kernel Only: HOG only supports Linear SVM detectors—if you trained your SVM with a non-linear kernel, this won’t work.
- Match HOG Parameters: Even a tiny mismatch (e.g., using 10 bins instead of 9) between training and detection will break results. Double-check every parameter.
- Check SVM Type: Ensure your SVM was trained as a
C_SVCorLINEAR_SVC(the most common for object detection).
内容的提问来源于stack exchange,提问作者PhilBot

