Is GeoTIFF using correct coordinate reference system? - geotiff

I have the following simple code that returns the elevation at a certain lat/lng using rasterio, given an existing GeoTIFF file. The output is 69m and the coordinate reference system (CRS) that rasterio reports is EPSG:4326:
import rasterio
lng=34.9462949
lat=32.2586248
with rasterio.open('my.tif') as dataset:
print(f'CRS: {dataset.crs}') # output EPSG:4326
row, col = dataset.index(lng, lat)
elevation = dataset.read(1, window=((row, row+1), (col, col+1)))
print(elevation[0, 0]) # output 69
I'm new to rasterio but looking up EPSG:4326 says it is "WGS 84, latitude/longitude coordinate system based on the Earth's center of mass, used by the Global Positioning System among others."
Does this mean the results are heights above the WGS84 ellipsoid? If so, the problem is that we have an independent and highly-accurate measuring system that explicitly reports 69m above MSL and NOT above the ellipsoid. And, when checking the diff between MSL and Ellipsoid at that point shows a 20m gap. So they can't both be right. On the other hand, if rasterio results are MSL, then why doesn't the CRS indicate that, e.g EPSG:5100 (approximates the MSL geoid)
How to resolve this conflict?

Related

Pre-projected geometry v getting the browser to do it (aka efficiency v flexibility)

To improve the performance of my online maps, especially on smartphones, I'm following Mike Bostock's advice to prepare the geodata as much as possible before uploading it to the server (as per his command-line cartography). For example, I'm projecting the TopoJSON data, usually via d3.geoConicEqualArea(), at the command line rather than making the viewer's browser do this grunt work when loading the map.
However, I also want to use methods like .scale, .fitSize, .fitExtent and .translate dynamically, which means I can't "bake" the scale or translate values into the TopoJSON file beforehand.
Bostock recommends using d3.geoTransform() as a proxy for projections like d3.geoConicEqualArea() if you're working with already-projected data but still want to scale or translate it. For example, to flip a projection on the y-axis, he suggests:
var reflectY = d3.geoTransform({
point: function(x, y) {
this.stream.point(x, -y);
}
}),
path = d3.geoPath()
.projection(reflectY);
My question: If I use this D3 function, aren't I still forcing the viewer's browser to do a lot of data processing, which will worsen the performance? The point of pre-processing the data is to avoid this. Or am I overestimating the processing work involved in the d3.geoTransform() function above?
If I use this D3 function, aren't I still forcing the viewer's browser
to do a lot of data processing, which will worsen the performance? The
point of pre-processing the data is to avoid this. Or am I
overestimating the processing work involved in the d3.geoTransform()
function above?
Short Answer: You are overestimating the amount of work required to transform projected data.
Spherical Nature of D3 geoProjections
A d3 geoProjection is relatively unique. Many platforms, tools, or libraries take points consisting of latitude and longitude pairs and treat them as though they are on a Cartesian plane. This simplifies the math to a huge extent, but comes at a cost: paths follow Cartesian routing.
D3 treats longitude latitude points as what they are: points on a three dimensional ellipsoid. This costs more computationally but provides other benefits - such as routing path segments along great circle routes.
The extra computational costs d3 incurs in treating coordinates as points on a 3d globe are:
Spherical Math
Take a look at a simple geographic projection before scaling, centering, etc:
function mercator(x, y) {
return [x, Math.log(Math.tan(Math.PI / 4 + y / 2))];
}
This is likely to take longer than the transform you propose above.
Pathing
On a Cartesian plane, lines between two points are easy, on a sphere, this is difficult. Take a line stretching from 179 degrees East to 179 degrees West - treating these as though they were on a Cartesian plane that is easy - draw a line across the earth. On a spherical earth, the line crosses the anti-meridian.
Consequently, in flattening the paths, sampling is required along the route, great circle distance between points requires bends, and therefore additional points.I'm not certain on the process of this in d3, but it certainly occurs.
Points on a cartesian plane don't require additional sampling - they are already flat, lines between points are straight. There is no need to detect if lines wrap around the earth another way.
Operations post Projection
Once projected, something like .fitSize will force additional work that is essentially what you are proposing with the d3.geoTransform(): the features need to be transformed and scaled based on their projected location and size.
This is very visible in d3v3 (before there was fitSize()) when autocentering features: calculations involve the svg extent of the projected features.
Basic Quasi Scientific Performance Comparison
Using a US census bureau shapefile of the United States, I created three geojson files:
One using WGS84 (long/lat) (file size: 389 kb)
One using geoproject in node with a plain d3.geoAlbers transform (file size: 386 kb)
One using geoproject in node with d3.geoAlbers().fitSize([500,500],d) (file size 385 kb)
The gold standard of speed should be option 3, the data is scaled and centered based on an anticipated display extent, no transform is required here and I will use a null projection to test it
I proceeded to project these to a 500x500 svg using:
// For the unprojected data
var projection = d3.geoAlbers()
.fitSize([500,500],wgs84);
var geoPath = d3.geoPath().projection(projection)
// for the projected but unscaled and uncentered data
var transform = d3.geoIdentity()
.fitSize([500,500],albers);
var projectedPath = d3.geoPath()
.projection(transform);
// for the projected, centered, and scaled data
var nullProjection = d3.geoPath()
Running this a few hundred times, I got average rendering times (data was preloaded) of:
71 ms: WGS84
33 ms: Projected but unscaled and uncentered
21 ms: Projected, scaled, and centered
I feel safe in saying there is a significant performance bump in pre-projecting the data, regardless of if it is actually centered and scaled.
Note I used d3.geoIdentity() as opposed to d3.geoTransform() as it allows the use of fitSize(), and you can reflect if needed on the y: .reflectY(true);

Polydata .vtk generated from nifti .nii volume through cannot supperpose each other

Problem:
I am trying to construct a vtk polydata model from a CT Nifity volume using marching cube method.
What I did:
So far I can produce a perfectly-to-scale skull model using vtk's polydata writer. However, the skull.vtk is rotated and translated rigidly when compared to the original ct.nii volume. I understand that Nifities have a QForm matrix to map voxel data to real world and vktPolyData do not have this data explicitly. However, the result of applying the QForm matrix to the vtkPolyData is not even close to perfect overlapping.
Does anyone know why this happens?
I think the reason is that the y-axis is inverted in VTK. Most likely applying a rotation matrix of [-1 0 0; 0 -1 0; 0 0 1] (row-major) will solve your problem.
A quick and easy check is to use an external tool, e.g. 3D Slicer or Paraview, to apply the rotation. For example in paraview, you can do the following:
-Load the polydata and your image in Paraview.
-Change the rotation to (180, 180, 0) degrees (equivalent to above rotation matrix)
-See if the polydata and image line up
I have attached an example image that shows how to do this in paraview. The red is the result of applying rotation to the original blue polydata. The location of the rotation parameters is given in the green box.

what coordinate system is this and how to convert it to longitude latitudes?

I'm working with a coordinate system but I don't know what type of coordinate system is that.
Here is the part of the data set that I have.in 2nd and 3rd row shows the coordinate system.
Intersection Point Coordinate
N (X) E (Y)
384030.906 474784.247
384041.740 474892.294
384095.694 475203.524
These are real coordinates which were used in Sri Lanka and I want to map these coordinates in GIS map.(I'm making an android app to draw path according to the coordinates by using ArcGIS runtime sdk.)I need to find out what type of coordinate system is this and how to convert it in to longitude latitude? plz help me on this.thank you.
This might be in a Kalianpur (Indian Sub-continet) coordinate system with units in meters.
You can open a map and add a country boundary for Sri Lanka, such as this one: http://www.arcgis.com/home/item.html?id=a842e359856a4365b1ddf8cc34fde079
zoom towards the locale, if known, and choose different coordinate systems under the Layers button > coordinate system. The choose the general tab and pick different units until the measurements look good.
You can create xy data using the following instructions: http://help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#//00s50000001z000000
A quick and dirty approach is to move your cursor around and create points in a shapefile in an edit session.

cartesian to geographical/sperical coordinates

I have a dxf file of a town in meter coordinates. I need to extract polylines from the map and convert them to geographical coordinates. My idea is to add 3 or 4 points on the map with known coordinates. I will place them using google map as reference. These 3 or 4 points will be placed at intersections roads so I can not place them as they defined a rectangle (I think it would be simpler).
I can not found out what calculation I have to do to convert all the coordinates of the objects of the map.
google map earth radius: 6378137 meter.
so, If I consider 3 points, I will have 3 relations:
(x1,y1) with (lat1, lng1)
(x2,y2) with (lat2, lng2)
(x3,y3) with (lat3, lng3)
I have done one simple conversion with only 2 points but I'd like a more accurate result.
I preferably use c/c++ to do it.
example of one equivalent point:
latitude: -2.148707
longitude: -79.876270
x: 2012078.15
y: 498355.88
It's not a UTM, I verify it from here. Because I do not know if it s a normalized.
I googled a lot, I found libraries, but without knowing if tmy coordinates meet a specific format, I don't think I can use one.
Anyway, thanks to read and I hope someone could help me.
It is not as easy at that. First you need to know which reference ellipsoid you are using (e.g. WGS-84) and then which projection. I wouldn't try to implement this by hand, but use postgis instead, which would do all this ugly work for you.
The correct way is to ask the provider of the file what the coordinate system is related to. dxf is not realy a suitable format. you need a format like ESRI Shp file or mif/mid with a defined geographic coordinate system.
otherwise it is a bit unclear if the data are precise enough, to be used for geographic reference.
However it is not difficult to transform between meters and wgs84 lat longitude, especially if the area is not more than 10-20 miles.
you could use as first try the cylyndrical equidistant transformation, which is only a few lines of simple code. look also if the y-achsis in the dxf file points to the nort pole, otherwise you must find out that amount of false northing and rotate back to north.
MapInfo Professional is a tool with free evaluation period, this tool alows to specify reference points for such unknown coordinate systems. (at least for bitmaps i rememer that feature).
But if you are a professional sw developper, You should reject that file and demand a version in wgs84 lat lon.

How to plot geo-referenced image so that it "fits" the plot coordinate system in Matplotlib

A very similar question, solved the same way: how to use 'extent' in matplotlib.pyplot.imshow
I have a list of geographical coordinates (a "tracklog") that describe a geographical trajectory. Also, I have the means of obtaining an image spanning the tracklog coverage, where I know the "geographical coordinates" of the corners of the image.
My plot currently looks like this (notice the ticks - x=longitudes, y=latitudes, in UTM, WGS84):
Then suppose I know the corner coordinates of the following image (or a version of it without the blue track), and would like to plot it SO THAT IT FITS THE COORDINATE SYSTEM of the plot.
How would I do it?
(as a side note, in case that matters, I plan to use tiles)
As per the comment of Joe Kington (waiting for his actual answer so that I can accept it), the following code works as expected, giving a pannable and zoomable fixed-aspect "georeferenced" tile over which I am able to plot tracklogs:
import matplotlib.pyplot as plt
import Image
import numpy
imarray = numpy.asarray(Image.open('map.jpg'))
plt.plot([0,1], [0,1], 'o', c='red', ms=20) ## some reference circles for debugging
plt.imshow(imarray, extent=[0,1,0,1]) ## some random map whose corners have known coordinates
plt.axis('equal')
plt.show()
There is really not much of an answer here, but if you are using matplotlib, and you geos-tuff, take a look at matplotlib.basemap.
By default all operations are done on UTM maps, but you can choose your own projection.
Take also a look on the list of good tutorials in http://www.geophysique.be, for example.

Resources