2

Trying to create a functional SVM. I have 114 training images, 60 Positive/54 Negative, and 386 testing images for the SVM to predict against.

I read in the training image features to float like this:

trainingDataFloat[i][0] = trainFeatures.rows;
trainingDataFloat[i][1] = trainFeatures.cols;

And the same for the testing images too:

testDataFloat[i][0] = testFeatures.rows;
testDataFloat[i][2] = testFeatures.cols;

Then, using Micka's answer to this question, I turn the testDataFloat into a 1 Dimensional Array, and feed it to a Mat like this so to predict on the SVM:

float* testData1D = (float*)testDataFloat;
Mat testDataMat1D(height*width, 1, CV_32FC1, testData1D);
float testPredict = SVMmodel.predict(testDataMat1D);

Once this was all in place, there is the Debug Error of:

Sizes of input arguments do not match (the sample size is different from what has been used for training) in cvPreparePredictData

Looking at this post I found (Thanks to berak) that:

"all images (used in training & prediction) have to be the same size"

So I included a re-size function that would re-size the images to be all square at whatever size you wished (100x100, 200x200, 1000, 1000 etc.)

Run it again with the images re-sized to a new directory that the program now loads the images in from, and I get the exact same error as before of:

Sizes of input arguments do not match (the sample size is different from what has been used for training) in cvPreparePredictData

I just have no idea anymore on what to do. Why is it still throwing that error?

EDIT

I changed

Mat testDataMat1D(TestDFheight*TestDFwidth, 1, CV_32FC1, testData1D);

to

Mat testDataMat1D(1, TestDFheight*TestDFwidth, CV_32FC1, testData1D);

and placed the .predict inside the loop that the features are given to the float so that each image is given to the .predict individually because of this question. With the to int swapped so that .cols = 1 and .rows = TestDFheight*TestDFwidth the program seems to actually run, but then stops on image 160 (.exe has stopped working)... So that's a new concern.

EDIT 2

Added a simple

std::cout << testPredict;

To view the determined output of the SVM, and it seems to be positively matching everything until Image 160, where it stops running:

Community
  • 1
  • 1
MLMLTL
  • 1,519
  • 5
  • 21
  • 35
  • please post your `svm.train(...);` line and tell details about the parameters you feed to it. – Micka Jan 16 '15 at 13:19
  • I'm using the default SVM Params and for the train: `SVMmodel.train(trainingDataMat, labelsMat, Mat(), Mat(), SVMParams());` – MLMLTL Jan 16 '15 at 13:22
  • what are the dimensions of `trainingDataMat` and what are the dimensions of your training and prediction images? – Micka Jan 16 '15 at 13:24
  • Training Mat: `Mat trainingDataMat(height, width, CV_32FC1, trainingDataFloat);` - `height` = 114 `width` = 2. Images are resized to 500x500 for both Training and Testing – MLMLTL Jan 16 '15 at 13:28
  • according to http://stackoverflow.com/questions/14694810/using-opencv-and-svm-with-images it should be something like: `Mat trainingDataMat(114, 500*500, CV_32FC1, trainingDataFloat);` instead... where 114 is the number of input images and 500*500 is the size of the 1D array you want to feed to prediction later. – Micka Jan 16 '15 at 13:31
  • `Mat trainingDataMat(114, 500*500, CV_32FC1, trainingDataFloat);` breaks the program; `.exe has stopped working`. The reason I have the 2nd `int` in `trainingDataMat` as `width` is because of [**this post**](http://stackoverflow.com/questions/9830033/labeling-data-in-svm-opencv-c). – MLMLTL Jan 16 '15 at 13:45
  • you probably have to adjust the part that fills `trainingDataMat`. The accepted answer in the link you provided says `cv::Mat data(numSamples, featureSize, CV_32FC1);` for the training data, which would be `500*500` if you use image pixels as features and your images have width 500 and height 500. – Micka Jan 16 '15 at 14:00
  • In that question, after obtaining the feature data from both, there is that reminder of `// Make sure anger.cols == disgust.cols`. As he is using `SIFT`, his `.cols` would be `128`, and the `.rows` would be the `Detected Features`, no? So his `cv::Mat data` consists of the collective amount of `.rows` from the images, as well as the `.cols` too as the 2nd `int`. His would come out as `[Y x 128]` for the `cv::Mat data`. This is what I have done. – MLMLTL Jan 16 '15 at 14:09
  • ok, I'm out here. Since I never used it myself, but I think `.cols` is `128*number_of_features` (make sure that same number of features is used) and `.rows` is `# of sample images'. Or he can use each single keypoint as a single training feature, resulting in y1+y2+y3+...+yn features of size 128. But this will give him the possibility to predict for a `single keypoint` instead of an image. – Micka Jan 16 '15 at 14:26
  • via the usage of a simple `std::cout << trainFeatures.cols;`, I can determine that `.cols` is `64`. (I'm using `SURF`; if I was using `SIFT`, this would output `128`). So I don't think you're correct with your suggestion of `128*number_of_features`. Do appreciate your time though! – MLMLTL Jan 16 '15 at 14:59
  • In reference to the second part of your reply, although it is a valid suggestion that _"he can use each single keypoint as a single training feature"_, you then pretty much stated as to why this wouldn't be the case in your following line. – MLMLTL Jan 16 '15 at 15:06
  • `.train()` uses `traindata` with `#samples` rows and `#features` cols (which means each of your samples has 64 features). So if you want to use 64 cols (= 1 SURF descriptor per sample) then you only have 64 features per sample and it would allow you to `.predict` a 1D array with 64 elements. If you want to use a an image as a sample, you would use imgWidth*imgHeight cols and #images rows. And you would use a imgWidth*imgHeight 1D-array for `.predict` input – Micka Jan 16 '15 at 15:17
  • I think you messed up on your formatting. You meant to put `imgWidth*imgHeight` twice? Also, I don't understand your wording of this part: If you want to use a an image as a sample, you would use `imgWidth*imgHeight` cols and #images rows. And you would use a `imgWidth*imgHeight` 1D-array for .predict input – MLMLTL Jan 16 '15 at 15:21

1 Answers1

2

Please check your training and test feature vector.

I'm assuming your feature data is some form of cv::Mat containing features on each row. In which case you want your training matrix to be a concatenation of each feature matrix from each image. These line doesn't look right:

trainingDataFloat[i][0] = trainFeatures.rows;
trainingDataFloat[i][1] = trainFeatures.cols;

This is setting an element of a 2d matrix to the number of rows and columns in trainFeatures. This has nothing to do with the actual data that is in the trainFeatures matrix.

What are you trying to detect? If each image is a positive and negative example, then are you trying to detect something in an image? What are your features?

If you're trying to detect an object in the image on a per image basis, then you need a feature vector describing the whole image in one vector. In which case you'd do something like this with your training data:

int N; // Set to number of images you plan on using for training
int feature_size; // Set to the number of features extracted in each image.  Should be constant across all images.

cv::Mat X = cv::Mat::zeros(N, feature_size, CV_32F); // Feature matrix
cv::Mat Y = cv::Mat::zeros(N, 1, CV_32F); // Label vector
// Now use a for loop to copy data into X and Y, Y = +1 for positive examples and -1 for negative examples
for(int i = 0; i < trainImages.size(); ++i)
{
  X.row(i) = trainImages[i].features; // Where features is a cv::Mat row vector of size N of the extracted features
  Y.row(i) = trainImages[i].isPositive ? 1:-1; 
}
// Now train your cv::SVM on X and Y.
Daniel Moodie
  • 357
  • 1
  • 10
  • When you say _"Should be constant across all images."_, do you mean that the number of features extracted should be the same for every image? And to set `feature_size` I would feed it `trainFeatures.rows`? And would you do all this in one loop, and then train after? – MLMLTL Jan 19 '15 at 10:21
  • Also, `trainImages` would be a `vector` yes? And I don't understand your wording of _"Where features is a cv::Mat row vector of size N of the extracted features"_. – MLMLTL Jan 19 '15 at 11:06
  • Yes to be able to train an SVM you need a constant number of features. I'm assuming trainImages is a vector of a struct of all your feature images. The struct would just contain a cv::Mat for the features of that image and a boolean parameter isPositive that is true if it is a positive class. – Daniel Moodie Jan 19 '15 at 14:53
  • But if you feed the `SVM` a `Mat` of all the features together, why does every image need to have the exact same number of features detected? I was under the impression that you can't train an `SVM ` one at a time, rather you give it a `Mat` where each `row` holds the features for each individual image. – MLMLTL Jan 19 '15 at 15:39
  • You do need to concatenate all of your features together into the X matrix I described above. This matrix contains one sample on each row. Now the question is more so, what is it that you are looking for? If you are extracting a variable number of features from each image, and you know each feature corresponds to your target, then feasibly you could train the SVM on each feature. But for example if you're extracting sift and training an SVM on sift, then you're training an SVM to detect a whole object based on a single extracted point. So please describe your goal more clearly. – Daniel Moodie Jan 19 '15 at 23:03
  • Using `SURF` to extract feature points on images that I wish to give to a `Mat` which I then wish to feed to an `SVM`. and pretty much the same when predicting too. – MLMLTL Jan 20 '15 at 10:04
  • An SVM can make a prediction on a single sample, IE a row of your training feature matrix. So you could train the SVM on each feature point. In which case your SVM would make a prediction based on the probability that that feature point corresponds to the designated label. If you have a label for the whole image, then how are you certain that each feature point on the image describes that label? – Daniel Moodie Jan 20 '15 at 14:15
  • So I need to: 1) detect or extract features? 2) give these to a vector or Mat? 3) feed that to the SVM? And I don't know... how do you do that? – MLMLTL Feb 05 '15 at 16:42