I want to multiply 2 quaternions, which are stored in a cv::Mat structure. I want the function to be as efficient as possible. I have the following code so far:
/** Quaternion multiplication
*
*/
void multiplyQuaternion(const Mat& q1,const Mat& q2, Mat& q)
{
// First quaternion q1 (x1 y1 z1 r1)
const float x1=q1.at<float>(0);
const float y1=q1.at<float>(1);
const float z1=q1.at<float>(2);
const float r1=q1.at<float>(3);
// Second quaternion q2 (x2 y2 z2 r2)
const float x2=q2.at<float>(0);
const float y2=q2.at<float>(1);
const float z2=q2.at<float>(2);
const float r2=q2.at<float>(3);
q.at<float>(0)=x1*r2 + r1*x2 + y1*z2 - z1*y2; // x component
q.at<float>(1)=r1*y2 - x1*z2 + y1*r2 + z1*x2; // y component
q.at<float>(2)=r1*z2 + x1*y2 - y1*x2 + z1*r2; // z component
q.at<float>(3)=r1*r2 - x1*x2 - y1*y2 - z1*z2; // r component
}
Is this the fastest way with OpenCV? Would it be fastest using fixed-point arithmetic?
In this tutorial different ways to access different pixels are covered. The Mat::at function was found to be about 10% slower in comparison to direct pixel access, probably due to the extra check in debug mode.
If you are really off for performance, you should rewrite your method with the 3 different methods mentioned in the text and then profile to find the one which is best in your situation.
There -had- been an ARM vector floating point quaternion multiply out there I can not find now. I could find this SIMD library:
Bullet 3D Game Multiphysics Library
Quaternions are often used to rotate 3D vectors so you might consider checking that one quaternion is a pure vector (i.e., the scalar or real part is zero). This could cut your work to 12 multiplies, 8 adds/subtracts and one sign flip.
You can also use quaternion multiplication on two pure vectors to compute their dot and cross products simultaneously, so testing for this special case may also be worth it. If both quaternions are pure vectors, you only need do 9 multiplies, 5 add/subtracts and one sign flip.
Related
Consider the following code:
#include <Eigen/Core>
using Matrix = Eigen::Matrix<float, 2, 2>;
Matrix func1(const Matrix& mat) { return mat + 0.5; }
Matrix func2(const Matrix& mat) { return mat / 0.5; }
func1() does not compile; you need to replace mat with mat.array() in the function body to fix it ([1]). However, func2() does compile as-is.
My question has to do with why the API is designed this way. Why is addition-with-scalar and division-by-scalar treated differently? What problems would arise if the following method is added to the Matrix class, and why haven't those problems arisen already for the operator/ method?:
auto operator+(Scalar s) const { return this->array() + s; }
From a mathematics perspective, a scalar added to a matrix "should" be the same as adding the scalar only to the diagonal. That is, a math text would usually use M + 0.5 to mean M + 0.5I, for I the identity matrix. There are many ways to justify this. For example, you can appeal to the analogy I = 1, or you can appeal to the desire to say Mx + 0.5x = (M + 0.5)x whenever x is a vector, etc.
Alternatively, you could take M + 0.5 to add 0.5 to every element. This is what you think is right if you don't think of matrices from a "linear algebra mindset" and treat them as just collections (arrays) of numbers, where it is natural to just "broadcast" scalar operations.
Since there are multiple "obvious" ways to handle + between a scalar and a matrix, where someone expecting one may be blindsided by the other, it is a good idea to do as Eigen does and ban such expressions. You are then forced to signify what you want in a less ambiguous way.
The natural definition of / from an algebra perspective coincides with the array perspective, so no reason to ban it.
I do not know how to approach this math problem. Any hint would be much appreciated. Before I could solve such problem using Atan2 method to get two vector angles, when axes c and a are orthogonal.
Problem: there are two non orthogonal to each other vectors c and a. I need to rotate one time around vector c then around vector a to obtain vector v orientation.
Question: how can I get c and a vector rotations, when I only know vector v orientation?
In the image below, c and a vector rotations are both 0.
I was using atan2 for orthogonal system to get two rotations, but in this cases axis A is not perpendicular to C.
double RotationC = Math.Atan2(V_.X, V_.Y);
double RotationA = Math.Atan2(Math.Sqrt(V_.X * V_.X + V_.Y * V_.Y), V_.Z);
I am looking for an algorithm to check if a point is coplanar with a given 3D plane, defined out of three vertices, while minimizing floating point errors.
I would like to minimize the amount of multiplications and division to mitigate floating point errors.
My implementation uses floats, I cannot go double.
I cannot use an external library.
My current method suffers from these errors:
I have code defining a plane using the general form of the plane equation:
ax + by + cz + d = 0
I compute these coefficients using three 3D vertices v0, v1 and v2 as follow:
// Pseudo-code to define a plane (with class Vector3 defining a vector in 3D)
Vector3 A = v1 - v0;
Vector3 B = v2 - v0;
Vector3 N = cross_product(A,B); // Normal vector
N.Normalize(); // Unit normal vector storing coefs. a, b, c
float d = dot_product(N,v0);
To check if another vertex p is coplanar, I plug the point into the plane equation and check if the result is 0:
// Pseudo-code for coplanar test:
bool is_coplanar()
{
float res = N.x()*p.x() + N.y()*p.y() + N.z()*p.z() - d;
return true if res is "almost" null; // "almost" is: abs(res)<EPSILON
}
My code fails in this case:
v0 = [-8.50001907, 0, 323]
v1 = [8.49998093, 0, 323]
v2 = [-8.50001907, 1.49999976, 322.598083]
Then the plane coefficients are:
N = [-0, 0.258814692, 0.965926945]
d = 311.994415
And when I plug the point v2, I find a result "far" from 0 (although v2 was used to define the plane):
res = -3.05175781e-05
My EPSILON is currently 1e-5.
Tested on compiler qcc 4.4.2 (QNX Momentics, similar to gcc). With no optimization -O0.
Such geometric predicates suffer in a lot of ways from floating point errors. The only industrial strength solution is to use adaptable arithmetic filtering (provided that a robust implementation of the coplanar test is not covering you).
Luckily such implementations (that would take quite some time to write) are already available. In the previous link the orient3d predicate does what you need: Given 3 plane forming points, decide whether a 4th one lies above,below or on the plane
If such an implementation is an overkill, check the simple one. It offers 4 in total:
orient3dfast() Approximate 3D orientation test. Nonrobust.
orient3dexact() Exact 3D orientation test. Robust.
orient3dslow() Another exact 3D orientation test. Robust.
orient3d() Adaptive exact 3D orientation test. Robust.
Disclaimer: The code listing is provided as a tutorial of the mathematical concepts and programming techniques needed to reach a robust solution. I'm neither suggesting nor implying copy-pasting anything.
I am trying to look for an equivalent opencv function for interp2 and I understand that
cv::remap is a good way of doing this.
However, if I have the following:
f2 = interp2( x, y, f, x2, y2, 'bicubic' );
where x, y, x2 and y2 are all (say m x n) matrices, I am not sure how to use cv::remap for this.
How would I use remap for this? I know I have to convert it to a map ... but I'm unable to do so.
And,is there anything else that could do interp2 the way the matlab function does it?
In case you didn't find your answer yet, this is how you should use it.
remap(f,f2,x2,y2,CV_INTER_CUBIC);
The function remap supposes that you're working on exactly the grid where f is defined so no need to pass the x,y monotonic coordinates. I'm almost sure that the matrices cannot be CV_64F (double) so, take that into account.
interp2 is interpolator - if you get x,y and f values for some mesh it gives you the value f2 for x2 and y2.
remap - wraps your mesh by moving x and y coordinates acording to the deformation maps.
if you want interpolate regular mesh then use scaling (cv::resize for example).
If data is scattered then you can use Delaunay triangulation and then barycentric interpolation as variant or inverse distance weighting.
I have been working on Unigine and been trying to code a flight program for weeks, I need to find the direction between two dummy nodes so I can use this direction to rotate the wings of the aircraft. Any explanation would be appreciated.
First you have to calculate the length of the distance between P1 and P2.
distance = abs(P2(y) - P1(y))
Then you can use the angular functions to calculate the angle.
a = sin(distance / length(P12))
As already stated in the comments, the vector from P1 to P2 is given by P = P2 - P1.
The direction can be attained in two ways.
1. Directly compute angle = tan_inverse( P.y() / P.x() ).
In this method however, 1st quadrant and 3rd quadrant are treated in the same way as the signs cancel out.
2.You can normalize this vector to get a unit vector. This is the preferred way since it alleviates the quadrant issues.
P(normalized) = P / (mod(p))
Now you can get the projection of any vector in this direction by just calculating the dot-product by this unit vector.
I just randomly came across this question and therefore it might be useful for someone else to read some more useful information here, regardless of the fact that this question has been asked years ago.
Currently, there is no accepted answer, which could mean that it wasn't very clear what the OP was asking so I'll confront two problems here.
Finding the direction of a vector
I am not very fluent in C++ so I'll
go one abstraction below and write C. Consider the following function
double get_vector_direction (vector v)
{
return atan2(v.q.y - v.p.y, v.q.x - v.p.x); /* atan(ratio) */
}
As simple as this! Also, I like to define vectors this way:
typedef struct POINT { double x, y; } point;
typedef struct VECTOR { point p, q; } vector;
the atan family of functions returns the inverse tangent and this function returns the direction of a vector, which is the measure of the angle it makes with a horizontal line (in radians).
There is a diagram in the answers here that shows the horizontal line as the x component of a vector. It's a simplistic implementation of a Cartesian to Polar coordinates conversion.
Finding the distance between the initial and terminal point
You may also want to know the magnitude of the vector, which could be obtained using the distance formula: sqrt(pow(v.q.x-v.p.x, 2)+pow(v.q.y-v.p.y, 2));
The two functions make up direction() and distance() which are the two most essential functions when dealing with algebra during game development. I would also recommend vectoradd and maybe even vectorsub and of course, radtodeg to convert radians to degrees if the angle is to be showed to the player.
If under the direction you mean angle w.r.t. an arbitrary vector (let it be (p1,p3)), then you can calculate the angle using:
angle = arcos( (p1,p2) * (p1,p3) / (modulus((p1,p2)) * modulus((p1,p3)) ))
where * is the dot product. The angle will be in radians. To change it to degrees you can multiply it by 180/PI (PI=3.1415926...). Modulus is length of vector:
modulus((p1,p2))=square root((p1,p2) * (p1,p2)).
The answer is rather about math than C++ but the implementation of the simple formula is straightforward.