I load an Eigen matrix A(5,12), and I would like to assign a new eigen Vector as the first 7 values of the first row of matrix A.
Somehow, it doesn't work...
Later I realize that block returns a pointer to the original data. How to deep copy the block into Eigen Vector?
Eigen::MatrixXd A(5,12);
Eigen::VectorXd B(12); B = A.row(0);
Eigen::VectorXd C(7); C = B.head(7);
Block methods like block, col, row, head, etc. return views on the original data, but operator = always perform a deep copy, so you can simply write:
VectorXd C = A.row(0).head(7);
This will perform a single deep copy. With Eigen 3.4 slicing API, you'll also be able to write:
VectorXd C = A(0,seqN(0,7));
Related
I have a data array (double *) in memory which looks like:
[x0,y0,z0,junk,x1,y1,z1,junk,...]
I would like to map it to an Eigen vector and virtually remove the junk values by doing something like:
Eigen::Map<
Eigen::Matrix<double, Eigen::Dynamic, 1, Eigen::ColMajor>,
Eigen::Unaligned,
Eigen::OuterStride<4>
>
But it does not work because the outerstride seems to be restricted to 2D matrices.
Is there a trick to do what I want?
Many thanks!
With the head of Eigen, you can map it as a 2D matrix and then view it as a 1D vector:
auto m1 = Matrix<double,3,Dynamic>::Map(ptr, 3, n, OuterStride<4>());
auto v = m1.reshaped(); // new in future Eigen 3.4
But be aware accesses to such a v involve costly integer division/modulo.
If you want a solution compatible with Eigen 3.3, you can do something like this
VectorXd convert(double const* ptr, Index n)
{
VectorXd res(n*3);
Matrix3Xd::Map(res.data(), 3, n) = Matrix4Xd::Map(ptr, 4, n).topRows<3>();
return res;
}
But this of course would copy the data, which you probably intended to avoid.
Alternatively, you should think about whether it is possible to access your data as a 3xN array/matrix instead of a flat vector (really depends on what you are actually doing).
I have been testing the Tensor module from Eigen3 for a new project.
Even when the module is not yet finished, it seems to have most of the functionality that I need.
But there is one part that I quite not get. Whenever I have a big Tensor and I want to extract a slice from it, Eigen makes a copy of the data.
Is there a way to not copy the data, but instead point to the original data block in the slice?
For example if I do:
Tensor<float, 3> A(100,1000,1000); A.setZero();
Eigen::array<int, 3> offsets = {0, 0, 0};
Eigen::array<int, 3> extents = {2, 2, 2};
Tensor<float, 3> c = A.slice(offsets, extents);
A(0,0,0) = 1.0;
cerr << c << endl;
But the first element of "c" is still zero, instead of mapping to the modified "A(0,0,0)" data block.
You can use a TensorMap to create a tensor based on shared memory space of your slice. However this only works if your slice occupies contiguous portion of the data array. Otherwise you would need to do some tensor arithmetic to figure out the begin and end 1d indices of various parts of your single slice.
TensorMap<Tensor<float, 3, RowMajor> > row_major(data, ...);
Is there a more elegant solution than to copy the values point to point?!
Something like this works for a 1D vector...
vector<float> vec(mat.data(), mat.data() + mat.rows() * mat.cols());
I tried various other alternatives that were suggested by the GCC compiler for vector< vector > but nothing worked out...
Eigen::MatrixXf uses efficient linear memory, while a vector of vector would represent a very different datatype.
For multidimentional vector, you would therefore have to read the matrix block by block and copy those values to the outmost vectors.
Another way would be to copy the values to a vector based class with specific accessors ... but that would end up reconstructing a Matrix like class.
Why do you want to do that ? What kind of access are you trying to provide ? Maybe you should rather try to do similar access using the eigen::matrix interface
Conversion
Eigen::MatrixXf m(2,3);
std::vector<std::vector<T>> v;
for (int i=0; i<m.rows(); ++i)
{
const float* begin = &m.row(i).data()[0];
v.push_back(std::vector<float>(begin, begin+m.cols()));
}
I have two geotiff images (saying "A" and "B") imported in Matlab as matrices with Geotiffread. One has different values, while the second has only 0 and 255s.
What I'd like to do is replacing all the 255s with the values inside the other image (or matrix), according to their positions.
A and B differs in size, but they have the same projections.
I tried this:
A (A== 255)= B;
the output is the error:
??? In an assignment A(:) = B, the number of elements in A and B must be the same.
Else, I also tried with the logical approach:
if A== 255
A= B;
end
and nothing happens.
Is there a way to replace the values of A with values of B according to a specific value and the position in the referenced space?
As darthbith put in his comment, you need to make sure that the number of entries you want to replace is the same as the number values you are putting in.
By doing A(A==255)=B you are trying to put the entire matrix B into the subset of A that equals 255.
However, if, as you said, the projections are the same, you can simply do A(A==255) = B(A==255), under the assumption that B is larger or the same size as A.
Some sample code to provide a proof of concept.
A = randi([0,10],10,10);
B = randi([0,4],15,15);
C = A % copy original A matrix for comparison later
A(A==5) = B(A==5); % replace values
C==A % compare original and new
This example code creates two matrices, A is a 10x10 and B is a 15x15 and replaces all values that equal 5 in A with the corresponding values in B. This is shown to be true by doing C==A which shows where the new matrix and the old matrix vary, proving replacement did happen.
It seems to me that you are trying to mask an image with a binary mask. You can do this:
BW = im2bw(B,0.5);
A=A.*BW;
hope it helps
Try A(A==255) = B(A==255). The error is telling you that when you try to assign values to the elements of an array, you cannot give it any more or fewer values than you are trying to assign.
Also, regarding the if statement: if A==255 means the same as if all(A==255), as in, if any elements of A are not 255, false is returned. You can check this at the command line.
If you're really desperate, you can use a pair of nested for loops to achieve this (assuming A and B are the same size and shape):
[a,b] = size(A);
for ii = 1:a
for jj = 1:b
if A(ii,jj) == 255
A(ii,jj) = B(ii,jj);
end
end
end
How can I find the following intersection of two array structs in Matlab.
For example, I have two struct arrays a and b:
a(1)=struct('x',1,'y',1);
a(2)=struct('x',3,'y',2);
a(3)=struct('x',4,'y',3);
a(4)=struct('x',5,'y',4);
a(5)=struct('x',1,'y',5);
b(1)=struct('x',1,'y',1);
b(2)=struct('x',3,'y',5);
I want to find the intersection of a and b as follows:
c = intersect(a,b)
where c should be
c = struct('x',1,'y',1);
But when it seems wrong when I type intersect(a,b) since the elements of a and b are both structures. How can I combat this difficulty. Thanks.
The elegant solution would have been to supply intersect with a comparator operator (like in , e.g., C++).
Unfortunaetly, Matlab does not seem to support this kind of functionality/flexibility.
A workaround for your problem would be
% convert structs into matrices
A = [[a(:).x];[a(:).y]]';
B = [[b(:).x];[b(:).y]]';
% intersect the equivalent representation
[C, ia, ib] = intersect( A, B, 'rows' );
% map back to original structs
c = a(ia);
Alternatively, have you considered replacing your structs with class objects derived from handle class? It might be possible to overload the relational operators of the class and then it should be possible to sort the class objects directly (I haven't looked closely into this solution - it's just a proposal off the tip of my head).
A more general variant of Shai's approach is:
A = cell2mat(permute(struct2cell(a), [3 1 2]));
B = cell2mat(permute(struct2cell(b), [3 1 2]));
[C, ia] = intersect(A, B, 'rows');
c = a(ia);
This way you don't need to explicitly specify all the struct fields. Of course, this won't work if the struct fields contain non-numeric values.
Generalized approach for fields of any type and dimensions
If you're uncertain about the type and size of the data stored in your structs, interesect won't cut it. Instead, you'll have to use isequal with a loop. I'm using arrayfun here for elegancy:
[X, Y] = meshgrid(1:numel(a), 1:numel(b));
c = a(any(arrayfun(#(m, n)isequal(a(m), b(n)), X, Y)));
A systematic approach would be to produce a hash - and then use intersect:
hash_fun = #(x) sprintf('x:%g;y:%g',x.x,x.y);
ha = arrayfun(hash_fun,a,'UniformOutput',false);
hb = arrayfun(hash_fun,b,'UniformOutput',false);
[hi,ind_a,ind_b]=intersect(ha,hb)
res=a(ind_a) % result of intersection