Initializing segments of an Eigen VectorXd - c++

I'd like to efficiently initialize segments of an VectorXd object from the Eigen library. This vector is large (~1e6) so I would like to do this efficiently. Below is an example showing what I was thinking.
size_t N = 1e6;
std::vector<double> F(1., 2., 3., 4.);
Eigen::VectorXd ln_f_origin( F.size() * num_B );
for (size_t i=0; i<F.size(); i++) {
ln_f_origin.segment(i*num_B, num_B) = log(F[i]/num_B);
}
This doesn't seem to be working. I'm getting the following error:
error: no match for 'operator=' (operand types are 'Eigen::DenseBase<Eigen::Matrix<double, -1, 1> >::FixedSegmentReturnType<-1>::Type' {aka 'Eigen::VectorBlock<Eigen::Matrix<double, -1, 1>, -1>'} and 'double')

Related

Slicing Eigen tensor: Error accessing matrices from tensors

I am new to tensor in Eigen and just trying to run simple examples here. This is the code I have it's to access the first matrix in a tensor. Let's say I have a tensor with size ((nz+1),ny,nx), where each matrix in this tensor should have the shape or size of (nz+1)-by-ny. The thing is I can only extract a matrix that returns size ny-by-nz.
The code:
static const int nx = 10;
static const int ny = 10;
static const int nz = 10;
Eigen::Tensor<double, 3> epsilon((nz+1),ny,nx);
epsilon.setZero();
//slicing test: access first matrix in tensor
std::array<long,3> offset = {0,0,0}; //Starting point
std::array<long,3> extent = {1,ny,nx}; //Finish point
std::array<long,2> shape2 = {(ny),(nx)};
std::cout << epsilon.slice(offset, extent).reshape(shape2) << std::endl;
The answer is a matrix with a 10-by-10 size. How can I change this to extract slice and reshape it into a 11x10 matrix instead (11 rows and 10 columns). I tried changing last line to std::array<long,2> shape2 = {(nz+1),(nx)}; but this returns the error:
Eigen::TensorEvaluator<const Eigen::TensorReshapingOp<NewDimensions, XprType>, Device>::TensorEvaluator(const XprType&, const Device&) [with NewDimensions = const std::array<long int, 2>; ArgType = Eigen::TensorSlicingOp<const std::array<long int, 3>, const std::array<long int, 3>, Eigen::Tensor<double, 3> >; Device = Eigen::DefaultDevice; Eigen::TensorEvaluator<const Eigen::TensorReshapingOp<NewDimensions, XprType>, Device>::XprType = Eigen::TensorReshapingOp<const std::array<long int, 2>, Eigen::TensorSlicingOp<const std::array<long int, 3>, const std::array<long int, 3>, Eigen::Tensor<double, 3> > >]: Assertion `internal::array_prod(m_impl.dimensions()) == internal::array_prod(op.dimensions())' failed.
Aborted
How can I change the number of rows in this matrix? Thanks
I was able to fix:
std::array<long,3> offset = {0,0,0}; //Starting point
std::array<long,3> extent = {(nz+1),nx,1}; //Finish point:(row,column,matrix)
std::array<long,2> shape = {(nz+1),(nx)};
std::cout << epsilon.slice(offset, extent).reshape(shape) << std::endl;

no matching function for call to ‘normalize(cv::Point3f&)’ error

I'm getting no matching function for call to ‘normalize(cv::Point3f&)’ error in this code snippet using gcc 9.3.0 and OpenCV 4.3.0:
cv::Point3f p{3, 0, 0}, q{0, 2, 0};
p.cross(q);
cv::normalize(p);
According to current documentation, both cross and normalize accept the same parameter type, which is const Vec< _Tp, cn > &. Why then call to cross compiles, but call to normalize doesn't?
EDIT
I know that cv::normalize((Vec3f)p); works. The question is why this explicit conversion to Vec3f is necessary here, but not in case of cross()?
cv::norm(...) gives you the norm (a scalar value) of your vector. You can normalize a vector by dividing by its norm.
Given two vector p, q, you can get the normal vector as:
cv::Point3f p{3, 0, 0}, q{0, 2, 0};
cv::Point3f r = p.cross(q);
cv::Point3f rn = r / cv::norm(r);
You can also use cv::Vec3f instead of cv::Point:
cv::Vec3f p{3, 0, 0}, q{0, 2, 0};
cv::Vec3f r = p.cross(q);
cv::Vec3f rn = r / cv::norm(r);
// or
cv::Vec3f rm = cv::normalize(r);
The question is why this explicit conversion to Vec3f is necessary here
Because cv::normalized is defined for cv::Vec_<Tp, 3>, not for cv::Point3_<Tp>
template<typename _Tp, int cn> inline
Vec<_Tp, cn> normalize(const Vec<_Tp, cn>& v)
{
double nv = norm(v);
return v * (nv ? 1./nv : 0.);
}
Please note that it just divides the vector by its norm, as showed above for the cv::Point3f case.
but not in case of cross()
cross is a method of the class cv::Point3_
Also note that cv::Point3_ has an overloaded conversion operator for cv::Vec
//! conversion to cv::Vec<>
operator Vec<_Tp, 3>() const;
According to the doc for 4.3.0, you need to include <opencv/core/matx.hpp>, have you tried that?
I do also understand from the doc that you need to assign the return value, the input argument is const, and you need to do that also for the cross product. So it's going o be something like:
#include <opencv/core/matx.hpp>
...
cv::Point3f p{3, 0, 0}, q{0, 2, 0};
auto normalized = cv::normalize(p.cross(q));
--EDIT--
There's also a mismatch in the type (Vec instead of Point). This last version builds fine:
cv::Vec3f p{3, 0, 0}, q{0, 2, 0};
auto normalized = cv::normalize(p.cross(q)); // Defined only for Vec_
cv::Point3f p3 = normalized; // Get back a Point3f, or continue with a Vec?

Converting Eigen 4x4 Matrix to QMatrix4x4

I've been converting RGBDSLAM to armhf (https://github.com/felixendres/rgbdslam_v2) and I've been encountering errors with this function:
template <typename T >
QMatrix4x4 eigenTF2QMatrix(const T& transf)
{
Eigen::Matrix<double, 4, 4, Eigen::RowMajor> m = transf.matrix();
//QMatrix4x4 qmat( static_cast<qreal*>( m.data() ) ); (original line)
QMatrix4x4 qmat( m.data() );
printQMatrix4x4("From Eigen::Transform", qmat);
return qmat;
}
The line:
QMatrix4x4 qmat( m.data() );
as well as the original:
QMatrix4x4 qmat( static_cast<qreal*>( m.data() ) );
Gives me the error:
error: invalid conversion from 'Eigen::PlainObjectBase<Eigen::Matrix<double, 4, 4, 1> >::Scalar* {aka double*}' to 'int' [-fpermissive]
How can I fix this function to work on arm?
You cannot cast a pointer and expect it to work. There is the cast method of Eigen, but it does not work with temporaries, so you will have to perform a copy:
using Eigen;
Matrix<qreal, 4, 4, RowMajor> mcopy = m.cast<qreal>();
QMatrix4x4 qmat(mcopy.data());

simple multiplication or operator issue

I am trying to run this simple code. But I am missing something. I tried to look at operator overloading. Could someone explain what I am missing here.
#include <iostream>
#include <vector>
#include <cstdlib>
int main(){
std::vector < std::vector<double> > tm;
std::vector<int> dfg;
// Creating a simple matrix
double ta1[]={0.5,0.5,0};
std::vector <double> tv1 (ta1, ta1+3);
tm.push_back(tv1);
double ta2[]={0.5,0,0};
std::vector <double> tv2 (ta2, ta2+3);
tm.push_back(tv2);
double ta3[]={0,0.5,0};
std::vector <double> tv3 (ta3, ta3+3);
tm.push_back(tv3);
double d_load =0.5;
// doing some simple calculations
for (int destinationID = 1; destinationID <= tm.size(); destinationID++){
float randomNum = ((double) rand())/((double) RAND_MAX);
if (randomNum <= d_load * tm[destinationID - 1])
dfg.push_back(destinationID);
}
return 0;
}
I get the following error.
error: no match for ‘operator*’ in ‘d_load * tm.std::vector<_Tp, _Alloc>::operator[] [with _Tp = std::vector<double>, _Alloc = std::allocator<std::vector<double> >, std::vector<_Tp, _Alloc>::reference = std::vector<double>&, std::vector<_Tp, _Alloc>::size_type = long unsigned int](((long unsigned int)(destinationID + -0x00000000000000001)))’
The tm is a std::vector<std::vector<double>>, thus effectively it is a 2-dimensional dynamic array of double. This means that to access the individual double elements in tm, you would use something like this:
double value = tm[destinationID - 1][theValueIndex];
It is the [theValueIndex] part of the loop that you're missing.
Since we don't know your exact intentions on how you want to traverse the array, I leave it to you to fill in this gap.
The following line is invalid:
d_load * tm[destinationID - 1]
Since tm is a std::vector<std::vector<double>>, The elements of tm are std::vector<double>, not double. If you want to multiply each number or check that each number matches the condition, you have to iterate the element you're getting out of tm[]

Filter points inside of a sphere with Eigen

I have a set of 3D points, and I need to compute which ones are the nearest to a given point p. I am wondering which could be the correct way to do it in Eigen. So far, I have:
Matrix<double, Dynamic, 3> points; // The set of 3D points
Matrix<double, 1, 3> p;
// Populate the "points" matrix
...
// Fill a matrix with several copies of "p" in order to match the size
of "points"
Matrix<double, Dynamic, 3> pp(points.rows(), 3);
pp = Matrix<double, Dynamic, 1>::Ones(points.rows, 1) * p;
Matrix<double, Dynamic, 1> sq_distances = (points - pp).rowwise.squaredNorm();
Matrix<bool, Dynamic, 1> nearest_points = sq_distances < (dist_threshold * dist_threshold);
Can I then have some way of extracting the points in "points" that fullfill the "nearest_points" condition like in
Matrix<double, Dynamic, 3> nearest = points(nearest_points);
?
For the nearest I'd suggest:
int i;
double sqdist = (points.rowwise()-p).rowwise().squaredNorm().minCoeff(&i);
nearest = points.row(i);
For the ones in a given ball, you currently have to write one loop yourself:
ArrayXd sqdists = (points.rowwise()-p).rowwise().squaredNorm();
Matrix<double,Dynamic,3> nearests( (sqdists<sqradius).count(), 3 );
int count = 0;
for(int i=0; i<points.rows(); ++i)
if(sqdists(i)<sqradius)
nearests.row(count++) = points.row(i);