Related
I have a 3D geometry problem and I am not certain of the best approach to solve it. I have a model with two boxes, one above the others. They have the same dimension, L (length) * p (depth) * e (thickness), and are separated by a height of h. They are perfectly superposed, with no offset between them.
For each point of my bottom box, I want to get the zenith of all lines that can cross the top box and arrive to this point. It doesn't matter if the line crosses the top box by the top or the side.
The zenith is the angle of "looking up". In our case, a zenith of 0 represents the point directly above the point P, and an angle of 90 is directly looking in front. A zenith of 180 would be looking below the point, but for our use, it's useless. The zeniths we look for are between 0 and 90°.
For a more intuitive visualization, let's say that I have a hole in the ceiling, and that I want to map the zenith of all light that crosses this hole and reaches the floor.
This is what it looks like:
For any point P of the bottom box, I want an array containing the zeniths of all "rays" that cross the top box before arriving on P. The red lines are the "edges", the last zeniths I would get for each corner.
I am working on a way to code it in MATLAB and I was wondering if there was a better algorithm that I am not seeing. My approach, in pseudocode, would be this:
bottomBox = [1:L, 1:p, 1:e];
topBox = [1:L, 1:p, 1+h:e+h];
results = zeros(L:p) * NaN; % Array of results, one per "case" on the bottom box
zeniths = zeros(L:p) * NaN; % Array of zeniths for each result case
for i = 1:L
for j = 1:p % Browsing the bottom box case by case
for k = 1:L
for l = 1:p
for m = 1:e % For each bottom box case, browsing the top box case by case
p1 = topBox(k,l,m); % p1 is each case on the top box
p2 = bottomBox(i,j,1); % p2 is the current bottom box case, z doesn't mattter
p3 = topBox(i,j,m); % p3 is the projection of p2 on the top box (zenith = 0)
v1 = p1 - p2;
v2 = p3 - p2;
zeniths(k,l) = rad2deg(atan2(norm(cross(p1, p2)), dot(p1, p2)));
end
end
end
results(i,j) = zeniths;
end
end
I tried to implement this and I couldn't get it to work. More specifically, the angle calculation doesn't seem to work, I have an error stating:
Error using cross;
A and B must be of length 3 in the dimension in which the cross product is taken.
I am looking for advice on how to build the algorithm.
Please tell me if the question is better suited for another StackExchange community, such as Math.
I'll get you started showing you one way to do it for 1 point and I'll let you build the final loop to do the calc for all your points.
As expressed in the comment, for the purpose of these calculations, you do not need to consider the thickness of your plates, you can model them simply with two parallel planes separated by a distance H.
I don't know the size of your plates nor the grid size you want so I'll keep it simple for this example:
H = 5 ; % distance between the planes
[X,Y] = meshgrid(-3:3,-2:2) ;
GridSize = size(X) ;
Zb = zeros(GridSize) ;
Zt = zeros(GridSize) + H ;
This gives you 4 matrices, defining 2 planes. The bottom plane is composed of [X,Y,Zb] and the top plane is formed by [X,Y,Zt].
If you want to visualise them, you can run the following code (optional):
%% Display planes
figure ;
ht = surf(X,Y,Zt, 'FaceColor',[.8 .8 .8],'DisplayName','Top plate') ;
hold on
hb = surf(X,Y,Zb, 'FaceColor',[.6 .6 .6],'DisplayName','Bottom plate') ;
xlabel('X') ; ylabel('Y') ; zlabel('Z') ;
axis equal ; legend show
Now for the rest of the example, I selected a point P, at coordinate [-2,1,0]. This choice is completely arbitrary, just for the example. In your final algorythm you will still have to loop over several points Pi (although remember that your problem is symetric so if your domain is too large you can reduce your computations by using the symetries of your model).
%% This will have to be embedded into a loop over the points Pi
% Assuming points P=(-2,1,0)
p = [-2;1;0] ;
zn = [0;0;1] ; % unitary vector, oriented Oz
dx = X - p(1) ; % `x` distance between all points of the plane and P
dy = Y - p(2) ; % `y` distance between all points of the plane and P
dz = zeros(size(X)) + H ; % `z` distance (all the same)
V = [dx(:) dy(:) dz(:)].' ; % to obtain list of vector V = [dx;dy;dz] ;
nv = size(V,2) ; % number of points/angle to calculate
zenith = zeros(nv,1) ; % preallocate result matrix (always good!)
for k=1:nv
% [u] is the vector going from `P` to the current point considered on the top plane
u = V(:,k) ;
% determine the angle between [u] and [zn]
zenith(k) = atan2( norm(cross(u,zn)) , dot(u,zn) ) ;
end
% Reshape "zenith" from vector to matrix so it matches the base grid system
zenith = reshape( zenith , GridSize ) ;
You now have, for this point P, a matrix of angle with every other point of the top plane:
>> rad2deg(zenith)
ans =
32.31 30.96 32.31 35.80 40.32 45.00 49.39
24.09 21.80 24.09 29.50 35.80 41.81 47.12
15.79 11.31 15.79 24.09 32.31 39.51 45.56
11.31 0 11.31 21.80 30.96 38.66 45.00
15.79 11.31 15.79 24.09 32.31 39.51 45.56
Once again, completely optionally, if you want to visualise the vectors which were used for the calculations:
for k=1:nv
hp(k) = plot3([p(1) X(k)],[p(2) Y(k)],[0 H],'Marker','o','MarkerFaceColor','k') ;
end
will yield:
Now for your final result, remember you have a 2D matrix for each point P of your bottom plane, so your final result will either be a collection of 2D matrices or a large 3D matrix.
Zenith angle is just
atan2(h, sqrt(dx^2+dy^2))
where dx, dy are coordinate differences along L and p axes (i-k and j-l in your loops)
Perhaps h+m (m as your variable for m = 1:e) instead of h if you need points inside top box
I found this challenge problem which states the following :
Suppose that there are n rectangles on the XY plane. Write a program to calculate the maximum possible number of rectangles that can be crossed with a single straight line drawn on this plane.
I have been brainstorming for quite a time but couldn't find any solution.
Maybe at some stage, we use dynamic programming steps but couldn't figure out how to start.
Here is a sketch of an O(n^2 log n) solution.
First, the preliminaries shared with other answers.
When we have a line passing through some rectangles, we can translate it to any of the two sides until it passes through a corner of some rectangle.
After that, we fix that corner as the center of rotation and rotate the line to any of the two sides until it passes through another corner.
During the whole process, all points of intersection between our line and rectangle sides stayed on these sides, so the number of intersections stayed the same, as did the number of rectangles crossed by the line.
As a result, we can consider only lines which pass through two rectangle corners, which is capped by O(n^2), and is a welcome improvement compared to the infinite space of arbitrary lines.
So, how do we efficiently check all these lines?
First, let us have an outer loop which fixes one point A and then considers all lines passing through A.
There are O(n) choices of A.
Now, we have one point A fixed, and want to consider all lines AB passing through all other corners B.
In order to do that, first sort all other corners B according to the polar angle of AB, or, in other words, angle between axis Ox and vector AB.
Angles are measured from -PI to +PI or from 0 to 2 PI or otherwise, the point in which we cut the circle to sort angles can be arbitrary.
The sorting is done in O(n log n).
Now, we have points B1, B2, ..., Bk sorted by the polar angle around point A (their number k is something like 4n-4, all corners of all rectangles except the one where point A is a corner).
First, look at the line AB1 and count the number of rectangles crossed by that line in O(n).
After that, consider rotating AB1 to AB2, then AB2 to AB3, all the way to ABk.
The events which happen during the rotation are as follows:
When we rotate to ABi, and Bi is the first corner of some rectangle in our order, the number of rectangles crossed increases by 1 as soon as the rotating line hits Bi.
When we rotate to ABj, and Bj is the last corner of some rectangle in our order, the number of rectangles crossed decreases by 1 as soon as the line rotates past Bj.
Which corners are first and last can be established with some O(n) preprocessing, after the sort, but before considering the ordered events.
In short, we can rotate to the next such event and update the number of rectangles crossed in O(1).
And there are k = O(n) events in total.
What's left to do is to track the global maximum of this quantity throughout the whole algorithm.
The answer is just this maximum.
The whole algorithm runs in O(n * (n log n + n + n)), which is O(n^2 log n), just as advertised.
Solution
In the space of all lines in the graph, the lines which pass by a corner are exactly the ones where the number or intersections is about to decrease. In other words, they each form a local maximum.
And for every line which passes by at least one corner, there exist an associated line that passes by two corners that has the same number of intersections.
The conclusion is that we only need to check the lines formed by two rectangle corners as they form a set that fully represents the local maxima of our problem. From those we pick the one which has the most intersections.
Time complexity
This solution first needs to recovers all lines that pass by two corners. The number of such line is O(n^2).
We then need to count the number of intersections between a given line and a rectangle. This can obviously be done in O(n) by comparing to each rectangles.
There might be a more efficient way to proceed, but we know that this algorithm is then at most O(n^3).
Python3 implementation
Here is a Python implementation of this algorithm. I oriented it more toward readability than efficiency, but it does exactly what the above defines.
def get_best_line(rectangles):
"""
Given a set of rectangles, return a line which intersects the most rectangles.
"""
# Recover all corners from all rectangles
corners = set()
for rectangle in rectangles:
corners |= set(rectangle.corners)
corners = list(corners)
# Recover all lines passing by two corners
lines = get_all_lines(corners)
# Return the one which has the highest number of intersections with rectangles
return max(
((line, count_intersections(rectangles, line)) for line in lines),
key=lambda x: x[1])
This implementation uses the following helpers.
def get_all_lines(points):
"""
Return a generator providing all lines generated
by a combination of two points out of 'points'
"""
for i in range(len(points)):
for j in range(i, len(points)):
yield Line(points[i], points[j])
def count_intersections(rectangles, line):
"""
Return the number of intersections with rectangles
"""
count = 0
for rectangle in rectangles:
if line in rectangle:
count += 1
return count
And here are the class definition that serve as data structure for rectangles and lines.
import itertools
from decimal import Decimal
class Rectangle:
def __init__(self, x_range, y_range):
"""
a rectangle is defined as a range in x and a range in y.
By example, the rectangle (0, 0), (0, 1), (1, 0), (1, 1) is given by
Rectangle((0, 1), (0, 1))
"""
self.x_range = sorted(x_range)
self.y_range = sorted(y_range)
def __contains__(self, line):
"""
Return whether 'line' intersects the rectangle.
To do so we check if the line intersects one of the diagonals of the rectangle
"""
c1, c2, c3, c4 = self.corners
x1 = line.intersect(Line(c1, c4))
x2 = line.intersect(Line(c2, c3))
if x1 is True or x2 is True \
or x1 is not None and self.x_range[0] <= x1 <= self.x_range[1] \
or x2 is not None and self.x_range[0] <= x2 <= self.x_range[1]:
return True
else:
return False
#property
def corners(self):
"""Return the corners of the rectangle sorted in dictionary order"""
return sorted(itertools.product(self.x_range, self.y_range))
class Line:
def __init__(self, point1, point2):
"""A line is defined by two points in the graph"""
x1, y1 = Decimal(point1[0]), Decimal(point1[1])
x2, y2 = Decimal(point2[0]), Decimal(point2[1])
self.point1 = (x1, y1)
self.point2 = (x2, y2)
def __str__(self):
"""Allows to print the equation of the line"""
if self.slope == float('inf'):
return "y = {}".format(self.point1[0])
else:
return "y = {} * x + {}".format(round(self.slope, 2), round(self.origin, 2))
#property
def slope(self):
"""Return the slope of the line, returning inf if it is a vertical line"""
x1, y1, x2, y2 = *self.point1, *self.point2
return (y2 - y1) / (x2 - x1) if x1 != x2 else float('inf')
#property
def origin(self):
"""Return the origin of the line, returning None if it is a vertical line"""
x, y = self.point1
return y - x * self.slope if self.slope != float('inf') else None
def intersect(self, other):
"""
Checks if two lines intersect.
Case where they intersect: return the x coordinate of the intersection
Case where they do not intersect: return None
Case where they are superposed: return True
"""
if self.slope == other.slope:
if self.origin != other.origin:
return None
else:
return True
elif self.slope == float('inf'):
return self.point1[0]
elif other.slope == float('inf'):
return other.point1[0]
elif self.slope == 0:
return other.slope * self.origin + other.origin
elif other.slope == 0:
return self.slope * other.origin + self.origin
else:
return (other.origin - self.origin) / (self.slope - other.slope)
Example
Here is a working example of the above code.
rectangles = [
Rectangle([0.5, 1], [0, 1]),
Rectangle([0, 1], [1, 2]),
Rectangle([0, 1], [2, 3]),
Rectangle([2, 4], [2, 3]),
]
# Which represents the following rectangles (not quite to scale)
#
# *
# *
#
# ** **
# ** **
#
# **
# **
We can clearly see that an optimal solution should find a line that passes by three rectangles and that is indeed what it outputs.
print('{} with {} intersections'.format(*get_best_line(rectangles)))
# prints: y = 0.50 * x + -5.00 with 3 intersections
(Edit of my earlier answer that considered rotating the plane.)
Here's sketch of the O(n^2) algorithm, which combines Gassa's idea with Evgeny Kluev's reference to dual line arrangements as sorted angular sequences.
We start out with a doubly connected edge list or similar structure, allowing us to split an edge in O(1) time, and a method to traverse the faces we create as we populate a 2-dimensional plane. For simplicity, let's use just three of the twelve corners on the rectangles below:
9| (5,9)___(7,9)
8| | |
7| (4,6)| |
6| ___C | |
5| | | | |
4| |___| | |
3| ___ |___|(7,3)
2| | | B (5,3)
1|A|___|(1,1)
|_ _ _ _ _ _ _ _
1 2 3 4 5 6 7
We insert the three points (corners) in the dual plane according to the following transformation:
point p => line p* as a*p_x - p_y
line l as ax + b => point l* as (a, -b)
Let's enter the points in order A, B, C. We first enter A => y = x - 1. Since there is only one edge so far, we insert B => y = 5x - 3, which creates the vertex, (1/2, -1/2) and splits our edge. (One elegant aspect of this solution is that each vertex (point) in the dual plane is actually the dual point of the line passing through the rectangles' corners. Observe 1 = 1/2*1 + 1/2 and 3 = 1/2*5 + 1/2, points (1,1) and (5,3).)
Entering the last point, C => y = 4x - 6, we now look for the leftmost face (could be an incomplete face) where it will intersect. This search is O(n) time since we have to try each face. We find and create the vertex (-3, -18), splitting the lower edge of 5x - 3 and traverse up the edges to split the right half of x - 1 at vertex (5/3, 2/3). Each insertion has O(n) time since we must first find the leftmost face, then traverse each face to split edges and mark the vertices (intersection points for the line).
In the dual plane we now have:
After constructing the line arrangement, we begin our iteration on our three example points (rectangle corners). Part of the magic in reconstructing a sorted angular sequence in relation to one point is partitioning the angles (each corresponding with an ordered line intersection in the dual plane) into those corresponding with a point on the right (with a greater x-coordinate) and those on the left and concatenating the two sequences to get an ordered sequence from -90 deg to -270 degrees. (The points on the right transform to lines with positive slopes in relation to the fixed point; the ones on left, with negative slopes. Rotate your sevice/screen clockwise until the line for (C*) 4x - 6 becomes horizontal and you'll see that B* now has a positive slope and A* negative.)
Why does it work? If a point p in the original plane is transformed into a line p* in the dual plane, then traversing that dual line from left to right corresponds with rotating a line around p in the original plane that also passes through p. The dual line marks all the slopes of this rotating line by the x-coordinate from negative infinity (vertical) to zero (horizontal) to infinity (vertical again).
(Let's summarize the rectangle-count-logic, updating the count_array for the current rectangle while iterating through the angular sequence: if it's 1, increment the current intersection count; if it's 4 and the line is not directly on a corner, set it to 0 and decrement the current intersection count.)
Pick A, lookup A*
=> x - 1.
Obtain the concatenated sequence by traversing the edges in O(n)
=> [(B*) 5x - 3, (C*) 4x - 6] ++ [No points left of A]
Initialise an empty counter array, count_array of length n-1
Initialise a pointer, ptr, to track rectangle corners passed in
the opposite direction of the current vector.
Iterate:
vertex (1/2, -1/2)
=> line y = 1/2x + 1/2 (AB)
perform rectangle-count-logic
if the slope is positive (1/2 is positive):
while the point at ptr is higher than the line:
perform rectangle-count-logic
else if the slope is negative:
while the point at ptr is lower than the line:
perform rectangle-count-logic
=> ptr passes through the rest of the points up to the corner
across from C, so intersection count is unchanged
vertex (5/3, 2/3)
=> line y = 5/3x - 2/3 (AC)
We can see that (5,9) is above the line through AC (y = 5/3x - 2/3), which means at this point we would have counted the intersection with the rightmost rectangle and not yet reset the count for it, totaling 3 rectangles for this line.
We can also see in the graph of the dual plane, the other angular sequences:
for point B => B* => 5x - 3: [No points right of B] ++ [(C*) 4x - 6, (A*) x - 1]
for point C => C* => 4x - 6: [(B*) 5x - 3] ++ [(A*) x - 1]
(note that we start at -90 deg up to -270 deg)
How about the following algorithm:
RES = 0 // maximum number of intersections
CORNERS[] // all rectangles corners listed as (x, y) points
for A in CORNERS
for B in CORNERS // optimization: starting from corner next to A
RES = max(RES, CountIntersectionsWithLine(A.x, A.y, B.x, B.y))
return RES
In other words, start drawing lines from each rectangle corner to each other rectangle corner and find the maximum number of intersections. As suggested by #weston, we can avoid calculating same line twice by starting inner loop from the corner next to A.
If you consider a rotating line at angle Θ and if you project all rectangles onto this line, you obtain N line segments. The maximum number of rectangles crossed by a perpendicular to this line is easily obtained by sorting the endpoints by increasing abscissa and keeping a count of the intervals met from left to right (keep a trace of whether an endpoint is a start or an end). This is shown in green.
Now two rectangles are intersected by all the lines at an angle comprised between the two internal tangents [example in red], so that all "event" angles to be considered (i.e. all angles for which a change of count can be observed) are these N(N-1) angles.
Then the brute force resolution scheme is
for all limit angles (O(N²) of them),
project the rectangles on the rotating line (O(N) operations),
count the overlaps and keep the largest (O(N Log N) to sort, then O(N) to count).
This takes in total O(N³Log N) operations.
Assuming that the sorts needn't be re-done in full for every angle if we can do them incrementally, we can hope for a complexity lowered to O(N³). This needs to be checked.
Note:
The solutions that restrict the lines to pass through the corner of one rectangle are wrong. If you draw wedges from the four corners of a rectangle to the whole extent of another, there will remain empty space in which can lie a whole rectangle that won't be touched, even though there exists a line through the three of them.
We can have an O(n^2 (log n + m)) dynamic-programming method by adapting Andriy Berestovskyy's idea of iterating over the corners slightly to insert the relationship of the current corner vis a vis all the other rectangles into an interval tree for each of our 4n iteration cycles.
A new tree will be created for the corner we are trying. For each rectangle's four corners we'll iterate over each of the other rectangles. What we'll insert will be the angles marking the arc the paired-rectangle's farthest corners create in relation to the current fixed corner.
In the example directly below, for the fixed lower rectangle's corner R when inserting the record for the middle rectangle, we would insert the angles marking the arc from p2 to p1 in relation to R (about (37 deg, 58 deg)). Then when we check the high rectangle in relation to R, we'll insert the interval of angles marking the arc from p4 to p3 in relation to R (about (50 deg, 62 deg)).
When we insert the next arc record, we'll check it against all intersecting intervals and keep a record of the most intersections.
(Note that because any arc on a 360 degree circle for our purpose has a counterpart rotated 180 degrees, we may need to make an arbitrary cutoff (any alternative insights would be welcome). For example, this means that an arc from 45 degrees to 315 degrees would split into two: [0, 45] and [135, 180]. Any non-split arc could only intersect with one or the other but either way, we may need an extra hash to make sure rectangles are not double-counted.)
I have two images which one of them is the Original image and the second one is Transformed image.
I have to find out how many degrees Transformed image was rotated using 3x3 transformation matrix. Plus, I need to find how far translated from origin.
Both images are grayscaled and held in matrix variables. Their sizes are same [350 500].
I have found a few lecture notes like this.
Lecture notes say that I should use the following matrix formula for rotation:
For translation matrix the formula is given:
Everything is good. But there are two problems:
I could not imagine how to implement the formulas using MATLAB.
The formulas are shaped to find x',y' values but I already have got x,x',y,y' values. I need to find rotation angle (theta) and tx and ty.
I want to know the equivailence of x, x', y, y' in the the matrix.
I have got the following code:
rotationMatrix = [ cos(theta) sin(theta) 0 ; ...
-sin(theta) cos(theta) 0 ; ...
0 0 1];
translationMatrix = [ 1 0 tx; ...
0 1 ty; ...
0 0 1];
But as you can see, tx, ty, theta variables are not defined before used. How can I calculate theta, tx and ty?
PS: It is forbidden to use Image Processing Toolbox functions.
This is essentially a homography recovery problem. What you are doing is given co-ordinates in one image and the corresponding co-ordinates in the other image, you are trying to recover the combined translation and rotation matrix that was used to warp the points from the one image to the other.
You can essentially combine the rotation and translation into a single matrix by multiplying the two matrices together. Multiplying is simply compositing the two operations together. You would this get:
H = [cos(theta) -sin(theta) tx]
[sin(theta) cos(theta) ty]
[ 0 0 1]
The idea behind this is to find the parameters by minimizing the error through least squares between each pair of points.
Basically, what you want to find is the following relationship:
xi_after = H*xi_before
H is the combined rotation and translation matrix required to map the co-ordinates from the one image to the other. H is also a 3 x 3 matrix, and knowing that the lower right entry (row 3, column 3) is 1, it makes things easier. Also, assuming that your points are in the augmented co-ordinate system, we essentially want to find this relationship for each pair of co-ordinates from the first image (x_i, y_i) to the other (x_i', y_i'):
[p_i*x_i'] [h11 h12 h13] [x_i]
[p_i*y_i'] = [h21 h22 h23] * [y_i]
[ p_i ] [h31 h32 1 ] [ 1 ]
The scale of p_i is to account for homography scaling and vanishing points. Let's perform a matrix-vector multiplication of this equation. We can ignore the 3rd element as it isn't useful to us (for now):
p_i*x_i' = h11*x_i + h12*y_i + h13
p_i*y_i' = h21*x_i + h22*y_i + h23
Now let's take a look at the 3rd element. We know that p_i = h31*x_i + h32*y_i + 1. As such, substituting p_i into each of the equations, and rearranging to solve for x_i' and y_i', we thus get:
x_i' = h11*x_i + h12*y_i + h13 - h31*x_i*x_i' - h32*y_i*x_i'
y_i' = h21*x_i + h22*y_i + h23 - h31*x_i*y_i' - h32*y_i*y_i'
What you have here now are two equations for each unique pair of points. What we can do now is build an over-determined system of equations. Take each pair and build two equations out of them. You will then put it into matrix form, i.e.:
Ah = b
A would be a matrix of coefficients that were built from each set of equations using the co-ordinates from the first image, b would be each pair of points for the second image and h would be the parameters you are solving for. Ultimately, you are finally solving this linear system of equations reformulated in matrix form:
You would solve for the vector h which can be performed through least squares. In MATLAB, you can do this via:
h = A \ b;
A sidenote for you: If the movement between images is truly just a rotation and translation, then h31 and h32 will both be zero after we solve for the parameters. However, I always like to be thorough and so I will solve for h31 and h32 anyway.
NB: This method will only work if you have at least 4 unique pairs of points. Because there are 8 parameters to solve for, and there are 2 equations per point, A must have at least a rank of 8 in order for the system to be consistent (if you want to throw in some linear algebra terminology in the loop). You will not be able to solve this problem if you have less than 4 points.
If you want some MATLAB code, let's assume that your points are stored in sourcePoints and targetPoints. sourcePoints are from the first image and targetPoints are for the second image. Obviously, there should be the same number of points between both images. It is assumed that both sourcePoints and targetPoints are stored as M x 2 matrices. The first columns contain your x co-ordinates while the second columns contain your y co-ordinates.
numPoints = size(sourcePoints, 1);
%// Cast data to double to be sure
sourcePoints = double(sourcePoints);
targetPoints = double(targetPoints);
%//Extract relevant data
xSource = sourcePoints(:,1);
ySource = sourcePoints(:,2);
xTarget = targetPoints(:,1);
yTarget = targetPoints(:,2);
%//Create helper vectors
vec0 = zeros(numPoints, 1);
vec1 = ones(numPoints, 1);
xSourcexTarget = -xSource.*xTarget;
ySourcexTarget = -ySource.*xTarget;
xSourceyTarget = -xSource.*yTarget;
ySourceyTarget = -ySource.*yTarget;
%//Build matrix
A = [xSource ySource vec1 vec0 vec0 vec0 xSourcexTarget ySourcexTarget; ...
vec0 vec0 vec0 xSource ySource vec1 xSourceyTarget ySourceyTarget];
%//Build RHS vector
b = [xTarget; yTarget];
%//Solve homography by least squares
h = A \ b;
%// Reshape to a 3 x 3 matrix (optional)
%// Must transpose as reshape is performed
%// in column major format
h(9) = 1; %// Add in that h33 is 1 before we reshape
hmatrix = reshape(h, 3, 3)';
Once you are finished, you have a combined rotation and translation matrix. If you want the x and y translations, simply pick off column 3, rows 1 and 2 in hmatrix. However, we can also work with the vector of h itself, and so h13 would be element 3, and h23 would be element number 6. If you want the angle of rotation, simply take the appropriate inverse trigonometric function to rows 1, 2 and columns 1, 2. For the h vector, this would be elements 1, 2, 4 and 5. There will be a bit of inconsistency depending on which elements you choose as this was solved by least squares. One way to get a good overall angle would perhaps be to find the angles of all 4 elements then do some sort of average. Either way, this is a good starting point.
References
I learned about homography a while ago through Leow Wee Kheng's Computer Vision course. What I have told you is based on his slides: http://www.comp.nus.edu.sg/~cs4243/lecture/camera.pdf. Take a look at slides 30-32 if you want to know where I pulled this material from. However, the MATLAB code I wrote myself :)
I have a line, defined by the parameters m, h, where
y = m*x + h
This line goes across a grid (i.e. pixels). For each square (a, b) of the grid (ie the square [a, a+1] x [b, b+1]), I want to determine if the given line crosses this square or not, and if so, what is the length of the segment in the square.
Eventually, I would like to be able to do this with multiple lines at once (ie m and h are vectors, matlab-style), but we can focus on the "simple" case for now.
I figured how to determine if the line crosses the square:
Compute the intersection of the line with the vertical lines x = a and x = a + 1, and the horizontal lines y = b and y = b + 1
Check if 2 of these 4 points are on the square boundaries (ie a <= x < a + 1 and b <= y < b + 1)
If two on these points are on the square, the line crosses it. Then, to compute the length, you simply subtract the two points, and use Pythagorean theorem.
My problem is more on the implementation side: how can I implement that nicely (especially when selecting which 2 points to subtract) ?
Let square be defined by corner points (a,b), (a+1,b), (a,b+1), (a+1,b+1).
Step 1: Check if the line intersects the square...
(a)Substitute each of the coordinates of the 4 corner points, in turn into y - mx - h. If the sign of this evaluation includes both positive and negative terms, go to step b. Otherwise, the line does not intersect the square.
(b)Now there are two sub-cases:
(b1)Case 1: In step (a) you had three points for which y - mx - h evaluated to one sign and the fourth point evaluated to the other sign. Let this 4th point be some (x*,y*). Then the points of intersection are (x*,mx*+h) and ((y*-h)/m,y*).
(b2)Case 2: In step (a) you had two points for which y - mx - h evaluate to one sign and the other two points evaluated to the other sign. Pick any two points that evaluated to the same sign, say (x*,y*) and (x*+1, y*). Then the intersection points are (x*, mx* + h) and (x*+1,m(x*+1) + h).
You would have to consider some degenerate cases where the line touches exactly one of the four corner points and the case where the line lies exactly on one side of the square.
Your proposed method may meet with problems in step (1) when m is 0 (when trying to compute the intersection with y = k).
if m is 0, then it's easy (the line segment length is either 1 or 0, depending on whether b <= h <= b+1).
Otherwise, you can find the intersections with x = a and a+1, say, y_a, y_{a+1} via a substitution. Then, clip y_a and y_{a+1} to between b and b+1 (say, y1 and y2, i.e. y1 = min(b+1, max(b, y_a)) and similarly for y2), and use the proportion abs((y1-y2)/m) * sqrt(m^2+1).
This makes use of the fact that the line segment between x=k and x=k+1 is sqrt(m^2+1), and the difference in y is m, and similarity.
You can do like this:
first find center of square and then find length of diagonal. If the distance from center of square to line is less than length of diagonal then the line will intersect the square. and once you know that line will intersect then you can easily find the intersected line segment. I think you are trying to make weight matrix for Algebraic reconstruction technique. I hope this is correct answer. This was my first answer in stack flow. :)
Trilinear interpolation approximates the value of a point (x, y, z) inside a cube using the values at the cube vertices. I´m trying to do an "inverse" trilinear interpolation. Knowing the values at the cube vertices and the value attached to a point how can I find (x, y, z)? Any help would be highly appreciated. Thank you!
You are solving for 3 unknowns given 1 piece of data, and as you are using a linear interpolation your answer will typically be a plane (2 free variables). Depending on the cube there may be no solutions or a 3D solution space.
I would do the following. Let v be the initial value. For each "edge" of the 12 edges (pair of adjacent vertices) of the cube look to see if 1 vertex is >=v and the other <=v - call this an edge that crosses v.
If no edges cross v, then there are no possible solutions.
Otherwise, for each edge that crosses v, if both vertices for the edge equal v, then the whole edge is a solution. Otherwise, linearly interpolate on the edge to find the point that has a value of v. So suppose the edge is (x1, y1, z1)->v1 <= v <= (x2, y2, z2)->v2.
s = (v-v1)/(v2-v1)
(x,y,z) = (s*(x2-x1)+x1, (s*(y2-y1)+y1, s*(z2-z1)+z1)
This will give you all edge points that are equal to v. This is a solution, but possibly you want an internal solution - be aware that if there is an internal solution there will always be an edge solution.
If you want an internal solution then just take any point linearly between the edge solutions - as you are linearly interpolating then the result will also be v.
I'm not sure you can for all cases. For example using tri-linear filtering for colours where each colour (C) at each point is identical means that wherever you interpolate to you will still get the colour C returned. In this situation ANY x,y,z could be valid. As such it would be impossible to say for definite what the initial interpolation values were.
I'm sure for some cases you can reverse the maths but, i imagine, there are far too many cases where this is impossible to do without knowing more of the input information.
Good luck, I hope someone will prove me wrong :)
The wikipedia page for trilinear interpolation has link to a NASA page which allegedly describes the inversing process - have you had a look at that?
The problem as you're describing it somewhat ill-defined.
What you're asking for basically translates to this: I have a 3D function and I know its values in 8 known points. I'd like to know what is the point in which the function received value V.
The trouble is that in most likelihood there is an infinite number of such points which make a set of surfaces, lines or points, depending on the data.
One way to find this set is to use an iso-surfacing algorithm like Marching cubes.
Let's start with 2d: think of a bilinear hill over a square km,
with heights say 0 10 20 30 at the 4 corners
and a horizontal plane cutting the hill at height z.
Draw a line from the 0 corner to the 30 corner (whether adjacent or diagonal).
The plane must cut this line, for any z,
so all points x,y,z fall on this one line, right ? Hmm.
OK, there are many solutions -- any z plane cuts the hill in a contour curve.
Say we want solutions to be spread out over the whole hill,
i.e. minimize two things at once:
vertical distance z - bilin(x,y),
distance from x,y to some point in the square.
Scipy.optimize.leastsq is one way of doing this, sample code below;
trilinear is similar.
(Optimizing any two things at once requires an arbitrary tradeoff or weighting:
food vs. money, work vs. play ...
Cf. Bounded rationality
)
""" find x,y so bilin(x,y) ~ z and x,y near the middle """
from __future__ import division
import numpy as np
from scipy.optimize import leastsq
zmax = 30
corners = [ 0, 10, 20, zmax ]
midweight = 10
def bilin( x, y ):
""" bilinear interpolate
in: corners at 0 0 0 1 1 0 1 1 in that order (binary)
see wikipedia Bilinear_interpolation ff.
"""
z00,z01,z10,z11 = corners # 0 .. 1
return (z00 * (1-x) * (1-y)
+ z01 * (1-x) * y
+ z10 * x * (1-y)
+ z11 * x * y)
vecs = np.array([ (x, y) for x in (.25, .5, .75) for y in (.25, .5, .75) ])
def nearvec( x, vecs ):
""" -> (min, nearest vec) """
t = (np.inf,)
for v in vecs:
n = np.linalg.norm( x - v )
if n < t[0]: t = (n, v)
return t
def lsqmin( xy ): # z, corners
x,y = xy
near = nearvec( np.array(xy), vecs )[0] * midweight
return (z - bilin( x, y ), near )
# i.e. find x,y so both bilin(x,y) ~ z and x,y near a point in vecs
#...............................................................................
if __name__ == "__main__":
import sys
ftol = .1
maxfev = 10
exec "\n".join( sys.argv[1:] ) # ftol= ...
x0 = np.array(( .5, .5 ))
sumdiff = 0
for z in range(zmax+1):
xetc = leastsq( lsqmin, x0, ftol=ftol, maxfev=maxfev, full_output=1 )
# (x, {cov_x, infodict, mesg}, ier)
x,y = xetc[0] # may be < 0 or > 1
diff = bilin( x, y ) - z
sumdiff += abs(diff)
print "%.2g %8.2g %5.2g %5.2g" % (z, diff, x, y)
print "ftol %.2g maxfev %d midweight %.2g => av diff %.2g" % (
ftol, maxfev, midweight, sumdiff/zmax)