Eigen3/C++: Tile a MatrixXd with a Vector3d - c++

What is the most elegant way in 'Eigen3/C++' to construct a MatrixXd
from a repeated Vector3d. That is, given a row vector
Eigen::Vector3d V(v00, v01, v02);
the goal is to find an operation op such that
Eigen::MatrixXd M = op(V, N);
delivers a matrix M consisting of N rows which are equal to V, i.e.
/ v00 v01 v02 \
| v00 v01 v02 |
M = | ... |
| |
\ v00 v01 v02 /
similar to what can be achieved by tile in numpy.

vectorwise and dense expressions can replicate:
V.rowwise().replicate(N).transpose() // or
V.transpose().colwise().replicate(N) // or
V.transpose().replicate(N,1) // or ...
of which there are also corresponding versions when N and/or the direction is known at compile time...

Related

Generating spheres with vertices and indices?

I'm currently working on an OpenGL project where I should currently generate spheres with vertices and indices.
All vertices represent a point, and indices tells the graphic card to link 3 points as a triangle.
Example : indices : {0,1,2} = it will make a triangle with the first, second and third point.
I've managed to make a UV sphere with correct vertices, but I don't know how I can get indices.
Here is my current result :
And here is my code :
Mesh ObjectFactory::createSphere() {
// Texture loaded and binded to the shaderprogram
Texture textures[]{
Texture("resources/pop_cat.png", "diffuse", 0, GL_RGBA, GL_UNSIGNED_BYTE),
};
int numHorizontalSegments = 20;
int numVerticalSegments = 20;
Vertex vertices[numVerticalSegments * numVerticalSegments] = {};
GLuint indices[numVerticalSegments * numVerticalSegments] = {};
int i = 0;
for (int h = 0; h < numHorizontalSegments; h++) {
float angle1 = (h + 1) * M_PI / (numHorizontalSegments + 1);
for (int v = 0; v < numVerticalSegments; v++) {
i++;
float angle2 = v * (2 * M_PI) / numVerticalSegments;
float x = sinf(angle1) * cosf(angle2);
float y = cosf(angle1);
float z = sinf(angle1) * sinf(angle2);
vertices[i] = Vertex{glm::vec3(x, y, z), glm::vec3(0.83f, 0.70f, 0.44f), glm::vec2(0.0f, 0.0f)};
indices[i] = i;
}
}
// Store mesh data in vectors for the mesh
std::vector<Vertex> verts(vertices, vertices + sizeof(vertices) / sizeof(Vertex));
std::vector<GLuint> ind(indices, indices + sizeof(indices) / sizeof(GLuint));
std::vector<Texture> tex(textures, textures + sizeof(textures) / sizeof(Texture));
// Create sphere mesh
return {verts, ind, tex};
}
Thank you a lot for your help !
You have created a sphere of vertices by calculating horizontal circles in multiple vertical layers, a UV sphere. Good.
You are just adding indexes once for each vertex for a total of one index per vertex, that is not according to the concept.
What you need to repeatedy do is finding the three indexes in your array of vertices, which make a usable triangle.
Among other things it means that you will name the same vertex index multiple times. Mostly six times, because most of your vertices will be part of six triangles. At least one to the "upper left", one towards the "upper right", "lower left", "lower right"; while there are usually two double directions; e.g. two triangles to the upper right.
"mostly six", because of edge cases like the "north pole" and "south pole"; which participate in many triangles and quads.
Lets looks at a part of your UV sphere:
V03----------V02----------V01---------V00
| | __/ | __/|
| | __/ | c __/ |
| | __/ | __/ |
| | / f | / d |
V13----------V12----------V11----------V10
| | __/ | e __/|
| | a __/ | __/ |
| | __/ | __/ |
| | / b | / |
V23----------V22----------V21----------V20
| | | |
| | | |
| | | |
| | | |
V33----------V32----------V31---------V30
You can see that for the quad in the middle (represented by two triangles "a" and "b"),
you need six index entries, though it only has 4 of the vertices, and each of the vertices will be used even more often, from the other touching quads.
For the triangle "a" you get indexes for the vertexes V11, V12, V22 (mind the orientation, depending on where you want the surface, thinking either always "counter clock" or always "clockwise" will get you where you only need a few tries to get the desired result).
For the triangle "b" you get indexes for the vertexes V11, V22, V21.
Also, the vertex V11 will have to be index again for the triangle "c" and "d", and "e", and "f"; for participating in six triangles or four quads.
You managed to do your UV sphere fine, so I do not think that I need to provide the loop and selection code for getting that done. You managed to visualise the result of your UV sphere, just try and retry after checking the result.

How to get texture coordinates from VTK IntersectWithLine?

I've loaded a texture mapped OBJ via vtkOBJReader and loaded it into a vtkModifiedBSPTree:
auto readerOther(vtkSmartPointer<vtkOBJReader>::New());
auto rawOtherPath(modelPathOther.toLatin1());
readerOther->SetFileName(rawOtherPath.data());
readerOther->Update();
auto meshDataOther(readerOther->GetOutput());
auto bspTreeOther(vtkSmartPointer<vtkModifiedBSPTree>::New());
bspTreeOther->SetDataSet(meshDataOther);
bspTreeOther->BuildLocator();
I then compute my line segment start and end and feed that into
if (bspTreeOther->IntersectWithLine(p1, p2, tolerance, distanceAlongLine, intersectionCoords, pcoords, subId, cellId, cell))
With all the relevant predefined variables of course.
What I need is the texture's UV coordinates at the point of intersection.
I'm so very new to VTK that I've not yet caught the logic of how its put together yet; the abstraction layers are still losing me while I'm digging through the source.
I've hunted for this answer across SO and the VTK users archives and found vague hints given by those who understood VTK deeply to those who were nearly there themselves, and thus of little help to me thus far.
(Appended 11/9/2018)
To clarify, I'm working with non-degenerate triangulated meshes created by a single 3D scanner shot, so quads and other higher polygons are not going to be ever seen by my code. A general solution should account for such things, but that can be accomplished via triangulating the mesh first via a good application of handwavium.
Code
Note that if one vertex belongs to several polygons and has different texture coordinates, VTK will create duplicates of the vertex.
I don't use vtkCleanPolyData, because VTK will merge such "duplicates" and we will lose needed information, as far as I know.
I use vtkCellLocator instead of vtkModifiedBSPTree,
because in my case it was faster.
The main file main.cpp.
You can find magic numbers in start and end arrays — these are your p1 and p2.
I've set these values just for example
#include <vtkSmartPointer.h>
#include <vtkPointData.h>
#include <vtkCellLocator.h>
#include <vtkGenericCell.h>
#include <vtkOBJReader.h>
#include <vtkTriangleFilter.h>
#include <vtkMath.h>
#include <iostream>
int main(int argc, char * argv[])
{
if (argc < 2)
{
std::cerr << "Usage: " << argv[0] << " OBJ_file_name" << std::endl;
return EXIT_FAILURE;
}
auto reader{vtkSmartPointer<vtkOBJReader>::New()};
reader->SetFileName(argv[1]);
reader->Update();
// Triangulate the mesh if needed
auto triangleFilter{vtkSmartPointer<vtkTriangleFilter>::New()};
triangleFilter->SetInputConnection(reader->GetOutputPort());
triangleFilter->Update();
auto mesh{triangleFilter->GetOutput()};
// Use `auto mesh(reader->GetOutput());` instead if no triangulation needed
// Build a locator to find intersections
auto locator{vtkSmartPointer<vtkCellLocator>::New()};
locator->SetDataSet(mesh);
locator->BuildLocator();
// Initialize variables needed for intersection calculation
double start[3]{-1, 0, 0.5};
double end[3]{ 1, 0, 0.5};
double tolerance{1E-6};
double relativeDistanceAlongLine;
double intersectionCoordinates[3];
double parametricCoordinates[3];
int subId;
vtkIdType cellId;
auto cell{vtkSmartPointer<vtkGenericCell>::New()};
// Find intersection
int intersected = locator->IntersectWithLine(
start,
end,
tolerance,
relativeDistanceAlongLine,
intersectionCoordinates,
parametricCoordinates,
subId,
cellId,
cell.Get()
);
// Get points of intersection cell
auto pointsIds{vtkSmartPointer<vtkIdList>::New()};
mesh->GetCellPoints(cellId, pointsIds);
// Store coordinates and texture coordinates of vertices of the cell
double meshTrianglePoints[3][3];
double textureTrianglePoints[3][2];
auto textureCoordinates{mesh->GetPointData()->GetTCoords()};
for (unsigned pointNumber = 0; pointNumber < cell->GetNumberOfPoints(); ++pointNumber)
{
mesh->GetPoint(pointsIds->GetId(pointNumber), meshTrianglePoints[pointNumber]);
textureCoordinates->GetTuple(pointsIds->GetId(pointNumber), textureTrianglePoints[pointNumber]);
}
// Normalize the coordinates
double movedMeshTrianglePoints[3][3];
for (unsigned i = 0; i < 3; ++i)
{
movedMeshTrianglePoints[0][i] = 0;
movedMeshTrianglePoints[1][i] =
meshTrianglePoints[1][i] -
meshTrianglePoints[0][i];
movedMeshTrianglePoints[2][i] =
meshTrianglePoints[2][i] -
meshTrianglePoints[0][i];
}
// Normalize the texture coordinates
double movedTextureTrianglePoints[3][2];
for (unsigned i = 0; i < 2; ++i)
{
movedTextureTrianglePoints[0][i] = 0;
movedTextureTrianglePoints[1][i] =
textureTrianglePoints[1][i] -
textureTrianglePoints[0][i];
movedTextureTrianglePoints[2][i] =
textureTrianglePoints[2][i] -
textureTrianglePoints[0][i];
}
// Calculate SVD of a matrix consisting of normalized vertices
double U[3][3];
double w[3];
double VT[3][3];
vtkMath::SingularValueDecomposition3x3(movedMeshTrianglePoints, U, w, VT);
// Calculate pseudo inverse of a matrix consisting of normalized vertices
double pseudoInverse[3][3]{0};
for (unsigned i = 0; i < 3; ++i)
{
for (unsigned j = 0; j < 3; ++j)
{
for (unsigned k = 0; k < 3; ++k)
{
if (w[k] != 0)
{
pseudoInverse[i][j] += VT[k][i] * U[j][k] / w[k];
}
}
}
}
// Calculate interpolation matrix
double interpolationMatrix[3][2]{0};
for (unsigned i = 0; i < 3; ++i)
{
for (unsigned j = 0; j < 2; ++j)
{
for (unsigned k = 0; k < 3; ++k)
{
interpolationMatrix[i][j] += pseudoInverse[i][k] * movedTextureTrianglePoints[k][j];
}
}
}
// Calculate interpolated texture coordinates of the intersection point
double interpolatedTexturePoint[2]{textureTrianglePoints[0][0], textureTrianglePoints[0][1]};
for (unsigned i = 0; i < 2; ++i)
{
for (unsigned j = 0; j < 3; ++j)
{
interpolatedTexturePoint[i] += (intersectionCoordinates[j] - meshTrianglePoints[0][j]) * interpolationMatrix[j][i];
}
}
// Print the result
std::cout << "Interpolated texture coordinates";
for (unsigned i = 0; i < 2; ++i)
{
std::cout << " " << interpolatedTexturePoint[i];
}
std::cout << std::endl;
return EXIT_SUCCESS;
}
CMake project file CMakeLists.txt
cmake_minimum_required(VERSION 3.1)
PROJECT(IntersectInterpolate)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(VTK REQUIRED)
include(${VTK_USE_FILE})
add_executable(IntersectInterpolate MACOSX_BUNDLE main.cpp)
if(VTK_LIBRARIES)
target_link_libraries(IntersectInterpolate ${VTK_LIBRARIES})
else()
target_link_libraries(IntersectInterpolate vtkHybrid vtkWidgets)
endif()
Math
What we need
Suppose you have a mesh consisting of triangles and your vertices have texture coordinates.
Given vertices of a triangle A, B and C, corresponding texture coordinates A', B' and C', you want to find a mapping (to interpolate) from another inner and boundary points of the triangle to the texture.
Let's make some rational assumptions:
Points A, B, C should correspond to their texture coordinates A', B', C';
Each point X on the border, say AB, should correspond to the points of A'B' line in following way: |AX| / |AB| = |A'X'| / |A'B'| — half way on the original triangle should be a half way on the texture map;
Centroid of the triangle (A + B + C) / 3 should correspond to centroid of the texture triangle (A' + B' + C') / 3.
Equations to solve
Looks like we want to have affine mapping: coordinates of vertices of the original triangle should be multiplied by some coefficients and be added to some constants.
Let's construct the system of equations
Ax * Mxx + Ay * Myx + Az * Mzx + M0x = A'x
Ax * Mxy + Ay * Myy + Az * Mzy + M0y = A'y
Ax * Mxz + Ay * Myz + Az * Mzz + M0z = 0
and the same for B and C.
You can see that we have 9 equations and 12 unknowns.
Though, equations containing Miz (for i in {x, y, z}) have the solution 0 and don't play any role in further computations, so we can just set them equal to 0.
Thus, we have system with 6 equations and 8 unknowns
Ax * Mxx + Ay * Myx + Az * Mzx + M0x = A'x
Ax * Mxy + Ay * Myy + Az * Mzy + M0y = A'y
Let's write entire system in matrix view
-- -- -- -- -- --
| 1 Ax Ay Az | | M0x M0y | | A'x A'y |
| 1 Bx By Bz | x | Mxx Mxy | = | B'x B'y |
| 1 Cx Cy Cz | | Myx Myy | | C'x C'y |
-- -- | Mzx Mzy | -- --
-- --
I subtract coordinates of A vertex from B and C
and texture coordinates A' from B' and C',
and now we have the triangle with the first vertex located
in start of coordinate system as well as corresponding texture coordinates.
This means that now triangles are not translated (moved) one relative to another
and we don't need M0 part of interpolation matrix
-- -- -- -- -- --
| Bx By Bz | | Mxx Mxy | | B'x B'y |
| Cx Cy Cz | x | Myx Myy | = | C'x C'y |
-- -- | Mzx Mzy | -- --
-- --
Solution
Let's call the first matrix P, the second M and the last one T
P M = T
The matrix P is not square.
If we add zero row to it, the matrix becomes singular.
So, we have to calculate pseudo-inverse of it in order to solve the equation.
There's no function for calculating pseudo-inverse matrix in VTK.
We go to Moore–Penrose inverse article on Wikipedia and see that it can be calculated using SVD.
VTKMath::SingularValueDecomposition3x3 function allows us to do it.
The function gives us U, S and VT matrices.
I'll write pseudo-inverse of matrix P as P",
transposition of U as UT and transposition of VT as V.
Pseudo-inverse of diagonal matrix S is a matrix with 1 / Sii elements
where Sii is not a zero and 0 for zero elements
P = U S VT
P" = V S" UT
M = P" T
Usage
To apply interpolation matrix,
we need to not forget that we need to translate input and output vectors.
A' is a 2D vector of texture coordinates of the first vertex in the triangle,
A is a 3D vector of coordinates of the vertex,
M is the found interpolation matrix,
p is a 3D intersection point we want to get texture coordinates for,
t' is the resulting 2D vector with interpolated texture coordinates
t' = A' + (p - A) M
[Rewritten 2019/5/7 to reflect an updated understanding.]
After finding out that the parametric coordinates are inputs to a function from which one can get barycentric coordinates in the case of triangular cells, and then learning about what barycentric coordinates are, I was able to work out the following.
const auto readerOther(vtkSmartPointer<vtkOBJReader>::New());
const auto rawOtherPath(modelPathOther.toLatin1());
readerOther->SetFileName(rawOtherPath.data());
readerOther->Update();
const auto meshDataOther(readerOther->GetOutput());
const auto bspTreeOther(vtkSmartPointer<vtkModifiedBSPTree>::New());
bspTreeOther->SetDataSet(meshDataOther);
bspTreeOther->BuildLocator();
double point1[3]{0.0, 0.0, 0.0}; // start of line segment used to intersect the model.
double point2[3]{0.0, 0.0, 10.0}; // end of line segment
double distanceAlongLine;
double intersectionCoords[3]; // The coordinate of the intersection.
double parametricCoords[3]; // Parametric Coordinates of the intersection - see https://lorensen.github.io/VTKExamples/site/VTKBook/08Chapter8/#82-interpolation-functions
int subId; // ?
vtkIdType cellId;
double intersectedTextureCoords[2];
if (bspTreeOther->IntersectWithLine(point1, point2, TOLERANCE, distanceAlongLine, intersectionCoords, parametricCoords, subId, cellId))
{
const auto textureCoordsOther(meshDataOther->GetPointData()->GetTCoords());
const auto pointIds{meshDataOther->GetCell(cellId)->GetPointIds()};
const auto vertexIndex0{pointIds->GetId(0)};
const auto vertexIndex1{pointIds->GetId(1)};
const auto vertexIndex2{pointIds->GetId(2)};
double texCoord0[2];
double texCoord1[2];
double texCoord2[2];
textureCoordsOther->GetTuple(vertexIndex0, texCoord0);
textureCoordsOther->GetTuple(vertexIndex1, texCoord1);
textureCoordsOther->GetTuple(vertexIndex2, texCoord2);
const auto parametricR{parametricCoords[0]};
const auto parametricS{parametricCoords[1]};
const auto barycentricW0{1 - parametricR - parametricS};
const auto barycentricW1{parametricR};
const auto barycentricW2{parametricS};
intersectedTextureCoords[0] =
barycentricW0 * texCoord0[0] +
barycentricW1 * texCoord1[0] +
barycentricW2 * texCoord2[0];
intersectedTextureCoords[1] =
barycentricW0 * texCoord0[1] +
barycentricW1 * texCoord1[1] +
barycentricW2 * texCoord2[1];
}
Please note that this code is an interpretation of the actual code I'm using; I'm using Qt and its QVector2D and QVector3D classes along with some interpreter glue functions to go to and from arrays of doubles.
See https://lorensen.github.io/VTKExamples/site/VTKBook/08Chapter8 for details about the parametric coordinate systems of various cell types.

3D Reconstruction: Solving Equations for 3D Points from Uncalibrated Images

This is a pretty straightforward question (I hope). The following is from 3D reconstruction from Multiple Images, Moons et al (Fig 2-13, p. 348):
Projective 3D reconstruction from two uncalibrated images
Given: A set of point correspondences m1 in I1 and m2 in I2 between two uncalibrated images I1 and I2 of a static scene.
Aim: A projective 3D reconstruction ^M of the scene.
Algorithm:
Compute an estimate ^F for the fundamental matrix
Compute the epipole e2 from ^F
Compute the 3x3-matrix
^A = −(1/||e2||2) [e2]x ^F
For each pair of corresponding image points m1 and m2, solve the following system of linear equations for ^M :
^p1 m1 = ^M and ^p2 m2 = ^A ^M + e2
( ^p1 and ^p2 are non-zero scalars )
[I apologize for the formatting. I don't know how to put hats over characters.]
I'm pretty much OK up until step 4. But it's been 30+ years since my last linear algebra class, and even then I'm not sure I knew how to solve something like this. Any help or references would be greatly appreciated.
By the way, this is sort of a follow-on to another post of mine:
Detecting/correcting Photo Warping via Point Correspondences
This is just another way to try to solve the problem.
Given a pair of matching image points m1 and m2, the two corresponding rays from the optical centers are unlikely to intersect perfectly due to noise in the measurements. Consequently a solution to the provided system should instead be found in the (linear) least square sense i.e. find x = argmin_x | C x - d |^2 with (for instance):
/ 0 \ / \
| I -m1 0 | | M |
C x = | 0 | | |
| 0 | | p1 |
| A 0 -m2 | \ p2 /
\ 0 /
and
/ 0 \
| 0 |
d = | 0 |
| |
| -e2 |
\ /
The problem has 5 unknowns for 6 equations.
A possible alternative formulation exploits the fact that m1 and m2 are collinear with M so m1 x M = 0 and m2 x (A M + e2) = 0 yielding the linear least squares problem x = argmin_x | C x - d |^2 with:
/ [m1]x \ / \
C = | | | M |
\ [m2]x A / \ /
and
/ 0 \
d = | |
\ -m2 x e2 /
where [v]x is the 3 x 3 matrix of the cross product with v. The problem has 3 unknowns for 6 equations which can be reduced to 4 only by keeping non-linearly dependent ones.

How to get full access to one dimension in OpenCV mat?

Ok, My problem is not accessing one element from the mat, but I want to get the whole mat while one dimension is fixed. Let's say we have a three dimension matrix and I want to access the third dimension which should return a rows*cols mat.
In matlab, this is extremely easy, say A is a three dimension matrix(3*3*3), if we want to access the the third dimension, then just use A(:,:,1), A(:,:,2) A(:,:,3). But how should we do in OpenCV? It seems that OpenCV didn't provide this method?
I am asking this because I have a vector of Mat: Vector frames, each element in the vector is a two dimension gray image. I want to change the vector format into a three-dimensional Mat format. But I just don't know how to copy it. The ideal way should be:
for(int i=0; i<frames.size(); i++) {
A(:,:,i) = frames[i].clone();
}
How should I do this? Thanks!
To answer your specific question on how to combine 3 channels into one image, you would use merge like so:
merge(frames, A);
For the more general question of how to access 2D planes of a 3D Mat, hopefully this tutorial will give you some insight. Specifically how the B, G and R components of a Mat are interleaved on each row like so (they have a much better image in the tutorial):
| Col 1 | Col 2 | Col 3 | Col 4 |...
Row 1 |B G R | B G R | B G R | B G R |...
Row 2 |B G R | B G R | B G R | B G R |...
Row 3 |B G R | B G R | B G R | B G R |...
...

How to convert a Eigen::Quaternion<float> to a Matrix4f?

As the title says, i have a problem to convert a Quaternion to a Matrix4f. Eigen has the method Quaternion.toRotationMatrix() which gives me a Matrix3f.
Now i need a Matrix4f ( because our program is designed to take only Matrix4f), is there an easy way to achieve this?
#Zacharias' answer contains the necessary theory. I just reiterate my earlier comment I made there with the actual Eigen C++ code.
Eigen::Matrix3f mat3 = Eigen::Quaternionf(W, X, Y, Z).toRotationMatrix();
Eigen::Matrix4f mat4 = Eigen::Matrix4f::Identity();
mat4.block(0,0,3,3) = mat3;
Eigen::Matrix4f::Identity() takes care of initializing the ones and zeros of the 4th and last row and column. mat4.block(0,0,3,3) = mat3 then overwrites the values obtained from the rotation matrix.
M3 to M4
The answere is already there, given by Rob and Najzero.
In most cases, it will be sufficient to construct the matrix as follows:
m3:
|a00|a01|a02|
|a10|a11|a12|
|a20|a21|a22|
to m4:
|a00|a01|a02| 0 |
|a10|a11|a12| 0 |
|a20|a21|a22| 0 |
| 0 | 0 | 0 | 1 |
The 4x4 matrix does not only allow to rotate a vector, but also to shift(translate) and scale (in all 3 directions) any vector. So basically you got a full transformation matrix - thats why it is often used in computer graphics, describing the transformation of an object. Depending on row-column order, we might identify the matrix as:
|rot|rot|rot| sx |
|rot|rot|rot| sy |
|rot|rot|rot| sz |
| x | y | z | 1 |
with sx,sy,sz as scaling coefficients, and x,y,z as translation coefficients.
PS: of course, if you want to rotate a vector with m4, you will than have to use a 4-dimensional vector, e.g. (x,y,z,w) with w=1 (in most cases).
The direct approach
Convert Quaternion rotation to rotation matrix?
And my personal recommendation:
http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToMatrix/
There you will find also other transformations, backtrafos and so on.