Subtracting two vector<point2f> directly - c++

I have to subtract two vectors of type Point2f (both are of same size). I know it can be done by extracting the values at each index and then subtracting them in a loop but is there a direct method to it? Something like
Vector<Point2f> A[3];
A[2] = A[1] - A[0];

just for sports ;)
std::vector<Point2f> A,B;
A.push_back(Point2f(1,2));
A.push_back(Point2f(3,4));
A.push_back(Point2f(5,6));
B.push_back(Point2f(5,2));
B.push_back(Point2f(4,4));
B.push_back(Point2f(3,6));
// Mat C; subtract(A,B,C);
Mat C = Mat(A) - Mat(B);
cout<< A << endl << B << endl <<C<<endl;
[1, 2; 3, 4; 5, 6]
[5, 2; 4, 4; 3, 6]
[-4, 0; -1, 0; 2, 0]

As per the documentation link that you provided, subtraction of two points is supported. So the following should work:
std::transform (A[1].begin(), A[1].end(), A[0].begin(), A[2].begin(), std::minus<Point2f>());
Note that this assumes that A[2] is big enough to store the result.
Alternative, you could write your own overloaded operator-() for vector subtraction:
const vector<Point2f> operator-(const vector<Point2f>& lhs, const vector<Point2f>& rhs)
{ ... }
You would need to optimize the above function to avoid a copy of the vector when the function returns. This does not preclude the need to write the looping code that you want to avoid. But it will give you a cleaner syntax for vector subtractions.

Related

How can implement pdist of matlab using eigen with C++?

In Matlab, the D = pdist(X, Y) function computes pairwise distances between the two sets of observations X and Y. E.g. Given X = randu(3, 2), Y = randu(3, 2), where each row stores an observation (x, y). Then pdist returns a [3 x 3] D matrix in which the (i, j) entry represents the distance between the i-th observation in X and the j-th observation in Y.
I want to imitate this behavior using Eigen with C++.
I naively use a for-loop to iterate every observation in X and compute the pairwise distances between the current observation in X and every observation in Y. The result is a [1 x Y.rows] row vector which is then populated into the i-th row of the D matrix.
I think this implementation is somewhat slow as two iterations of the for-loop are independent, and a vectorization technique may be helpful.
Can some shed me some info to make the implementation faster?
I tried using Eigen's binaryExpr but the result was not expected.
I have implemented this function according to your explanation (I assume you want number of observations to be dynamic and this should work for any number of observations N1,N2):
#include <Eigen/Dense>
#include <iostream>
const int oDims = 2;
typedef Eigen::Matrix<double, Eigen::Dynamic, oDims, Eigen::RowMajor> ObservationMatrix;
auto pdist(const ObservationMatrix& X, const ObservationMatrix& Y)
{
return (X.replicate(1, Y.rows()) - Y.reshaped<Eigen::RowMajor>(1, Y.rows() * oDims).replicate(X.rows(), 1))
.reshaped<Eigen::RowMajor>(X.rows() * Y.rows(), oDims)
.rowwise().norm()
.reshaped<Eigen::RowMajor>(X.rows(), Y.rows());
}
int main() {
ObservationMatrix X(3, oDims), Y(4, oDims);
X << 3, 2,
4, 1,
0, 5;
Y << 10, 14,
12, 17,
16, 11,
13, 18;
Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> result = pdist(X, Y);
std::cout << result << std::endl;
return 0;
}
I'm not sure if this implementation is faster but if you can share your implementation using for-loops we can check the timings. I have tried to verify it's functionality with MATLAB's pdist function. However, I couldn't find a template of pdist that accepts two matrices X, Y like you have described (https://www.mathworks.com/help/stats/pdist.html). Am I missing something?

Eigen::Vector; Initialize Vector with Values of Eigen::Matrix3f in a function, bigger than 4 entries

im interested in building up a 1x6 Vector, which i want to concatenate with another 1x6 Vector to a 2x6 Matrix. I know it will be a Row Vector, so therefore i thought about initializing a Eigen::RowVectorXf vec, but maybe a simple Eigen::VectorXf would be enough, idk.
(Further on, this should be concatenated to an even bigger 2Nx6 Matrix, for SVD-Operations)
My Input is a 3x3 Matrix of type Eigen::Matrix3f Mat
I thought of using a function, because i have in total ~20 (number isn't that important) input matrices, for each i do have to build 2 vectors, in this manner ( Yep, this will be a 40x6 Matrix in the end):
Question:
How do i initialize vec with entries of mat, especially if its not only the entries, but the products of entries, or sums of products of entries.
Example:
// Inputvalue Mat, which i have
Eigen::Matrix<float, 3, 3> mat = [ 1 2 3; 4 5 6; 7 8 9];
// Outputvalue vec, which i need
Eigen::RowVectorXf = ( mat(0,0)*mat(1,1), mat(1,2)*mat(2,1)+mat(1,0)*mat(0,1), .... );
My inputs of mat(col,row) are arbitrary, but i have a pattern for col,row, which i want to test, and therefore i want to build up those vectors. I've already done it in MATLAB, but im interested in doing it with Eigen in C++.
RowVectorXf build_Vec(Eigen::Matrix3f Mat)
{
Eigen::RowVectorCf vec = ( ..., ..., ..., ..., ..., ...;);
return vec;
}
Anyone some hints for me?
Thanks in advance
For dynamically filling a big matrix at runtime you can't use the CommaInitializer (without abusing it). Just allocate a matrix large enough and set individual blocks:
Matrix<float, Dynamic, 6> Vges(2*views, 6);
for(int i=0; i<views; ++i) {
Matrix<float, 2, 6> foo;
foo << 1,2,3,4,5,6,7,8,9,10,11,12; // or combine from two Matrix<float, 1, 6>
Vges.middleRows<2>(2*i) = foo;
}
You may also consider computing Vges.transpose() * Vges on-the-fly (i.e., by accumulating foo.transpose()*foo into a 6x6 matrix and do a SelfAdjointEigendecomposition instead of a SVD (perhaps use double instead of single precision then).
Eigen::Matrix<double, 6, 6> VtV; VtV.setZero();
for(int i=0; i<views; ++i) {
foo = ...;
VtV.selfadjointView<Upper>().rankUpdate(foo);
}

c++ how to represent a vector as a matrix and transpose it?

I have a vector of size n; n is power of 2. I need to treat this vector as a matrix n = R*C. Then I need to transpose the matrix.
For example, I have vector: [1,2,3,4,5,6,7,8]
I need to find R and C. In this case it would be: 4,2. And treat vector as matrix:
[1,2]
[3,4]
[5,6]
[7,8]
Transpose it to:
[1, 3, 5, 7]
[2, 4, 6, 8]
After transposition vector should be: [1, 3, 5, 7, 2, 4, 6, 8]
Is there existing algorithms to perform in-place non-square matrix transposition? I don't want to reinvent a wheel.
My vector is very big so I don't want to create intermediate matrix. I need an in-place algorithm. Performance is very important.
All modofications should be done in oroginal vector. Ideally algorithm should work with chunks that will fit in CPU cache.
I can't use iterator because of memory locality. So I need real transposition.
It does not matter if matrix would be 2x4 or 4x2
The problem can be divided in two parts. First, find R and C and then, reshape the matrix. Here is something I would try to do:
Since n is a power of 2, i.e. n = 2^k then if k is even, we have: R=C=sqrt(n). And if k is odd, then R = 2^((k+1)/2) and C=2^((k-1)/2).
Note: Since you mentioned you want to avoid using extra memory, I have made some editions to my original answer.
The code to calculate R and C would be something like:
void getRandC(const size_t& n, size_t& R, size_t& C)
{
int k = (int)log2(double(n)),
i, j;
if (k & 1) // k is odd
i = (j = (k + 1) / 2) - 1;
else
i = j = k / 2;
R = (size_t)exp2(i);
C = (size_t)exp2(j);
}
Which needs C++11. For the second part, in case you want to keep the original vector:
void transposeVector(const std::vector<int>& vec, std::vector<int>& mat)
{
size_t R, C;
getRandC(vec.size(), R, C);
// first, reserve the memory
mat.resize(vec.size());
// now, do the transposition directly
for (size_t i = 0; i < R; i++)
{
for (size_t j = 0; j < C; j++)
{
mat[i * C + j] = vec[i + R * j];
}
}
}
And, if you want to modify the original vector and avoid using extra memory, you can write:
void transposeInPlace(std::vector<int>& vec)
{
size_t R, C;
getRandC(vec.size(), R, C);
for (size_t j = 0; R > 1; j += C, R--)
{
for (size_t i = j + R, k = j + 1; i < vec.size(); i += R)
{
vec.insert(vec.begin() + k++, vec[i]);
vec.erase(vec.begin() + i + 1);
}
}
}
See the live example
Since you haven't provided us with any of your code, can I suggest a different approach (that I don't know will work for your particular situation)?
I would use an algorithm based on your matrix to transpose your values into the new matrix yourself. Since performance is an issue this will help even more so since you don't have to create another matrix. If this is applicable for you.
Have a vector
[1, 2, 3, 4, 5, 6, 7, 8]
Create your matrix
[1, 2]
[3, 4]
[5, 6]
[7, 8]
Reorder vector without another matrix
[1, 3, 5, 7, 2, 4, 6, 8]
Overwrite the values in the current matrix (so you don't have to create a new one) and reorder the values based on your current matrix.
Add values in order
R1 and C1 to transposed_vector[0]
R2 and C1 to transposed_vector[1]
R3 and C1 to transposed_vector[2]
R4 and C1 to transposed_vector[3]
R1 and C2 to transposed_vector[4]
And so on.
For non square matrix representation, I think it may be tricky, and not worth the effort to make the transpose of your flat vector without creating another one. Here is a snippet of what I came up with:
chrono::steady_clock::time_point start = chrono::steady_clock::now();
int i, j, p, k;
vector<int> t_matrix(matrix.size());
for(k=0; k< R*C ;++k)
{
i = k/C;
j = k - i*C;
p = j*R + i;
t_matrix[p] = matrix[k];
}
cout << chrono::duration_cast<chrono::milliseconds> chrono::steady_clock::now() - start).count() << endl;
Here, matrix is your flat vector, t_matrix is the "transposed" flat vector, and R and C are, respectively rows and vector you found for your matrix representation.

How to cast CV_64F type Matrix to 1D Array with Double elements

I couldn't find an answer to this question but I believe it should be easily done.
Here I have following data structures;
Mat MyMatrix = Mat(3, 1, CV_64F, &targetArray) //Some 3x1 data in it
// Some process...
array <double ,3> MyArray
MyMatrix.convertTo(MyArray, double, 0 , DBL_MAX)
I want to convert MyMatrix (which I guarantee to be 3x1) to an 1D Array (Array elements should be double). How can I do that with C++ and opencv3.0.1?
You cannot convert a cv::Mat to a std::array. You can only copy the data into an array.
Given a
Mat m = Mat(3, 1, CV_64F);
// fill with some value
you can use memcpy:
array<double, 3> a;
memcpy(a.data(), m.ptr<double>(0), 3*sizeof(double));
or std::copy:
array<double, 3> b;
copy(m.begin<double>(), m.end<double>(), b.begin());
or, since it's only 3 elements, the array constructor:
array<double, 3> c = {m.at<double>(0), m.at<double>(1), m.at<double>(2)};
or, obviously, with a loop:
array<double, 3> d;
for (int i = 0; i < d.size(); ++i) { d[i] = m.at<double>(i); }
Conversion is instead possible with std::vector:
vector<double> e = m;
Note that, instead of a matrix with only 3 values, you can use Vec3d, or Matx31 or Matx13. Using Mat1d would however simplify the notation and make the code less verbose.

How to sort a multidimensional vector of floats?

So, I have a set of points in 3D, and I would like to store them in a 3 dimensional vector. Then I need sort that vector, giving priority first to the X dimention, then Y, then Z. So, for example, if I have this set of points:
P1 = (5, 10 ,9)
P2 = (1, 11, 4)
P3 = (8, 5, 2)
P4 = (5, 10, 3)
P5 = (5, 4, 0)
I would like to get a vector sorted like this:
[1, 11, 4]
[5, 4, 0]
[5, 10, 3]
[5, 10, 9]
[8, 5, 2]
So, how can a sort a multidimentional vector taking all rows into account?
Should I use std::priority_queue instead? If so, how show I use it?
Thanks
You could use an std::tuple<double, double, double> to represent a point. The comparison for std::tuple works lexicographically, the way you want it to. Alternatively, you could provide a custom sort function to your vector of points. Something like this:
sort(pointVector.begin(), pointVector.end(), [](const Point& lhs, const Point& rhs){//Implement your required comparison predicate here});
Also, as this question shows, you can achieve some sort of a named-tuple-with-lexicographic-sorting by using std::tuples lexicographic sort and std::tie.
...giving priority first to the X dimention, then Y, then Z
Use std::sort with std::tie, something like following
#include <algorithm>
#include <tuple>
//....
struct Points // Your 3D Point
{
float x,y,z;
} ;
std::vector<Points> v; // Vector of 3D points
std::sort( v.begin(), v.end(),
[]( const Points& lhs, const Points& rhs )
{
return std::tie(lhs.x,lhs.y,lhs.z)
< std::tie(rhs.x,rhs.y,rhs.z) ;
}
) ;
DEMO
You can use the std::sort() to easily sort according to your specific conditions by making your own comparator function.
Assuming you have stored a single 3D point in a struct point, and the points in a std::vector<points> (A std::tuple might be more useful.), try out this code.
Example:
#include <vector>
#include <algorithm>
using namespace std;
struct point
{
float x, y, z;
}
bool mySort(const point& a, const point& b)
{
//A naive comparison to help you understand better.
//You could always use std::tie for lexicographical comparison.
if (a.x == b.x)
{
if (a.y == b.y)
return a.z < b.z;
else
return a.y < b.y;
}
else
return a.x < b.x;
}
int main()
{
vector<point> graph;
//push_back() all your points into the graph.
//mySort() is a custom comparator function.
sort(graph.begin(),graph.end(),mySort);
}