Calculate x/y position on an image from latitude/longitude - model-view-controller

I already did some research but none answer did fit to my problem:
I have an image (jpeg) that is represented by a latlonbox:
https://developers.google.com/kml/documentation/kmlreference?hl=de#latlonbox
So I have North, South, East and West information that form the image, right? Is the N/W the top left point and the S/E the bottom-rightt point?
The image has a size of 4000x2000. In my mvc application i reduced size to 1500x750 pixel.
Now I am trying to achieve to calculate the x/y position on this image by getting a latitude/longitude input. How can I achieve this?
I found this link:
http://code.google.com/p/geographical-dot-net/source/browse/trunk/GeographicalDotNet/GeographicalDotNet/Projection/GoogleMapsAPIProjection.cs
But I don't have any zoom information and I also don't understand how to start, because I have a jpeg and the kml information with latlonbox.
Thanks for any help

thanks for your reply! Yes, in my case the kilometers are very small, maybe only some hundred meters. I tried to solve it with two linear equations, would that be appropriate?
Using the first link, with the example of latlonbox I did the following:
WN: (-90,8714285289695/48,25475939255556) <=> X: (0/0)
ES: (-90,86591508839973/48,25207367852141) <=> Y: (1500/750)
E: -90,86591508839973
S: 48,25207367852141
W: -90,8714285289695
N: 48,25475939255556
Diff EW: 0,00551344056977
Diff_SN: 0,00268571403415
I define two functions:
f_X1: m*x_lon + b where f_X1 is the X coordinate and x_lon the longitude value
f_X2: m*x_lat + b where f_X2 is the Y coordinate and x_lat the latitude value
Function to get X-coordinate:
m = (1500/Diff_EW) = 272062 (rounded)
Insert a known X/Longitude-Pair in function f_X1:
1500 = E * 272062 + b
b = 1500 - (E * 272062)
b = 24722662 ( rounded)
=> f_X1: 272062x + 24722662
Same procedure to get f_X2:
m = (750/-Diff_SN) = - 279255(rounded)
Insert a known Y/Latitude-Pair in functon f_X2:
750 = S * (-279255) + b
b = 750 - (S*(-279255))
b = 13475382
f_X2: -279255x + 13475382
If I insert the values for East and West (E and W) I will get the X-coordinates (approximately 1500 and 0; deviates due to rounding)
If I insert the values for South and North (S and N) I will get the Y-coordinates (approximately 750 and 0; deviates due to rounding)
Is this a correct way to do it in this case? I assumed the function to be linear, I don't know if that's correct.
Thanks for any help.

Related

How to find the pixel location of a GPS point in an orthoimage with known orientation and GPS location

I have a problem where I need to determine whether a given latitude, longitude GPS-point is in a given orthoimage (approx. 1 hectare area) with known real-world orientation and GPS-location (corresponding to the center of image).
That is, given a GPS-point P, I need to determine:
Is point P located in the orthoimage, and if yes,
What is the pixel location of point P in the orthoimage.
My question is summarized in the following image:
As you can see in the image, I know the GPS-coordinates of the image (center) and where North is located with respect to the image. Also, I know how many centimeters in the ground each pixel corresponds to.
My question is: What would be an efficient and smart way to achieve the goals in my problem?
One approach I had in mind was to solve a linear mapping between the GPS- and pixel-points and then use this mapping to answer both problems 1-2. I thought this could be a reasonable approach, even though the earth has curvature and the GPS-coordinates are (I'd say) more like a parabolic function of the pixel coordinates, since the distances are very small (one image is an approximately 1 hectare area) I could assume without significant loss in accuracy that the GPS-coordinates change locally linearly w.r.t pixel coordinates.
What do you think? Thank you.
Update:
The orthophotos have been taken with a Phantom 4 Pro drone with gimbal camera system.
I thought about one possibility myself, not perfect but it's a start:
The following information is given:
a rectangular orthoimage Img, Yaw of the image (that is, how many degrees the image is facing away from north), pix_size pixel size in the ground (centimeters/pixel).
The problem is: Given an arbitrary GPS-point p = (lat, long), determine the pixel location of p in Img.
Denote c = (latc, longc) and cp = (x,y) as the GPS- and pixel-coordinates of the center point of Img.
Determine how much we must move along North-South and West-East axes to get from c to p. Let lat_delta = latc-lat and long_delta = longc-long. If lat_delta < 0 -> p is more in north than c, otherwise p is more in south than c. The same goes analoguously for long_delta.
> if lat_delta < 0:
> pN = [latc + abs(lat_delta), longc]
> else:
> pN = [latc - abs(lat_delta), longc]
>
> if lat_long < 0:
> pE = [latc, longc + abs(long_delta)]
> else:
> pE = [latc, longc - abs(long_delta)]
Now the points c, p, pN and pE form a "spherical" right triangle (I think I could safely assume it to be planar because the orthophoto describes max 1 hectare area). So the Pythagorean theorem applies sufficiently enough for my purposes.
Next, I calculate the ground distances dN = Haversine(c,pN) and dE = Haversine(c, pE), which tell me how much in ground distance I must move in North-South and West-East axes in order to get from c to p.
Now I will apply a rotation matrix R(-Yaw) to vectors n = [0,1] and e = [1,0], which represent the upwards and right vectors in my pixel coordinate system. So I get nr = R(-Yaw)*n and er = R(-Yaw)*e where nr is a unit pixel vector pointing towards North in the image and er is similarly a unit pixel vector pointing towards East in the image.
Next, I calculate the ratios mN = dN/pix_size and mE = dE/pix_size (the factors also need to take into account the +- direction). Now I calculate the pixel location of p by:
pp = cp + mN*nr + mE*er,
where I can now easily check if the pixel values pp are within the bounds of the image Img.
Of course this method does not work in a general large area case and needs to be refined for this purpose.

how to get new coordinates with width, length and angle known?

I have trapezoid with three coordinates known. So I need to create 4th coordinate with length, width and angles I am having. You can assume this problem with triangle as ADC from trapezoid. The model comes as differently expected . The Law of cosines gives the angle but it should be applied to local coordinates of the model. Right side I am showing with arrow pointed as wrong object which i am getting. Even if I rotate the object or flip it, the coordinates should not get wrong.
newWidth2 is AB. newLength is AD. Point C need to be created from A,D with angle D. Math.Pow is "to the power of" and 2 is it's square.(for who can't understand this notation).
Assume that I dont have coordinates of C. I know only A,D coordinates. I know length of AD, Width2 and Width1. I can get angle ADC from initial coordinates of C where coordinates of C will vary when I change Width2 of DC. So coordinates of C will be based on length of AD, angle D and so on. Finally what I need is coordinates of C if the entire object is rotated in any angle.
newWidth2 is AB.
newLength is AD.
Point C need to be created from A,D with angle A or angle D also.
Math.Pow is "to the power of" and 2 is it's square.(for who can't understand this notation).
//Initially I will have Coordinates for C but later I should remove them and create from the model width and heights. So I can't take input as C Coordinates of (X3,Y3) which I already have.
//distance formula
newWidth2 = Math.Sqrt(Math.Pow(CoordX3 - CoordX5, 2) + Math.Pow(CoordY3 - CoordY5, 2));
//from the formula -> b2 = a2 + c2 - 2acCos(B)
diagangle = Math.Acos((Math.Pow(newWidth2, 2) - Math.Pow(newdiagonal, 2) - Math.Pow(newLength, 2)) / (-2 * (newdiagonal) * (newLength)) );
//I am getting this C coordinates as wrong.
//for getting C (third coordinates)
xcoord3 = CoordX5 + (newWidth2 * Math.Cos(diagangle));
ycoord3 = CoordY5 + (newWidth2 * Math.Sin(diagangle));
//sample values of one model
Width1 36
Width2 24
Length 88.0783
A
CoordX1 43.944
CoordY1 409.2514
B
CoordX2 46.9337
CoordY2 373.3758
C
CoordX3 133.7111
CoordY3 392.6488
D
CoordX4 131.718
CoordY4 416.5659
It is not clear what exactly is known and what is to be found. I assume that you know coordinates of A, B, C and length AB = width1 and CD = width2 and need to find coordinates of D.
I think this problem is easier to solve if you see it as a vector problem rather than a trigonometry problem. If you look at vectors BA and CD you may see that they are collinear and |BA| = width1 while |CD| = width2. It means that vector CD = width2/width1 * BA. Not you can trivially calculate the coordinates of D by:
Calculating vector BA
Calculating CD = width2/width1 * BA
Calculating D = C + CD

How much a point inside an ABC triangle moved from its origin, knowing the offset of the A,B,C

I'm trying to measure in % how much the X and Y coordinates of a point inside an ABC triangle moved from its original place, knowing how much % has the A,B,C points moved.
Example: Knowing that the following points moved from their original position: A.x 30%, A.y 45%, B.x 10%, B.y 20%, C.x 70%, C.Y 60%, find out how much the coordinates X and Y of a point P inside the A,B,C triangle moved.
How can I calculate the offset of any point inside such a triangle?
I believe you need the Barycentric coordinates here. Eventually those give you a chance to represent a given point P in the triangle with vertices t1, t2, t3 as P = a * t1 + b * t2 + c * t3. Given this, the new coordinates after translating the triangle into t1', t2', t3' will result into P' = a * t1' + b * t2' + c * t3' i.e. you would just apply the same weights to every corner.
Taken into account you start with cartesian coordinates here are the formulas to do the conversion from cartesian to barycentric i.e. find the a, b, c I mentioned before.
Since you did have the c++, I'll answer the question from a programmer prospective rather than a mathematician so this may not be the best mathematical way to do it. the way i would calculate this is I would first work out the left-most and right-most point of the triangle so this would be the points with the lowest x value and the highest x value then using the following formula we calculate it's percentile position within the triangle.
percentile.x = (rightMostPoint.x - leftMostPoint.x) / (point.x - leftMostPoint.x);
The Y axis is pretty much the same. Please note as well that firstly this function returns a float percentile so 0.5 = 50% and also a values between 0% and 100% don't guarantee that the point is within the triangle.
Now you know the percentile position you can simply calculate the difference in between the before and after percentile position. i.e.
percentileChangeOnX = abs(precentPosBefore.x - precentPosAfter.x);

Find coordinates inside a rectangular area constructed by lat/long GPS pairs

I've never deal much with location-based data, so very much new to the whole GPS coding related questions. I have a problem that I don't seem to find a very efficient way in solving it or maybe there's an algorithm that I'm not too sure.
Let said you have given 4 lat/long coordinates which construct some kind of a rectangular area: (X0, Y0), (X1, Y0), (X0, Y1), (X1, Y1)
-----------------------------------
| b |
| a |
| | d
| |
| c |
-----------------------------------
e
Is there a way to find all the point that are inside the given rectangular area : a, b, c
And all the points outside of the area? e, d
I can easily to construct a 2D matrix to do this, but that's only if the coordinates are in integer, but with lat/long pairs, the coordinates are usually in float numbers which we cannot use it to construct a 2D table.
Any cool ideas?
Edited 1:
What about this Ray-casting algorithm? Is this a good algorithm to be used for GPS coordinates which is a float number?
If your rectangle is axis-aligned, #Eyal's answer is the right one (and you actually don't need 8 values but 4 are enough).
If you deal with a rotated rectangle (will work for any quadrilateral), the ray-casting method is appropriate: consider the horizontal line Y=Yt through your test point and find the edges that cross it (one endpoint above, one endpoint below). There will be 0 or 2 such edges. In case 0, you are outside. Otherwise, compute the abscissas of the intersections of these edges with the line. If 0 or 2 intersection are on the left of the test point, you are outside.
Xi= Xt + (Yt - Y0) (X1 - X0) / (Y1 - Y0)
An alternative solution to #YvesDaoust's and #EyalSchneider's is to find the winding number or the crossing number of each point (http://geomalgorithms.com/a03-_inclusion.html). This solution scales to a polygon of any number of vertices (regardless of axis-alignment).
The Crossing Number (cn) method
- which counts the number of times a ray starting from the point P crosses the polygon boundary edges. The point is outside when this "crossing number" is even; otherwise, when it is odd, the point is inside. This method is sometimes referred to as the "even-odd" test.
The Winding Number (wn) method
- which counts the number of times the polygon winds around the point P. The point is outside only when this "winding number" wn = 0; otherwise, the point is inside.
Incidentally, #YvesDaoust's solution effectively calculates the crossing number of the point.
There is an unlimited number of points inside a rectangle, so you have to define a
step with (distane between two points).
You could just iterate with two nested loops,
lat, lon coordinates can be converted to integer using a multiplication factor of:
multiply with 1E7 (10000000) to get maximum acuracy of 1cm, or
10000000: 1cm
1000000: 10cm
100000: 1m
10000: 10m
1000: 100m
100: 1km
10: 11km
1: 111km
Now iterate
// convert to spherical integer rectangle
double toIntFact = 1E7;
int x = (int) (x0 * toIntFact);
int y = (int) (y0 * toIntFact);
int tx1 = x1 * toIntFact;
int ty1 = y1 * toIntFact;
int yStep = 100000; // about 1.11 m latitudinal span. choose desired step above in list
int xStep = (int) (yStep / cos(Math.toRadians(y0))); // longitude adaption factor depending of cos(latitude); more acurate (symetric) is to use cos of centerLatitude: (y0 + y1) / 2;
for (int px = x; px < tx1; px+= xStep) {
for (int py = y; py < ty1; py+= yStep) {
drawPoint(px, py); // or whatever
}
}
This should give an point set with same distances inbetween point for about some kilometer wide rectangles.
The code does not work when overlapping the Datum limit (-180 to 180 jump) or
when overlapping the poles. Delivers useable results up to latitude 80° N or S.
This code uses some kind of implicit equidistant (equirectangular) projection (see the division by cos(centerLat) to correct the fact that 1 degree of latitude is another distance measured in meters than one degree of longitude.
If the size of the rectangle exceeds some ten or hundred kilomters, then depending on your requirements have to use an advanced projection: e.g convert lat, lon with an WGS84 to UTM conversion. The result are coordinates in meters, which then you iterate analog.
But are you sure that this is what you want?
Nobody wants to find all atoms inside a rectangle.
May all screen pixels, or a method isInsideRectangle(lat,lon, Rectangle);
So think again for what you need that.

Does anyone know how to do an "inverse" trilinear interpolation?

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)

Resources