cv2 warpAffine, matrix transformation - cv2

The problem in this link: Group multiple barcodes on a single sticker together from an image with multiple stickers using python
H = np.eye(3)
H[0:2,2] = tl # origin
H[:2,0] = vx / lx
H[:2,1] = vy / ly
dst = cv.warpAffine(src=image,
M=H[:2], dsize=(int(lx), int(ly)),
flags=cv.INTER_LINEAR | cv.WARP_INVERSE_MAP)
Could anyone can explain this part of code? What I understand on warpAffine, the M value is matrix transformation, but why it uses the top left origin coordinate and the ratio of dividing the width by length?

Related

Arc length between points on Archimedean spiral using MATLAB or R

I'm needing to derive xy values and calculate arc length between each xy value, so a length value for every value in i as generated by the attached code below (excluding the origin). The points follow an Archimedean spiral path. I don't have MATLAB and am using R, but the closest I've found that I can interpret was a MATLAB example found here with credit to Jos. Below is a modified version of the MATLAB script to generate the xy data:
r = 938; %outer radius
a = 0; %inner radius
b = 7; %increment per rev
n = (r - a)./(b); %number of revolutions
th = 2*n*pi; %angle
i = linspace(0,n,n*1000);
x = (a+b*i).* cos(2*pi*i);
y = (a+b*i).* sin(2*pi*i);
and the R equivalent:
r <- 938 # outer radius
a <- 0 # inner radius
b <- 7 # increment per revolution
n <- (r - a)/b # number of revolutions
th <- 2*n*pi # angle
i <- seq(0, n, length.out = n*1000) # number of points per revolution
x <- (a+b*i) * cos(2*pi*i)
y <- (a+b*i) * sin(2*pi*i)
My assumption is that the easiest way to derive arc length between every point is to coerce i, x, and y into a MATLAB table (dataframe in R). The closest I've found for calculating arc length is this formula for calculating the total length. I'm unable to interpret math notation, so am not sure how to implement it or how to modify it to calculate arc length between every point. Using the example of the first spiral in the link above for calculating total length I tried:
sqrt((5 + 0.1289155 * 47.12389)^2 + (0.1289155)^2) * 47.12389
The link above says the result should be 378.8 but my attempt returns 521.9324. So in sum, how is the arc length between points derived in MATLAB or R?
The exact formula for the length, with your notations for a (start radius), r (end radius) and b (increment per revolutions) reduces to
(note that in order to preserve the OP notation, there are two different meanings of the same r symbol, that might be frown upon by some)
That formula can be implemented this way
r <- 938 # outer radius
a <- 0 # inner radius
b <- 7 # increment per revolution
A <- 2 * pi / b
fa <- sqrt(1 + A^2 * a^2)
fr <- sqrt(1 + A^2 * r^2)
int_r <- (A*r*fr - log(-(A*r)+fr))/(2*A)
int_a <- (A*a*fa - log(-(A*a)+fa))/(2*A)
spiralLen <- int_r - int_a #exact formula
394877.5
you can also use numerical (approximative) integration in R stats integrate to evaluate the integral
integrate(function(r){sqrt(4*pi^2*r^2/b^2+1)}, a, r)
394877.3 with absolute error < 5.8
Another method, that gives a rather rough approximation, but is a very good verification because it doesn't use any theoretical considerations, but just takes the data you generated - and sums up the length of the segments of all consecutive points in the data:
dx <- x[2:length(x)] - x[1:length(x)-1]
dy <- y[2:length(x)] - y[1:length(x)-1]
len_approx = sum(sqrt(dx^2 + dy^2))
394876.8
As for plotting, in R, since you already have a set of points, it seems the very basic application of plot function does the job
plot(x, y, type="l")

How to find 3D points coordinates in a perpendicular plane to a given vector

I have two points in a 3d space, one point is (x,0,z) and the other one is the origin (0,0,0), through those points there is a passing line with length L that is starting from the first point and continuing after the origin point, in the end of this line there is a perpendicular (to the line) flat board with dimensions of W x H, the line ends in the middle of this board.
Assume that x,z,L,H,W are given, I need a way to find all the 3D points coordinates where those points forming a pixels image over the board (meaning each point has a distance of 1 from its left, right, top, bottom neighboring points).
Attached a pretty ugly drawing :) I made trying to illustrate the problem (I marked the pixels points with two question marks but I need them all).
Thanks.
It is possible to define that plane. But there is no selected direction to build a grid uniquelly.
Let we choose OY direction as base (because normal has zero Y-component).
So we have:
Normal vector N = (xx, 0, zz) //I renamed values to avoid confusion with coordinate
variables
Unit normal vector n = (nx, 0, nz), where
nx = xx / Sqrt(xx*xx+zz*zz)
nz = zz / Sqrt(xx*xx+zz*zz)
Base point
B = (bx, 0, bz) = (xx - nx * L, 0, zz - nz * L)
Unit base vector in the plane
dy = (0, 1, 0)
Another base vector
dc = dy x n //vector product
= (-bz, 0, bx)
Now it is possible to generate a grid, using integer indexes i, j in ranges (-W/2..W/2) and (-H/2.. H/2). Grid nodes coordinates:
x(i, j) = bx - j * bz
y(i, j) = 0 + i
z(i, j) = bz + j * bx

Find the New Position of Vertices Given a Rotation Matrix

I have two triangles facing in arbitrary directions. I have the forward vector for both triangles, and I want to align each of the forward vectors to face the same direction. I only have the ability to do rotations about the world x, y and z axis (The software API I am using is very limited).
So, let A = forward vector of the first triangle, and B = forward vector of the second triangle.
I am able to find the Rotation Matrix using this equation:
v = B X A
s = ||v||
c = A dot B
vx = skew-symmetric cross-product matrix of v
R = I + [vx] + [vx]^2 * (1-c)/s^2
I am able to find R.
I am not sure how to use R so that I can move the vertices of triangle B such that the triangle B and triangle A are facing in the same direction.
Picture for Reference:
Thank you all in advance for the help.
You can use normalized vector v as an axis and the angle T between A and B to compute a rotation matrix (right-hand rule) from an axis-angle in the following way:
| cosT + x*x*(1 - cosT) y*x*(1 - cosT) + z*sinT z*x*(1 - cosT) - y*sinT |
| x*y*(1 - cosT) - z*sinT cosT + y*y*(1 - cosT) z*y*(1 - cosT) + x*sinT |
| x*z*(1 - cosT) + y*sinT y*z*(1 - cosT) - x*sinT cosT + z*z*(1 - cosT) |
x, y, z values refers to normalized v coordinates.
Now, you apply this matrix to each vertex in B.
PS: This matrix is in column-major order, you might want to transpose it.
You can do this more easily by calculating the angle between to forward vectors first:
theta = arccos(dot(A, B)/(length(A)*length(B)))
This gives you the angle by which you want to rotate your triangle. Then you can put this angle in the 2D rotation matrix and use it to calculate each vertex's new position:
vector2 newPos = R*oldPos, Where R is the rotation matrix

Minimal perpendicular vector between a point and a line

Okay so I'm trying to get a separating axis theorem algorithm to work (for collision detection) and I need to find the minimal perpendicular vector between a point and a line. I'm not asking for the minimum perpendicular distance (which I know how to find) but rather the vector that would have the same magnitude as that distance and that goes from an arbitrary point and a point on the line. I know the location of the point, a point on the line, and a unit vector giving the direction of the line.
What I tried doing was first finding the minimal distance between the point and the line.
The next part is confusing but I:
1) Found the vector between the point and the point on the line I know
2) Found the vector between the point on the line and the point on the line plus the unit vector giving the direction of the line
3) Took the cross product of these two vectors (I'll call this cross product A)
4) Took the cross product of the unit vector giving the direction of the line and the vector from cross product A (I'll call this cross product B)
5) Normalized cross product B
6) Scaled cross product B by the minimal distance
Anyways that whole attempt failed miserably. Can anyone tell me how I am supposed to find this vector?
If I understood your question correctly, I believe this is what you're looking for:
P - point
D - direction of line (unit length)
A - point in line
X - base of the perpendicular line
P
/|
/ |
/ v
A---X----->D
(P-A).D == |X-A|
X == A + ((P-A).D)D
Desired perpendicular: X-P
where the period represents the dot product and |X-A| means magnitude.
From the above figure, you have:
q = p + s --> s = q - p = q - (p2-p1) = q + p1 - p2
==> s^ = |q - p2 - p1| / |s| (unitary vector)
Also: |s| = |q| sin c = |q|sin(b-a)
b = arcsin (qy / |q|); a = arcsin( p1y / |p1| )
where: |q| = (qx^2 + qy^2)^1/2

formula for best approximation for center of 2D rotation with small angles

This is not a homework. I am asking to see if problem is classical (trivial) or non-trivial. It looks simple on a surface, and I hope it is truly a simple problem.
Have N points (N >= 2) with
coordinates Xn, Yn on a surface of
2D solid body.
Solid body has some small rotation (below Pi/180)
combined with small shifts (below 1% of distance between any 2 points of N). Possibly some small deformation too (<<0.001%)
Same N points have new coordinates named XXn, YYn
Calculate with best approximation the location of center of rotation as point C with coordinates XXX, YYY.
Thank you
If you know correspondence (i.e. you know which points are the same before and after the transformation), and you choose to allow scaling, then the problem is a set of linear equations. If you have 2 or more points then you can find a least-squares solution with little difficulty.
For initial points (xi,yi) and transformed points (xi',yi') you have equations of the form
xi' = a xi + b yi + c
yi' =-b xi + a yi + d
which you can rearrange into a linear system
A x = y
where
A = | x1 y1 1 0 |
| y1 -x1 0 1 |
| x2 y2 1 0 |
| y2 -x2 0 1 |
| ... |
| xn yn 1 0 |
| yn -xn 0 1 |
x = | a |
| b |
| c |
| d |
y = | x1' |
| y1' |
| x2' |
| y2' |
| ... |
| xn' |
| yn' |
the standard "least-squares" form of which is
A^T A x = A^T y
and has the solution
x = (A^T A)^-1 A^T y
with A^T as the transpose of A and A^-1 as the inverse of A. Normally you would use an SVD or QR decomposition to compute the solution as they ought to be more stable and less computationally intensive than the inverse.
Once you've found x (and so the four elements of the transformation a, b, c and d) then the various elements of the transformation are given by
scale = sqrt(a*a+b*b)
rotation = atan2(b,a)
translation = (c,d)/scale
If you don't include scaling then the system is non-linear, and requires an iterative solution (but isn't too difficult to solve). If you do not know correspondence then the problem is substantially harder, for small transformations something like iterated closest point works, for large transformations it's a lot harder.
Edit: I forgot to include the centre of rotation. A rotation theta about an arbitrary point p is a sequence
translate(p) rotate(theta) translate(-p)
if you expand it all out as an affine transformation (essentially what we have above) then the translation terms come to
dx = px - cos(theta)*px + sin(theta)*py
dy = py - sin(theta)*px - cos(theta)*py
we know theta (rotation), dx (c) and dy (d) from the equations above. With a little bit of fiddling we can solve for px and py
px = 0.5*(dx - sin(theta)*dy/(1-cos(theta)))
py = 0.5*(dy + sin(theta)*dx/(1-cos(theta)))
You'll notice that the equations are undefined if theta is zero, because there is no centre of rotation when no rotation is performed.
I think I have all that correct, but I don't have time to double check it all right now.
Look up the "Kabsch Algorithm". It is a general-purpose algorithm for creating rotation matrices using N known pairs. Kabsch created it to assist denoising stereo photographs. You rotate a feature in picture A to picture B, and if it is not in the target position, the feature is noise.
http://en.wikipedia.org/wiki/Kabsch_algorithm
See On calculating the finite centre of rotation for
rigid planar motion for a relatively simple solution. I say "relatively simple" because it still uses things like psuedo-inverses and SVD (singular value decomposition). And here's a wikipedia article on Instant centre of rotation. And another paper: ESTIMATION OF THE FINITE CENTER OF ROTATION IN PLANAR MOVEMENTS.
If you can handle stiffer stuff, try Least Squares Estimation of Transformation Parameters Between Two Point Patterns.
First of all, the problem is non-trivial.
A "simple" solition. It works best when the polygon resembles circle, and points are distributed evenly.
iterate through N
For both old and new dataset, find the 2 farthest points of the point N.
So now you have the triangle before and after the transformation. Use the clockwise direction from the center of each triangle to number its vertices as [0] (=the N-th point in the original dataset), [1], and [2] (the 2 farthest points).
Calculate center of rotation, and deformation (both x and y) of this triangle. If the deformation is more then your 0.001% - drop the data for this triangle, otherwise save it.
Calculate the average for the centers of rotation.
The right solution: define the function Err(Point BEFORE[N], Point AFTER[N], double TFORM[3][3]), where BEFORE - constant old data points, AFTER - constant new data points, TFORM[3][3] affine transformation matrix, Err(...) function that returns the scalar error value, 0.0 when the TFORM translated BEFORE to exact AFTER, or some >0.0 error value. Then use any numeric math you want to find the minimum of the Err(TFORM): e.g. gradient search.
Calculate polygon centers O1 and O2. Determine line formulae for O1 with (X0, Y0) and O2 with (XX0, YY0). Find intersection of lines to get C.
If I understand your problem correctly, this could be solved in this way:
find extremities (furthest points, probably on several axises)
scale either one to match
their rotation should now be trivial (?)
Choose any 2 points on the body, P1, P2, before and after rotation. Find vectors between these before and after points. Cross these vectors with a vector normal to the plane of rotation. This results in two new vectors, the intersection of the lines formed by the initial points and these two new vectors is the center of the rotation.
{
if P1after = P1before return P1after
if P2after = P2before return P2after
Vector V1 = P1after - P1before
Vector V2 = P2after - P2before
normal = Vn // can be messy to create for arbitrary 3d orientation but is simple if you know orientation, for instance, normal = (0,0,1) for an object in the x,y plane)
Vector VL1 = V1 x Vn //Vector V1 cross product with Vn
Vector VL2 = V2 x Vn
return intersectLines(P1after,VL1,P2after,VL2) //Center of rotation is intersection of two lines
}
intersectLines(Point P1, Vector V1, Point P2, Vector V2)
{
//intersect two lines using point, direction form of a line
//returns a Point
}

Resources