SVM + HOG, найденный объект всегда NULL
Я работаю над обнаружением грибковых спор. У меня есть около 359 положительных изображений (обрезанные изображения частиц гриба) и 171 негативных изображений (обрезанные изображения частиц пыли).
Фактический размер поз / наговых изображений такой же, как размер частицы, который составляет около 8x8, но для обучения SVM я изменил его размер до 30x30, а затем использовал измененные изображения для обучения классификатора SVM. Я непосредственно тренирую SVM с изображениями без каких-либо особенностей.
После успешного обучения классификатора я использовал hog.setSVMDetector(myclassifier) и hog.detectMultiScale, но найденные объекты равны нулю.
Теперь мои вопросы, что я делаю неправильно в моем коде? Пожалуйста, нажмите на ссылку ниже для получения положительных / положительных изображений, которые я использовал для классификатора SVM, тестовых изображений и изображения нужных частиц.
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 ответ
Мне не удалось заставить ваш классификатор работать, но я нашел причину вашей текущей проблемы.
Я выложил здесь суть, чтобы вы могли проверить это. Я использовал свои собственные методы чтения файлов для чтения изображений, поэтому вам придется внести одно или два изменения, чтобы они работали для вас.
Причина, по которой вы не получаете найденные объекты, заключается в том, что ваш вектор классификатора пуст. Это связано с неправильным чтением узла из файла yml. 'support_vectors' является подузлом 'my_svm'. Вы пытались прочитать его как узел верхнего уровня и возвращали пустой вектор.
Есть также несколько других ошибок в циклах чтения файлов, которые я исправил (отмечен FIXED
) - по крайней мере, они показались мне неверными.
Это все еще не будет правильно классифицировать (пока). Существует некоторая проблема с форматом вашего массива векторов поддержки, который нарушает дескриптор hog.
Так что вам нужно будет немного больше поработать над этим, но, надеюсь, это приведет вас в правильном направлении.
Я добавил слайдер в окно вывода. Когда вы заставите классификатор работать, вы можете изменить scaleFactor с помощью ползунка, который должен привести к интересным изменениям в результатах.