switching from knn to svm (opencv 3.1) [closed]
Hello !
I would like to switch from knn to svm in order to see how performance goes:
This is the "script" I use to generate a file call "raw-features.yml".
int main(int argc, char **argv)
{
// data to return
Mat features(nbrOfCells, normalizedSizeForCell * normalizedSizeForCell, CV_8UC1);
Mat labels(1, nbrOfCells, CV_8UC1);
Mat svm_labels(nbrOfCells, 1, CV_32S);
// Ptr<ml::KNearest> knn(ml::KNearest::create());
std::map<int, std::map<int, int>> knownCellValues(cellValues());
int value;
string fileName;
Mat raw, sudoku;
ExtractionInformation extractInfo;
string raw_features_path("./../assets/raw-features.yml");
cv::FileStorage raw_features(raw_features_path, cv::FileStorage::WRITE); // open the classifications file
int incrCell = 0; // --> 1184
Mat roi, normalized;
for (int i = 0; i <= lastTrainingPuzzle; i++)
{
// cout << i << endl;
stringstream ss;
ss << "./../assets/puzzles/s";
ss << i;
ss << ".jpg";
string fileName(ss.str());
raw = imread(fileName, CV_LOAD_IMAGE_GRAYSCALE);
vector<Point> biggestApprox = findBiggestBlob(raw);
extractInfo = extractPuzzle(raw, biggestApprox);
Mat sudoku = recursiveExtraction(extractInfo.image);
for (int k = 0; k < 81; k++)
{
roi = extractRoiFromCell(sudoku, k);
if (!roi.empty())
{
value = knownCellValues[i][k];
Mat feat = roi.reshape(1, 1);
feat.copyTo(features.row(incrCell));
labels.at<unsigned char>(0, incrCell) = value;
svm_labels.at<int>(incrCell, 0) = value;
incrCell++;
}
}
}
features.convertTo(features, CV_32F);
labels.convertTo(labels, CV_32F);
raw_features << "features" << features;
raw_features << "labels" << labels;
raw_features << "svm_labels" << svm_labels;
raw_features.release();
return 0;
}
Once "raw-features.yml" is ready, I can use it like that !
I use this the "getKnn" function from my project to train the knn algo.
Ptr<ml::KNearest> getKnn(cv::FileStorage raw_features)
{
int trainingNbr = nbrOfCells * 0.9;
int testingNbr = nbrOfCells - trainingNbr;
Mat features(nbrOfCells, normalizedSizeForCell * normalizedSizeForCell, CV_8UC1);
Mat labels(1, nbrOfCells, CV_8UC1);
Ptr<ml::KNearest> knn(ml::KNearest::create());
if (raw_features.isOpened() == false)
{
throw std::logic_error("error, unable to open training classifications file, exiting program\n\n");
}
raw_features["features"] >> features;
raw_features["labels"] >> labels;
raw_features.release();
Mat sub_features = features(cv::Range(0, trainingNbr), cv::Range::all());
Mat sub_labels = labels(cv::Range::all(), cv::Range(0, trainingNbr));
knn->train(sub_features, ml::ROW_SAMPLE, sub_labels);
return knn;
}
I'm really happy of it, it works perfectly but I have a problem of performance so I would like to test other algo.
I created the same function for SVM:
Ptr<ml::SVM> getSvm(FileStorage raw_features)
{
Mat features(nbrOfCells, normalizedSizeForCell * normalizedSizeForCell, CV_32F);
Mat svm_labels(nbrOfCells, 1, CV_32S);
raw_features["features"] >> features;
raw_features["svm_labels"] >> svm_labels;
raw_features.release();
Ptr<ml::SVM> svm = ml::SVM::create();
svm->setType(ml::SVM::C_SVC);
svm->setKernel(ml::SVM::POLY);
svm->setDegree(3); // I had to put it if not it fails
svm->setGamma(3);
Ptr<ml::TrainData> tData = ml::TrainData::create(features, ml::SampleTypes::ROW_SAMPLE, svm_labels);
svm->train(tData);
return svm;
}
I use it like that:
string grabNumbers(Mat extractedPuzzle, Ptr<ml::SVM> svm)
{
Mat roi, response, dist;
stringstream ss;
int K = 1;
for (int k = 0; k < 81; k++)
{
roi = extractRoiFromCell(extractedPuzzle, k);
if (!roi.empty())
{
roi.convertTo(roi, CV_32F);
float res = svm->predict(roi.reshape(1, 1));
ss << res;
}
else
{
ss << "0";
}
}
return ss.str();
}
But I have this weird error I say weird because I already done the conversion !
Gtk-Message: Failed ...
Mat labels(nbrOfCells, 1, CV_32S);
incrCell
is what ? (unclear, how you derive that, isk
just, what you want there ?)Hi! I simplify a bit my code and change the Mat labels to be "svm compliant" it still work for my knn algo. It still not work but I have a new error :
The error is weird because I think that my Mat labels has integer inside !
you also have to convert your features to float before calling train()
then, sad as it is, -- noone can actually test your code (too many unknowns). next time you have a problem, please try to come up with a self-containd testcase, that others can reproduce !
I made some modification I hope it is better now ! by the wat this is an open source project, you can check it out https://github.com/BenNG/sudoku-recognizer (here)
I had edited the code and now it works ! Thank you Berak !
My grabNumbers function use to take ~110ms now it's ~40ms this is huge !!!