feature extraction and dimension reduction with pca in opencv - opencv

//make every image as a row vector
Mat data = formatImagesForPca(v);
//apply PCA
PCA pca(data, cv::Mat(), CV_PCA_DATA_AS_ROW, k);
//project in some kxk dimension
Mat p = pca.project(data);
//calculate eigenvalues
Mat eigenval = pca.eigenvectors.clone();
i have applied pca but
i am facing problem in extracting the eigenvalues after applying pca.
i want to extract features using pca. but how can i reduce dimension and extract features and what is wrong with this code ?

https://github.com/Itseez/opencv/blob/master/samples/cpp/pca.cpp
http://www.bytefish.de/blog/pca_in_opencv/
I hope these code can help you.

Related

What is a joint histogram and a marginal histogram in image processing?

What is a joint histogram and a marginal histogram in image processing and how do they work and how to construct one, with simple examples if possible.
For example, if I have a feature space of 10 dimensions and want to build a histogram with each dimension quantize into 20 values. How to calculate the total bins for the joint histogram and for the marginal histogram?
I assume you know what histograms are in general. Joint histograms of data in an N-dimensional feature space are N dimensional. You just put the data points into N-dimensional bins (typically Cartesian products of N 1-dimensional grids). Marginal histograms are less than N-dimensional histograms where one or more dimension has been ignored. Joint and marginal histograms are very similar to joint/marginal distributions.
How to compute them depends on your specific situation. You could compute marginal histograms from joint histograms by integrating over some dimensions or you could build them the same way as joint histograms but with fewer dimensions. In Matlab, histcounts2 for example computes a joint histogram of 2D data. For higher dimensional data, accumarray might be of help. In Python with NumPy, histogramdd generates multi-dimensional histograms. Typically the N-dimensional bins are Cartesian products of bins in each dimension and the resulting histograms are simple Numpy arrays (in Python) or matrices (in Matlab).
Simple example in N=2D (in Matlab)
Let's create some data first
x = 3*randn(1e4, 1);
y = randn(1e4, 1);
scatter(x, y, '.');
xlim([-10,10]);
ylim([-10,10]);
pbaspect([1,1,1]);
Let's compute the joint histogram
h = histcounts2(x, y, -10:10, -10:10);
Let's display the joint histogram and on each side the marginal histograms, which could have been obtained either by integrating the joint histogram over one dimension or by creating 1D histograms for the data axes separately. Here the marginal histograms are created by just computing 1D histograms (ignoring the other data dimension).
fig = figure;
subplot('Position', [0.35, 0.35, 0.6, 0.6]);
im = imagesc(-10:10, -10:10, h.');
im.Parent.YDir = 'normal';
axis image;
title('joint histogram (x,y)');
subplot('Position', [0.43, 0.1, 0.45, 0.15]);
histogram(x, -10:10);
camroll(180);
title('marginal histogram x');
subplot('Position', [0.2, 0.4, 0.15, 0.55]);
histogram(y, -10:10);
camroll(90);
title('marginal histogram y');
One can see nicely that the marginal histograms just correspond to add-ups of the joint histogram along a directions.

FaceRec tutorial explanation

I try to do this face recognition example, with Eigenfaces. And cannot understand what these functions subspaceProject() and subspaceReconstruct() actually do. I tried to search on http://docs.opencv.org/ but there was not any link to description.
Could you explain me what this part of the code actually do?
Mat evs = Mat(W, Range::all(), Range(0, num_components));
Mat projection = subspaceProject(evs, mean, images[0].reshape(1,1));
Mat reconstruction = subspaceReconstruct(evs, mean, projection);
// Normalize the result:
reconstruction = norm_0_255(reconstruction.reshape(1, images[0].rows));
I mean what these functions do, what kind of cv::Mat they return ?
subspaceProject() will basically give you a dimensionality reduction.
projection = (images[0] - mean) * evs
Subtracting the mean ensures that the images approximate a subspace.
Presumably evs is the truncated right singular vectors.
and for subspaceReconstruct()
reconstruction = projection * transpose(evs) + mean
The reconstruction is just the reverse of the projection, except since evs is truncated, it can not be perfect.
See PCA

OpenCV Matrix of different size

I am having some problem with Mat in OpenCV. I was using SIFT for image classification with SVM. Now I realized that the true-positive rate was low, so I decided to add ORB feature detectors on top of SIFT. My problem is that, for example for one image:
SIFT descriptors: Mat size [128 x 250]
ORB descriptors: Mat size [32 x 400]
Now as for training matrix all the features have to be in the training matrix and than trained. Now, as you see that the 2 matrix of SIFT and ORB are of different size. How can I combine them into one matrix?.
Do I have to append (add) the second matrix to the end of the first one because currently I am assigning it to separate columns.
Please give me some hints on this please.
There are two parts to extracting features based on your solution. The first part is to detect keypoints, and the second part is to describe them. At the moment, you are doing both stages with both SIFT and ORB, and coming up with matrices of different sizes. Instead, use the following framework:
// Construct detectors
cv::FeatureDetector siftDetector, orbDetector;
siftDetector.create("SIFT");
orbDetector.create("ORB");
// Detect keypoints
std::vector<cv::Keypoint> siftPoints, orbPoints;
siftDetector.detect(img, siftPoints);
orbDetector.detect(img, orbPoints);
// Concantenate the vectors
siftPoints.insert(siftPoints.end(), orbPoints.begin(), orbPoints.end());
// Construct descriptor (SIFT used as example)
cv::FeatureDescriptor siftDescriptor;
siftDescriptor.create("SIFT");
// Compute descriptors
cv::Mat descriptors;
siftDescriptor.compute(img, siftPoints, descriptors);
You now have SIFT descriptions for all detected keypoints.
PS: I haven't compiled this code, so double check for typos and syntax.

OpenCV: Efficient Difference-of-Gaussian

I am trying to implement difference of guassians (DoG), for a specific case of edge detection. As the name of the algorithm suggests, it is actually fairly straightforward:
Mat g1, g2, result;
Mat img = imread("test.png", CV_LOAD_IMAGE_COLOR);
GaussianBlur(img, g1, Size(1,1), 0);
GaussianBlur(img, g2, Size(3,3), 0);
result = g1 - g2;
However, I have the feeling that this can be done more efficiently. Can it perhaps be done in less passes over the data?
The question here has taught me about separable filters, but I'm too much of an image processing newbie to understand how to apply them in this case.
Can anyone give me some pointers on how one could optimise this?
Separable filters work in the same way as normal gaussian filters. The separable filters are faster than normal Gaussian when the image size is large. The filter kernel can be formed analytically and the filter can be separated into two 1 dimensional vectors, one horizontal and one vertical.
for example..
consider the filter to be
1 2 1
2 4 2
1 2 1
this filter can be separated into horizontal vector (H) 1 2 1 and vertical vector(V) 1 2 1. Now these sets of two filters are applied to the image. Vector H is applied to the horizontal pixels and V to the vertical pixels. The results are then added together to get the Gaussian Blur. I'm providing a function that does the separable Gaussian Blur. (Please dont ask me about the comments, I'm too lazy :P)
Mat sepConv(Mat input, int radius)
{
Mat sep;
Mat dst,dst2;
int ksize = 2 *radius +1;
double sigma = radius / 2.575;
Mat gau = getGaussianKernel(ksize, sigma,CV_32FC1);
Mat newgau = Mat(gau.rows,1,gau.type());
gau.col(0).copyTo(newgau.col(0));
filter2D(input, dst2, -1, newgau);
filter2D(dst2.t(), dst, -1, newgau);
return dst.t();
}
One more method to improve the calculation of Gaussian Blur is to use FFT. FFT based convolution is much faster than the separable kernel method, if the data size is pretty huge.
A quick google search provided me with the following function
Mat Conv2ByFFT(Mat A,Mat B)
{
Mat C;
// reallocate the output array if needed
C.create(abs(A.rows - B.rows)+1, abs(A.cols - B.cols)+1, A.type());
Size dftSize;
// compute the size of DFT transform
dftSize.width = getOptimalDFTSize(A.cols + B.cols - 1);
dftSize.height = getOptimalDFTSize(A.rows + B.rows - 1);
// allocate temporary buffers and initialize them with 0's
Mat tempA(dftSize, A.type(), Scalar::all(0));
Mat tempB(dftSize, B.type(), Scalar::all(0));
// copy A and B to the top-left corners of tempA and tempB, respectively
Mat roiA(tempA, Rect(0,0,A.cols,A.rows));
A.copyTo(roiA);
Mat roiB(tempB, Rect(0,0,B.cols,B.rows));
B.copyTo(roiB);
// now transform the padded A & B in-place;
// use "nonzeroRows" hint for faster processing
Mat Ax = computeDFT(tempA);
Mat Bx = computeDFT(tempB);
// multiply the spectrums;
// the function handles packed spectrum representations well
mulSpectrums(Ax, Bx, Ax,0,true);
// transform the product back from the frequency domain.
// Even though all the result rows will be non-zero,
// we need only the first C.rows of them, and thus we
// pass nonzeroRows == C.rows
//dft(Ax, Ax, DFT_INVERSE + DFT_SCALE, C.rows);
updateMag(Ax);
Mat Cx = updateResult(Ax);
//idft(tempA, tempA, DFT_SCALE, A.rows + B.rows - 1 );
// now copy the result back to C.
Cx(Rect(0, 0, C.cols, C.rows)).copyTo(C);
//C.convertTo(C, CV_8UC1);
// all the temporary buffers will be deallocated automatically
return C;
}
Hope this helps. :)
I know this post is old. But the question is interresting and may interrest future readers. As far as I know, a DoG filter is not separable. So there is two solutions left:
1) compute both convolutions by calling the function GaussianBlur() twice then subtract the two images
2) Make a kernel by computing the difference of two gaussian kernels then convolve it with the image.
About which solution is faster:
The solution 2 seems faster at first sight because it convolves the image only once.
But this does not involve a separable filter. On the contrary, the first solution involves two separable filter and may be faster finaly. (I do not know how the OpenCV function GaussianBlur() is optimised and whether it uses separable filters or not. But it is likely.)
However, if one uses FFT technique to convolve, the second solution is surely faster.
If anyone has any advice to add or wishes to correct me, please do.

SVM for Image feature classification using OpenCv

my project scope is currency note identification by comparing the sample images feature set.There, i have completed the feature extraction part of the sample images. Further i need to store the sample images features in the text file or XML file and the classification of them.
please help me to do the image classification part by using SVM classifier on the OpenCv
this is the feature extraction code that i have completed.
int main( intargc, char** argv )
{
/Loading the image as gray scale/
//declaring Mat object.This will holds an image(like iplimage in old opencv versions).
Mat gray_scale_img;
//imread is used to load an image. in here i have load the image as a grayscale image.
gray_scale_img=imread("100.jpg",CV_LOAD_IMAGE_GRAYSCALE);
/*surf detector settings*/
//setting the threshold value.high value will result low number of keypoints.
int hessian=100;
//initializing the surf keypoint detector
SurfFeatureDetectordetector(hessian);
/*detect surf key points*/
//creating vector to store detected keypoints
std::vector<KeyPoint>keypoints;
//detect keypoints
detector.detect(gray_scale_img,keypoints);
/*extract descriptor vectors/feature vectors from each and every keypoints */
SurfDescriptorExtractor extractor;
//this mat object will goinf to hold the extracted descriptors.
Mat descriptors;
//extracting descriptors/features
extractor.compute(gray_scale_img,keypoints,descriptors);
}
SVM in OpenCV is implemented in CvSVM class;
You need to have feature vector in form of a Matrix (row wise).
Assuming you are using height, width as your feature vector, your mat will be as follows (assuming you have 20 feature vectors):
Mat FV(20,2, CV_32F);
Mat flagmat(20,1,CV_8U);
/*
code to populate the matrix FV.
Fill the matrix with values so that it will look something as follows:
20 30
30 40
..
..
code to populate the matrix flagmat.
Fill the matrix with labels of each corresponding feature vector in matrix FV. It will look something as follows:
1
-1
1
1
-1
1
1
1
..
*/
CvSVM svm;
svm.train(datamat, flagmat,Mat(),Mat(),CvSVMParams());
Mat testFV(20,2,CV_32F);
Mat sample(1,2,CV_32F);
/* similarly as described above fill testFV matrix*/
float res;// to store result
for(int i =0;i<testFV.rows;i++)
{
sample.at<float>(0,0)=testFV.at<float>(i,0);
sample.at<float>(0,1)=testFV.at<float>(i,1);
float res = svm.predict(sample);
cout<<"predicted label: "<<res<<endl;
}
I'm assuming you can extract numerical values from the feature descriptors/vectors and put them in the sample matrix in above code. You can replace the feature vectors with any feature descriptor that you are using.

Resources