OpenCV SVM prediction inconsistent? - opencv

This question has been asked here, but still no answer/solution. My problem is this: I trained an SVM (with RBF kernel) for smoke detection, using the RGB histogram distribution (in 8 bins - so M = 24) of the smoke:
cv::Mat labelsMat = cv::Mat(N, 1, CV_32SC1);
for (int i = 0; i < N; i++)
{
labelsMat.at<int>(i, 0) = labels[i];
}
cv::Mat trainingDataMat = cv::Mat(N, M, CV_32FC1);
for (int i = 0; i < N; i++)
{
for (int j = 0; j < M; j++)
{
trainingDataMat.at<float>(i, j) = histogramData[i][j];
}
}
// Create the SVM
cv::Ptr<ml::SVM> svm = ml::SVM::create();
svm->setType(ml::SVM::C_SVC);
svm->setKernel(ml::SVM::RBF);
svm->setTermCriteria(cv::TermCriteria(cv::TermCriteria::MAX_ITER, 1000, 1e-8));
// Train the SVM
svm->trainAuto(trainingDataMat, ml::ROW_SAMPLE, labelsMat);
svm->save(SVMFileName);
Then I saved the SVM model in a file. For the detection, after loading the SVM model:
svm = cv::ml::SVM::load(SVMFile);
I proceeded with the smoke detection; in this case to decide for each detected blob in a frame whether it's smoke or not:
for (int i = 0; i < 8; i++)
histogramData.at<float>(0, i) = Rhist[i];
for (int i = 8; i < 16; i++)
histogramData.at<float>(0, i) = Ghist[i];
for (int i = 16; i < 24; i++)
histogramData.at<float>(0, i) = Bhist[i];
float response = svm->predict(histogramData);
The frames where detection (true/false positive) occurs are saved, with the frame no. When I run this on the same video several times, each time different results (frame no.) will be produced (the blob detection always produces the same blobs). Regarding the detection, sometimes (most of the time) the smoke will be detected, but there are some cases where the same smoke will not be detected (the same video).
Anybody has any idea how to resolve this? Or is this still a known problem in OpenCV SVM?

Just realized my stupid error in the code: the indexing of Ghist & Bhist to form the data for prediction is totally incorrect, hence the inconsistencies!

Related

opencv decision tree regression, predict unseen responses?

I am using opencv3 for Visual Studio 2017, coding in C++, on a surface pro (windows 10 64-bit).
I want to train a decision tree so that it can predict with regression. I need it to be able to predict in between responses which were not in the represented training set. For example, this code:
cv::Mat samples(6, 1, CV_32FC1);
samples.at<float>(0, 0) = 1.5;
samples.at<float>(1, 0) = 2.7;
samples.at<float>(2, 0) = 3.8;
samples.at<float>(3, 0) = 4.3;
samples.at<float>(4, 0) = 5.4;
samples.at<float>(5, 0) = 5.2;
cv::Mat responses = samples.clone();
cv::Mat samples2(5, 1, CV_32FC1);
samples2.at<float>(0, 0) = 1.8;
samples2.at<float>(1, 0) = 2.5;
samples2.at<float>(2, 0) = 3.6;
samples2.at<float>(3, 0) = 4.4;
samples2.at<float>(4, 0) = 5.3;
cv::Ptr< cv::ml::DTrees > model = cv::ml::DTrees::create();
model->setMinSampleCount(1);
model->setCVFolds(1);
model->setMaxDepth(10);
model->setRegressionAccuracy(.01f);
model->train(samples, cv::ml::ROW_SAMPLE, responses);
cv::Mat results;
model->predict(samples2, results);
for (int i = 0; i < results.rows; i++) {
for (int j = 0; j < results.cols; j++)
cout << results.at<float>(i, j) << ", ";
cout << endl;
}
The output is:
1.5
2.7
3.8
4.3
5.2
This is a simple identity problem, whatever the sample is that's what the response should be. However, from this example, it can only predict the responses it has seen. From my understanding, this is because each response leaf is a constant value. After a decision tree finishes, it lands on one of those leaves with a constant value.
My question is, does anyone know of a way to manipulate a decision tree (preferably using OpenCV) so that it can predict responses outside of what it has seen? e.g. using interpolation and/or extrapolation.

partition a set of images into k clusters with opencv

I have an image data set that I would like to partition into k clusters. I am trying to use the opencv implementation of k-means clustering.
Firstly, I store my Mat images into a vector of Mat and then I am trying to use the kmeans function. However, I am getting an assertion error.
Should the images be stored into a different kind of structure? I have read the k-means documentation and I dont seem to understand what I am doing wrong. This is my code:
Thank you in advance,
vector <Mat> images;
string folder = "D:\\football\\positive_clustering\\";
string mask = "*.bmp";
vector<string> files = getFileList(folder + mask);
for (int i = 0; i < files.size(); i++)
{
Mat img = imread(folder + files[i]);
images.push_back(img);
}
cout << "Vector of positive samples created" << endl;
int k = 10;
cv::Mat bestLabels;
cv::kmeans(images, k, bestLabels, TermCriteria(), 3, KMEANS_PP_CENTERS);
//have a look
vector<cv::Mat> clusterViz(bestLabels.rows);
for (int i = 0; i<bestLabels.rows; i++)
{
clusterViz[bestLabels.at<int>(i)].push_back(cv::Mat(images[bestLabels.at<int>(i)]));
}
namedWindow("clusters", WINDOW_NORMAL);
for (int i = 0; i<clusterViz.size(); i++)
{
cv::imshow("clusters", clusterViz[i]);
cv::waitKey();
}

organized Point Cloud to Depth Image

I have got a fotonic e70 Time-of-Flight camera and like to transfer the point cloud to a depth image. The Point cloud is organized. I thought by simply write each col and row to an cv::Mat with
for (int i = 0; i < 120; i++)
for (int j = 0; j < 160; j++) {
image.at<short>(i,j) = aImage[j + i * 160 * 4]; //intensity
I would resived a rectyfied intensity 2d image. Why is it curved? as you can see here:
Depth Image
and how do I get a rectify image from a point cloud?

How can I get the Kernel of a SVM classifier in OpenCV?

I developed a multi-class SVM with OpenCV 3.0 and I want to compute the distance between each class and data (input) in order to estimate the confidence of the prediction.
I used the below code at link1 but I have errors when I try to get the Kernel of my SVM!
Thanks for your help.
Mat sv = svm->getSupportVectors();
Ptr<SVM::Kernel> kernel = svm->getKernel(); // ??
Mat buffer(1, sv.rows, CV_32F);
kernel->calc(sv.rows, sv.cols, sv.ptr<float>(), data.ptr<float>(), buffer.ptr<float>()); // apply kernel on data (CV_32F vector) and support vectors
Mat alpha, svidx;
int N = 11;
vector<int> votes(N, 0); // results of majority vote will be stored here (N is number of classes)
int i, j, dfi;
for (i = dfi = 0; i < N; i++)
{
for (j = i + 1; j < N; j++, dfi++)
{
// compute score for each binary svm
double rho = svm->getDecisionFunction(dfi, alpha, svidx);
double sum = -rho;
for (int k = 0; k < sv.rows; k++)
sum += alpha.at<float>(k)*buffer.at<float>(sv.at<int>(k));
// majority vote
votes[sum > 0 ? i : j]++;
}
}

Kiss fft does not work after giving it more than 32 samples

I am trying to take data from an accelerometer and apply Kiss FFT to the samples. I'm using a Freescale Kinetis FRDM-K22F board. I want to use 64 samples, but when I run the program I get an error saying "kiss fft usage error: improper alloc" I started turning down the sample size and saw that the FFT does work with 32 samples, but giving it 33 samples the program just stops and returns no errors. Giving it any more samples gives similar results.
I played around with how I set up the FFT and followed a few websites and forum posts:
KissFFT output of kiss_fftr
http://digiphd.com/programming-reconstruction-fast-fourier-transform-real-signal-kiss-fft-libraries/
Kiss FFT on a dsPIC33
From what I can see, I haven't done anything different from what the above websites and forums have done. I've included my code below. Any help or advice is greatly appreciated.
void Sample_RUN()
{
int size = 64;
kiss_fft_scalar zero;
memset(&zero,0,sizeof(zero));
kiss_fft_cpx fft_in[size];
kiss_fft_cpx fft_out[size];
kiss_fftr_cfg fft = kiss_fftr_alloc(size*2 ,0 ,NULL,NULL);
signed short samples[size];
for (int i = 0; i < size; i++) {
fft_in[i].r = zero;
fft_in[i].i = zero;
fft_out[i].r = zero;
fft_out[i].i = zero;
}
printf("Data Collection Begins \r\n");
for(int j = 0; j < size; j++)
{
for(;;)
{
dr_status = My_I2C_ReadByte(STATUS_REG);
dr_status = (dr_status & 0x04);
if (dr_status == 0x04)
{
//READING FROM ACCEL OUTPUT DATA REGISTERS
AccelData[0] = My_I2C_ReadByte(OUT_X_MSB_REG);
AccelData[1] = My_I2C_ReadByte(OUT_X_LSB_REG);
AccelData[2] = My_I2C_ReadByte(OUT_Y_MSB_REG);
AccelData[3] = My_I2C_ReadByte(OUT_Y_LSB_REG);
AccelData[4] = My_I2C_ReadByte(OUT_Z_MSB_REG);
AccelData[5] = My_I2C_ReadByte(OUT_Z_LSB_REG);
// 14-bit accelerometer data
Xout_Accel_14_bit = ((signed short) (AccelData[0]<<8 | AccelData[1])) >> 2; // Compute 16-bit X-axis acceleration output value
Yout_Accel_14_bit = ((signed short) (AccelData[2]<<8 | AccelData[3])) >> 2; // Compute 16-bit Y-axis acceleration output value
Zout_Accel_14_bit = ((signed short) (AccelData[4]<<8 | AccelData[5])) >> 2; // Compute 16-bit Z-axis acceleration output value
mag_accel = sqrt(pow(Xout_Accel_14_bit, 2) + pow(Yout_Accel_14_bit, 2) + pow(Zout_Accel_14_bit, 2) );
printf("%d \r\n", mag_accel);
samples[j] = mag_accel;
break;
} // end if
} // end infinite for
} // end for
for (int j = 0; j < size; j++)
{
fft_in[j].r = samples[j];
fft_in[j].i = zero;
fft_out[j].r = zero;
fft_out[j].i = zero;
}
printf("Executing FFT\r\n");
kiss_fftr(fft, (kiss_fft_scalar*) fft_in, fft_out);
printf("Printing FFT Outputs\r\n");
for(int j = 0; j < size; j++)
{
printf("%d \r\n", fft_out[j].r);
}
kiss_fft_cleanup();
free(fft);
} // end Sample_RUN
Sounds like you are running out of memory. I am not familiar with that chip, but perhaps you should be using the last arguments of kiss_fft_alloc so you can skip heap allocation.

Resources