OpenCV Gaussian Mixture Model of histogram - opencv

Given a histogram I want to train a Gaussian Mixture Model:
int calcGMMThreshold(cv::Mat & hist, cv::Mat & labels){
cv::Mat samples(hist.rows,2, CV_32FC1); // for building 2 dim samples
// output variables
cv::Mat probs, log_likelihoods;
// building 2 dimensional Mat -->[value][#value]
for(int i = 0; i<hist.rows; i++)
{
samples.at<float>(i,0) = (float)i;
samples.at<float>(i,1) = hist.at<float>(i);
}
assert(samples.cols == 2);
assert(samples.rows == 256);
///set up gmm
//gmm object with 3 gmms
cv::EM gmm(3);
/*train gmms*/
gmm.train(samples, log_likelihoods, labels, probs);
}
When I plot the histogram with the labels for me it looks like that my gmms separate the absolute values and not the 2 dimensional input.
I would have expected 3 Gaussians with their means at each peak of the histogram.

To compute a gaussian mixture model use the actual image data not the histogram as intended in the code above.

Related

Euclidean distance between RGB histogram of two images

I have two pictures with histogram of the R,G,B intensities for each image. I am suppose to find the euclidean distance using the values of histogram to find the similarity.
I know euclidean distance formula is:
= sqr((R1-R2)^2 +(G1-G2)^2+(B1-B2)^2)
Since the histogram of R G and B for each image has several values, so are you suppose to take the average of all the intensity values in one histogram and then subtract it with the average of intensity values of the other histogram?
Example 1:
Image1: R1 histogram has values of 2,3,4
Image2: R2 histogram has values of 2,3,1
Then do I do R1=(2+3+4)/3 ,R2=(2+3+1)/3
Then do I do (9-6)^2 for the value (R1-R2)^2 in sqr((R1-R2)^2+(G1-G2)^2+(B1-B2)^2)?
OR
Example 2:
Image1: R1 histogram has values of 2,3,4
Image2: R2 histogram has values of 2,3,1
Then do I do this (2-2)^2 +(3-3)^2 +(4-1)^2 for the (R1-R2)^2 in sqr((R1-R2)^2 +(G1-G2)^2+(B1-B2)^2)?
Please help me out, thanks!
Think of a histogram as a vector (maybe there are 256 bins, so it’s a 256-dimensional vector). Now compute the Euclidean distance between the two vectors:
DR = norm(R1-R2); % same as sqrt(sum((R1-R2).^2))
You can repeat this for each R, G and B component, and combine the three distances again using the Euclidean norm:
D = sqrt(DR.^2 + DG.^2 + DB.^2);
This is the same as concatenating the 3 color histograms for each image and computing their distance:
H1 = [R1,G1,B1]; % assuming histograms are row vectors
H2 = [R2,G2,B2];
D = norm(H1-H2);
I think you are mixing Normalization with Euclidean Distance.
Euclidean Distance = Sqrt( Sum( ( a[i][j] - b[i][j] )^2 ) ) for all i = 0..width, j = 0..height
a[][] and b[][] can be normalized data or non-normalized data. If you are using the raw image pixel values, they are non-normalized. You can normalize the images by dividing by the intensity range of the pixel values (min-max normalization).
So, compute the normalized images anorm[][] and bnorm[][] in the first pass where,
for(i = 0; i < width; i++) {
for(j = 0; j < height; j++) {
anorm[i][j] = a[i][j] / (max_a - min_a);
bnorm[i][j] = b[i][j] / (max_b - min_b);
}
}
Now, apply the Euclidean Distance formula on anorm[][] and bnorm[][].

Column-Wise Standard Deviation in OpenCV

Is there a direct way to compute the column-wise standard deviation for a matrix in opencv? Similar to std in Matlab. I've found one for the mean:
cv::Mat col_mean;
reduce(A, col_mean, 1, CV_REDUCE_AVG);
but I cannot find such a function for the standard deviation.
Here's a quick answer to what you're looking for. I added both the standard deviation and mean for each column. The code can easily be modified for rows.
cv::Mat A = ...; // FILL IN THE DATA FOR YOUR INPUT MATRIX
cv::Mat meanValue, stdValue;
cv::Mat colSTD(1, A.cols, CV_64FC1);
cv::Mat colMEAN(1, A.cols, CV_64FC1);
for (int i = 0; i < A.cols; i++){
cv::meanStdDev(A.col(i), meanValue, stdValue);
colSTD.at<double>(i) = stdValue.at<double>(0);
colMEAN.at<double>(i) = meanValue.at<double>(0);
}
The following is not in a single line,but it is another version without loops:
reduce(A, meanOfEachCol, 0, CV_REDUCE_AVG); // produces single row of columnar means
Mat repColMean;
cv::repeat(meanOfEachCol, rows, 1, repColMean); // repeat mean vector 'rows' times
Mat diffMean = A - repColMean; // get difference
Mat diffMean2 = diffMean.mul(diffMean); // per element square
Mat varMeanF;
cv::reduce(diffMean2, varMeanF, 0, CV_REDUCE_AVG); // sum each column's elements to get single row
Mat stdMeanF;
cv::sqrt(varMeanF, stdMeanF); // get standard deviation

openCV error:"Sizes of input arguments do not match" while trying to detect objects using HoG features and SVM

I am working on object detection using HoG Features and SVM. I am calculating HoG features for 64X128 images using the code in this (Integral Histogram for fast Calculation of HOG Features) and this (Calculation of Hog Features) for both positive(pos.xml) and Negative(neg.xml) images. I am training the SVM with the pos.xml and neg.xml . When I try to detect using the xml file saved using SVM training , it gives me following error. (image size used for detection is 64X128)
OpenCV Error: Sizes of input arguments do not match (The sample size
is differen t from what has been used for training) in
cvPreparePredictData, file .......
.\opencv\modules\ml\src\inner_functions.cpp, line 1114
My code for detecting images.
Mat img= imread("path\\a91.jpg"); // 64X128 pixels
CvSVM svm;
svm.load("svm1.xml");
Mat example;
cvtColor(img,example,CV_RGB2GRAY);
example = example.reshape(0,1);
//cout <<type2str(example.type()) <<endl;
example.convertTo(example, CV_32FC1);
//cout <<type2str(example.type()) <<endl;
cout<<svm.predict(example)<<endl;
SVM training code :
void trainSVM(CvMat* pos_mat, CvMat* neg_mat, char *savexml, char *pos_file = NULL, char *neg_file = NULL)
{
/* Read the feature vectors for positive samples */
if (pos_file != NULL)
{
printf("positive loading...\n");
pos_mat = (CvMat*) cvLoad(pos_file);
printf("positive loaded\n");
}
/* Read the feature vectors for negative samples */
if (neg_file != NULL)
{
neg_mat = (CvMat*) cvLoad(neg_file);
printf("negative loaded\n");
}
int n_positive, n_negative;
n_positive = pos_mat->rows;
n_negative = neg_mat->rows;
int feature_vector_length = pos_mat->cols;
int total_samples;
total_samples = n_positive + n_negative;
CvMat* trainData = cvCreateMat(total_samples,feature_vector_length, CV_32FC1);
CvMat* trainClasses = cvCreateMat(total_samples,1, CV_32FC1 );
CvMat trainData1, trainData2, trainClasses1,
trainClasses2;
printf("Number of positive Samples : %d\n",pos_mat->rows);
/*Copy the positive feature vectors to training
data*/
cvGetRows(trainData, &trainData1, 0, n_positive);
cvCopy(pos_mat, &trainData1);
cvReleaseMat(&pos_mat);
/*Copy the negative feature vectors to training
data*/
cvGetRows(trainData, &trainData2, n_positive,total_samples);
cvCopy(neg_mat, &trainData2);
cvReleaseMat(&neg_mat);
printf("Number of negative Samples : %d\n",trainData2.rows);
/*Form the training classes for positive and
negative samples. Positive samples belong to class
1 and negative samples belong to class 2 */
cvGetRows(trainClasses, &trainClasses1, 0, n_positive);
cvSet(&trainClasses1, cvScalar(1));
cvGetRows(trainClasses, &trainClasses2, n_positive, total_samples);
cvSet(&trainClasses2, cvScalar(2));
/* Train a linear support vector machine to learn from
the training data. The parameters may played and
experimented with to see their effects*/
CvSVM svm(trainData, trainClasses, 0, 0, CvSVMParams(CvSVM::C_SVC, CvSVM::LINEAR, 0, 0, 0, 2, 0, 0, 0, cvTermCriteria(CV_TERMCRIT_EPS,0, 0.01)));
printf("SVM Training Complete!!\n");
/*Save the learnt model*/
if (savexml != NULL) {
svm.save(savexml);
}
cvReleaseMat(&trainClasses);
cvReleaseMat(&trainData);
}
Please help me with this. I am stuck here. Thank you.

OpenCV SVM train_auto Insufficient Memory

This is my first post here so I hope to be able to ask my question properly :-)
I want to do "elephant detection" by classifying color samples (I was inspired by this paper). This is the pipeline of my "solution" until the training of the classifier:
Loading a set of 4 training images (all containing an elephant), and then splitting them in two images: one containing the environment surrounding the elephant (the "background"), and one containing the elephant (the "foreground");
Mean shift segmentation of the backgrounds and the foregrounds;
RGB -> Luv color space conversion and pixel values extraction (in order to fill a Mat object with 3 columns and a number of rows equal to the number of samples);
SVM training with an RBF Kernel by calling train_auto method.
So, the problem arises in this last step: after a while (a few hours), I get the following error message:
OpenCV Error: Insufficient memory (Failed to allocate 22165936 bytes) in OutOfMemoryError, file xxx\alloc.cpp, line 52
terminate called after throwing an instance of 'cv::Exception'
what(): xxx\alloc.cpp:52:error: (-4) Failed to allocate 22165936 bytes in function OutOfMemoryError
My training samples are a [3 columns x 1,385,235 rows] CV_32FC1 Mat object. I don't believe that this data structure is too large, isn't it? I've 16 GB of RAM, and I'm using OpenCV 2.4.9 and Codeblocks.
However, this is the source code:
//Loading Background & Foreground Training Images
Mat train_00_background = imread("training_set/train_00_background.png");
cvtColor(train_00_background, train_00_background, CV_BGR2BGRA);
oclMat t_00_bg;
t_00_bg.upload(train_00_background);
(...)
Mat train_00_foreground = imread("training_set/train_00_foreground.png");
cvtColor(train_00_foreground, train_00_foreground, CV_BGR2BGRA);
oclMat t_00_fg;
t_00_fg.upload(train_00_foreground);
(...)
//COLOR SEGMENTATION by MEAN SHIFT CLUSTERING
meanShiftSegmentation(t_00_bg, train_00_background_clustered, 5, 5, 50, TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 5, 1));
(...)
//CV_8UC3 -> CV_32FC3
train_00_background_clustered.convertTo(train_00_background_clustered, CV_32FC3);
(...)
//Normalization
train_00_background_clustered *= 1./255;
(...)
//RGB -> Luv
cvtColor(train_00_background_clustered, train_00_background_clustered, CV_BGR2Luv);
(...)
//COLOR LIST EXTRACTION FROM BACKGROUND AND FOREGROUND
//colorListBg_00 is a 3 x NumberOfColors CV_32FC1 Mat
extractColorList(train_00_background_clustered, colorListBg_00);
// Memory release
train_00_background_clustered.release();
(...)
//Color List concatenation
//background
colorListBg_00.copyTo(colorList);
colorList.push_back(colorListBg_01);
(...)
Size s = colorList.size();
int s1 = s.height;
//foreground
colorList.push_back(colorListFg_00);
(...)
s = colorList.size();
int s2 = s.height - s1;
// ASSIGNING THE LABELS
Mat labelsBg(s1, 1, CV_32FC1, -1.0);
Mat labelsFg(s2, 1, CV_32FC1, 1.0);
Mat labels;
labelsBg.copyTo(labels);
labels.push_back(labelsFg);
// SVM TRAINING
CvSVMParams params;
params.svm_type = CvSVM::C_SVC;
params.kernel_type = CvSVM::RBF;
params.term_crit = cvTermCriteria( CV_TERMCRIT_ITER+CV_TERMCRIT_EPS, 1000, FLT_EPSILON );
CvSVM SVM;
SVM.train_auto(colorList, labels, Mat(), Mat(), params, 2);
Thank you for paying attention towards this question.

OpenCV PCA question

I'm trying to create a PCA model in OpenCV to hold pixel coordinates. As an experiment I have two sets of pixel coordinates that maps out two approximate circles. Each set of coordiantes has 48 x,y pairs. I was experimenting with the following code which reads the coordinates from a file and stores them in a Mat structure. However, I don't think it is right and PCA in openCV seems very poorly covered on the Internet.
Mat m(2, 48, CV_32FC2); // matrix with 2 rows of 48 cols of floats held in two channels
pFile = fopen("data.txt", "r");
for (int i=0; i<48; i++){
int x, y;
fscanf(pFile, "%d%c%c%d%c", &x, &c, &c, &y, &c);
m.at<Vec2f>( 0 , i )[0] = (float)x; // store x in row 0, col i in channel 0
m.at<Vec2f>( 0 , i )[1] = (float)y; // store y in row 0, col i in channel 1
}
for (int i=0; i<48; i++){
int x, y;
fscanf(pFile, "%d%c%c%d%c", &x, &c, &c, &y, &c);
m.at<Vec2f>( 1 , i )[0] = (float)x; // store x in row 1, col i in channel 0
m.at<Vec2f>( 1 , i )[1] = (float)y; // store y in row 1, col i in channel 1
}
PCA pca(m, Mat(), CV_PCA_DATA_AS_ROW, 2); // 2 principle components??? Not sure what to put here e.g. is it 2 for two data sets or 48 for number of elements?
for (int i=0; i<48; i++){
float x = pca.mean.at<Vec2f>(i,0)[0]; //get average x
float y = pca.mean.at<Vec2f>(i,0)[1]; //get average y
printf("\n x=%f, y=%f", x, y);
}
However, this crashes when creating the pca object. I know this is a very basic question but I am a bit lost and was hoping that someone could get me started with pca in open cv.
Perhaps it would be helpful if you described in further detail what you need to use PCA for and what you hope to achieve (output?).
I am fairly sure that the reason your program crashes is because the input Mat is CV_32FC2, when it should be CV_32FC1. You need to reshape your data into 1 dimensional row vectors before using PCA, not knowing what you need I can't say how to reshape your data. (The common application with images is eigenFace which requires an image to be reshaped into a row vector). Additionally you will need to normalize your input data between 0 and 1.
As a further aside, usually you would choose to keep 1 less principal component than the number of input samples because the last principal component is simply orthogonal to the others.
I have worked with opencv PCA before and would like to help further. I would also refer you to this blog: http://www.bytefish.de/blog/pca_in_opencv which helped me get started with PCA in openCV.

Resources