SVM + HOG,找到的对象总是NULL

时间:2015-07-29 16:51:44

标签: c++ opencv image-processing svm detection

我正在研究真菌孢子检测。我有大约359张正面图像(真菌颗粒的裁剪图像)和171张负像(灰尘颗粒的裁剪图像)。

pos / nag图像的实际大小与大约8x8的粒子大小相同但是对于SVM训练我已将其调整为30x30,然后使用调整大小的图像来训练SVM分类器。我正在使用没有任何功能的图像直接训练SVM。

成功训练分类器后,我使用了hog.setSVMDetector(myclassifier)和hog.detectMultiScale,但找到的对象为零。

现在我的问题是我在代码中做错了什么? 请点击以下链接,查看我用于SVM分类器,测试图像和所需粒子图像的Nagative / Positive图像。

https://drive.google.com/folderview?id=0B7yRjtOGywg7fnNJTXcxR2NYb3ItWTZ0UjYwUmt6YW96R0NHLWZQbVJucEk0bnJmcFJGS0E&usp=sharing

class LinearSVM: public CvSVM {
public:

  void getSupportVector(std::vector<float>& support_vector) const;
};  

void LinearSVM::getSupportVector(std::vector<float>& support_vector) const {

    int sv_count = this->get_support_vector_count();
 //   mexPrintf("size :   %d\n",support_vector.size());
    const CvSVMDecisionFunc* df = this->decision_func;
    const double* alphas = df[0].alpha;
    double rho = df[0].rho;
    int var_count = this->get_var_count();
    support_vector.resize(var_count, 0);
    for (unsigned int r = 0; r < (unsigned)sv_count; r++) {
      float myalpha = alphas[r];
      const float* v = this->get_support_vector(r);
      for (int j = 0; j < var_count; j++,v++) {
        support_vector[j] += (-myalpha) * (*v);
      }
    }
    support_vector.push_back(rho);
}

////////////////////////////// main.cpp ///////////////////////////
    int num_files = 359*171;
int img_area = 30*30;
Mat training_mat(num_files,img_area,CV_32FC1);
vector<int> training_Labels;
Mat labels(num_files,1,CV_32FC1);
int imagenum=0;
 for (int pimageNum = 0; pimageNum < 359; pimageNum++)
{
     // reading Positive Images from directory and resize it to 30x30
int ii = 0; // Current column in training_mat
for (int i = 0; i<posImage.rows; i++) {
    for (int j = 0; j < posImage.cols; j++) {
        training_mat.at<float>(imagenum,ii++) = posImage.at<uchar>(i,j);
imagenum++;
    }
}
training_Labels.push_back(1.0);
}

for (int nimageNum = 0; nimageNum < 171; nimageNum++)
{
     // reading Nagative Images from directory and resize it to 30x30
int ii = 0; // Current column in training_mat
for (int i = 0; i<nagImage.rows; i++) {
    for (int j = 0; j < nagImage.cols; j++) {
        training_mat.at<float>(imagenum,ii++) = nagImage.at<uchar>(i,j);
imagenum++;
    }
}
training_Labels.push_back(-1.0);
}

Mat(training_Labels).copyTo(labels);
labels.convertTo(labels, CV_32FC1);

 CvSVMParams SVM_params;
    SVM_params.svm_type = CvSVM::C_SVC;
    SVM_params.kernel_type = CvSVM::LINEAR; //CvSVM::LINEAR;
    SVM_params.degree = 0;
    SVM_params.gamma = 3;
    SVM_params.coef0 = 0;
    SVM_params.C = 1;
    SVM_params.nu = 0;
    SVM_params.p = 0;
    SVM_params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 10, 0.03);
    //Train SVM


    LinearSVM svmClassifier;
    svmClassifier.train(training_mat, labels, Mat(), Mat(), SVM_params);
    svmClassifier.save("D:\\svmClassifier.yml");

HOGDescriptor hog;
hog.winSize = Size(8, 8);
std::vector<float> support_vector;

FileStorage fs;
    fs.open("D:\\svmClassifier.yml", FileStorage::READ);

    fs["support_vectors"] >> support_vector;

hog.setSVMDetector(support_vector);

vector< Rect> found,found_filtered;
Size padding(Size(0, 0));
Size winStride(Size(8, 8));

cv::Mat test=cv::imread("testimage.bmp",CV_LOAD_IMAGE_GRAYSCALE);
// actual size of test image is 1024x768 which I resize to 400x 300
hog.detectMultiScale(test, found, 0.0, winStride, padding, 1.01, 0);

cout<<""found particles"<< found.size() ;  // it is always zero

size_t i, j;
    for (i=0; i<found.size(); i++)
    {
        Rect r = found[i];
        for (j=0; j<found.size(); j++)
            if (j!=i && (r & found[j])==r)
                break;
        if (j==found.size())
            found_filtered.push_back(r);
    }

    for (i=0; i<found_filtered.size(); i++)
    {
        Rect r = found_filtered[i];
        r.x += cvRound(r.width*0.1);
        r.width = cvRound(r.width*0.8);
        r.y += cvRound(r.height*0.06);
        r.height = cvRound(r.height*0.9);
        rectangle(test, r.tl(), r.br(), cv::Scalar(0,255,0), 2);
    }

    imshow("detected particles", test);
    waitKey(0);

1 个答案:

答案 0 :(得分:1)

我没有设法让你的分类器工作,但我找到了你当前问题的原因。

我已经提出了一个要点here,所以你可以查看一下。我使用自己的文件阅读方法来读取图像,因此您必须进行一到两次更改才能使其适用。

您没有找到对象的原因是因为您的分类器向量为空。 是由于yml文件中节点的错误读取造成的。 'support_vectors'是'my_svm'的子节点。您试图将其作为顶级节点读取,并返回一个空向量。

我修复的文件阅读循环中还有一些其他错误(标记为FIXED) - 至少,它们对我来说似乎不正确。

这仍然无法正确分类(还)。支持向量数组的格式存在一些问题,它打破了hog描述符。

所以你需要为此付出更多的努力,但希望这会让你朝着正确的方向前进。

我在输出窗口添加了一个滑块。当你使分类器工作时,你可以用滑块改变scaleFactor,这应该会在结果中产生有趣的变化。