Flow matrix from Earth Mover's Distance - opencv

I was reading some paper and it said:
By adopting the Earth Mover's Distance (EMD) algorithm, a flow matrix
f = {fij} from one histogram to another can be obtained.
I found an implementation for EMD in OpenCV. However, this implementation looks like:
float EMDL1(InputArray signature1, InputArray signature2);
It returns a single float value rather than a flow matrix. Is there a way to obtain the flow matrix using OpenCV?

While I was Writing the post I found the answer. It might help someone...
There is another function which is:
float EMD(InputArray signature1, InputArray signature2, int distType, InputArray cost=noArray(), float* lowerBound=0, OutputArray flow=noArray() );
flow is an output parameter that return the flow matrix.

Related

How to perform a linear homography of an image in tensorflow

I would like to be able to replicate the behaviour of the opencv function warpPerspective which takes as input an image and an homography matrix, and projects the image according to the homography matrix (more details here : https://docs.opencv.org/2.4/modules/imgproc/doc/geometric_transformations.html).
It seems like tf.contrib.image.sparse_image_warp should do the job, but I am unable to replicate the behaviour of warpPerspective. The output I get is distorted in a non-linear fashion despite the use of the parameter interpolation_order=1.
With some further research, I suspect this is due to the fact that tf.contrib.image.interpolate_spline does not perform linear interpolation even when its order is 1 but rather uses some RBF kernels.
I can't see a way around this except encoding it with a dense_image_warp, but it seems a bit overkill and maybe costly. Does anyone has another solution ?
After some research, here is a solution. it uses the tf.contrib.image.dense_image_warp function and is not really pretty, but still, it works :
This first function computes the optical flow needed to perform the homography :
def homography_matrix_to_flow(tf_homography_matrix, im_shape1, im_shape2):
Y, X = np.meshgrid(range(im_shape1), range(im_shape2))
Z = np.ones_like(X)
XYZ = np.stack((X, Y, Z), axis=-1)
tf_XYZ = tf.constant(XYZ.astype("float64"))
tf_XYZ = tf_XYZ[tf.newaxis,:,:, :, tf.newaxis]
tf_homography_matrix = tf.tile(tf_homography_matrix[tf.newaxis, tf.newaxis], (1, im_shape2, im_shape1, 1, 1))
tf_unnormalized_transformed_XYZ = tf.matmul(tf_homography_matrix, tf_XYZ, transpose_b=False)
tf_transformed_XYZ = tf_unnormalized_transformed_XYZ / tf_unnormalized_transformed_XYZ[:,:,:, -1][:,:,:, tf.newaxis]
flow = -tf.squeeze(tf_transformed_XYZ-tf_XYZ)[..., :2]
return flow
Then, it used to warp the original image to the distorted image.
There is one trick : due to how the tf.contrib.image.dense_image_warp function works, you need to pass the inverse of the homography matrix to find the correct optical flow to use.
homography_matrix = np.array([[-4.86219067e-01, -2.20871298e+00, 4.08214879e+02],
[-1.02940133e-01, -5.60378659e+00, 3.87573763e+02],
[-1.35051362e-04, -6.59600583e-03, 2.91244998e-01]])
inv_homography_matrix = np.linalg.inv(homography_matrix)
tf_inv_homography_matrix = tf.constant(inv_homography_matrix)[tf.newaxis]
flow = homography_matrix_to_flow(tf_inv_homography_matrix, img.shape[1], img.shape[2])[tf.newaxis]
flow =tf.tile(flow, (self.bs, 1,1,1))
image_warped = tf.contrib.image.dense_image_warp(tf.transpose(img, (0,2,1,3)), flow)
image_warped = tf.transpose(image_warped, (0,2,1,3))
I still hope to find a better answer (one which does not have to compute a whole tensor of flow), therefore, I leave the question unanswered for now.

Gabor filter - parameters values and feature extraction in openCv

I want to extract features in my image - cropped iris. But I have problems with parameters. I also don't know how exacly it works. I've already red a lot of topics about this issue in the web, but I can't answer my questions.
Input image:
I use OpenCV library, and I writte this code:
double kSize = 11.0;
double sigma = 2, theta = Math.PI/4, lambda = 4.0, gamma = 0.6;
Mat kernel = Imgproc.getGaborKernel(new Size(kSize, kSize), sigma, theta, lambda, gamma);
Mat dest = new Mat(source.rows(), source.cols(), source.type());
Imgproc.filter2D(src, dest, CvType.CV_64F, kernel);
And I get the following image:
If my parameters are right? I want to get some more wavelets and display it in my application. How should I changing params to get good results?
I also want to extract and save a Gabor features. Could someone place some piece of code as an answer for this question?
I will be verry glad if someone want to help me. I get stuck with this, and I try to code this 3 day..

opencv flann module: knn-search for hierarchical kmeans tree giving weird result

I have about 130,000 SIFT descriptors. I am building a hierarchical Kmeans-index using Opencv's flann module. After this I want to quantize these 130,000 descriptors (will quantize more later). I am using flann's knnsearch method for doing this. But the result of this method is something weird. For every descriptor the nearest index it is showing is the index of the descriptor itself. However, it should be displaying the cluster-ID of the nearest cluster which will be one of the leaves of the HIK-tree.
Should I try k=2
Here is a code snippet -
int k=1;
cv::flann::KMeansIndexParams indexParams(8,4,cvflann::FLANN_CENTERS_KMEANSPP) ;
cv::flann::Index hik_tree(cluster_data, indexParams);
Mat indices,dist;
hik_tree.knnSearch(cluster_data, indices, dist, k, cv::flann::SearchParams(64));
knnSearch is looking for the k-nearest neighbours in the index (it does not give the cluster-ID!). You build your index using cluster_data, and then you try to match cluster_data against itself. In this situation, it is not surprising that the closest neighbour to each descriptor is itself...
EDIT: If you want to get the centers, have a look at this (from the source of the FLANN library):
/**
* Chooses the initial centers using the algorithm proposed in the KMeans++ paper:
* Arthur, David; Vassilvitskii, Sergei - k-means++: The Advantages of Careful Seeding
*/
template <typename Distance>
class KMeansppCenterChooser : public CenterChooser<Distance>
{
...
k-NN is a supervised classification algorithm, that's why you are supposed to construct an Index object with your training samples, so use
cv::flann::Index hik_tree(samples, indexParams);
instead of
cv::flann::Index hik_tree(cluster_data, indexParams);

Clustering and kmeans have unclear documentation

I have to use kmeans in my future work, I know it is available in OpenCV as they have a documentation page on it.
I cannot make sense of the format displayed, it has also not been explained in the given details below (it appears to be details related to OpenCV 1.1). I mean, with the C++ line:
double kmeans(InputArray data, int K, InputOutputArray bestLabels, TermCriteria criteria, int attempts, int flags, OutputArray centers=noArray() )
what datatype is data, vector or matrix? which is the input matrix, which will be the output?
I am used to reading documentation like this where it is clearly stated which is the input/output/flag etc and what data types they are.
C++: void FeatureDetector::detect(const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask=Mat() ) const
I would really appreciate if someone could give a short example of kmeans being used.
P.S. the input matrix I have ready to be used for kmeans is the one produces by DescriptorExtractor::compute
Thank you
You can find examples of using most of OpenCV's functions in folder samples. In your situation take a look at these two:
kmeans.cpp
matcher_simple.cpp

Feeding extracted HoG features into CvSVM's train function

This is a silly question since I'm quite new to SVM,
I've managed to extract features and locations using OpenCV's HoGDescriptor:
vector< float > features;
vector< Point > locations;
hog_descriptors.compute( image, features, Size(0, 0), Size(0, 0), locations );
Then I proceed to use CvSVM to train the SVM based on the features I've extracted.
Mat training_data( features );
CvSVM svm;
svm.train( training_data, labels, Mat(), Mat(), params );
Which gave me an error:
OpenCV Error: Bad argument (There is only a single class) in cvPreprocessCategoricalResponses, file /opt/local/var/macports/build/
My question is that, how do I convert the vector < features > into appropriate matrix to be fed into CvSVM ? Obviously I am doing something wrong, the OpenCV's tutorial shows that a 2D matrix containing the training data is fed into SVM. So, how do I convert vector < features > into a 2D matrix, what are the values in the 2nd dimension ?
What are these features exactly ? Are they the 9 bins consisting of normalized magnitude histograms ?
I found out the issue, since I was testing whether it is correct to pass feature vectors into the SVM in order to train it, I didn't bother to prepare both negative and positive samples.
Yet, CvSVM requires at least 2 different classes for training, that's why the error it threw.
Thanks a lot anyway !

Resources