我正在研究真菌孢子检测。我有大约359张正面图像(真菌颗粒的裁剪图像)和171张负像(灰尘颗粒的裁剪图像)。
pos / nag图像的实际大小与大约8x8的粒子大小相同但是对于SVM训练我已将其调整为30x30,然后使用调整大小的图像来训练SVM分类器。我正在使用没有任何功能的图像直接训练SVM。成功训练分类器后,我使用了hog.setSVMDetector(myclassifier)和hog.detectMultiScale,但找到的对象为零。
现在我的问题是我在代码中做错了什么? 请点击以下链接,查看我用于SVM分类器,测试图像和所需粒子图像的Nagative / Positive图像。
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);
答案 0 :(得分:1)
我没有设法让你的分类器工作,但我找到了你当前问题的原因。
我已经提出了一个要点here,所以你可以查看一下。我使用自己的文件阅读方法来读取图像,因此您必须进行一到两次更改才能使其适用。
您没有找到对象的原因是因为您的分类器向量为空。 那是由于yml文件中节点的错误读取造成的。 'support_vectors'是'my_svm'的子节点。您试图将其作为顶级节点读取,并返回一个空向量。
我修复的文件阅读循环中还有一些其他错误(标记为FIXED
) - 至少,它们对我来说似乎不正确。
这仍然无法正确分类(还)。支持向量数组的格式存在一些问题,它打破了hog描述符。
所以你需要为此付出更多的努力,但希望这会让你朝着正确的方向前进。
我在输出窗口添加了一个滑块。当你使分类器工作时,你可以用滑块改变scaleFactor,这应该会在结果中产生有趣的变化。