Well, it seems like I solved problems 1 & 2 at least. Full source code at github, but some explaination here:
For a custom CRS I decided (per Whubers suggestion) to "cheat" and use meters as unit. I found a "local crs" at apatialreference.org (SR-ORG:6707):
LOCAL_CS["Non-Earth (Meter)",
LOCAL_DATUM["Local Datum",0],
UNIT["Meter",1.0],
AXIS["X",NORTH],
AXIS["Y",EAST]]
Using Python and GDAL this is fairly easy to read:
def get_coordsys():
#load our custom crs
prj_text = open("coordsys.wkt", 'r').read()
srs = osr.SpatialReference()
if srs.ImportFromWkt(prj_text):
raise ValueError("Error importing PRJ information" )
return srs
Also, greating a DEM with GDAL was actually rather straightforward (I ended up with a single-band geo-tiff). The line parser.read_layer(0) returns my previously described 512x512 matrix.
def create_dem(afmfile, outfile):
#parse the afm data
parser = AFMParser(afmfile)
#flip to account for the fact that the matrix is top-left, but gdal is bottom-left
data = flipud(parser.read_layer(0))
driver = gdal.GetDriverByName("GTiff")
dst_ds = driver.Create(
outfile,
data.shape[1],
data.shape[0],
1 ,
gdal.GDT_Int16 ,
)
dst_ds.SetGeoTransform(get_transform(parser, data))
dst_ds.SetProjection(get_coordsys().ExportToWkt())
dst_ds.GetRasterBand(1).WriteArray(data)
dst_ds = None
The triockiest part was figuring out how to properly "georeference" my file, i ended up using SetGeoTransform, getting the parameters as so:
def get_transform(parser, data):
#calculate dims
scan_size, x_offset, y_offset = parser.get_size()
x_size = data.shape[0]
y_size = data.shape[1]
x_res = scan_size / x_size
y_res = scan_size / y_size
#set the transform (offsets doesn't seem to work the way I think)
#top left x, w-e pixel resolution, rotation, 0 if image is "north up", top left y, rotation, 0 if image is "north up", n-s pixel resolution
return [0, x_res, 0, 0, 0, y_res]
This last part is probably the one I am the most unsure about, what I really was looking for was something line *gdal_transform -ullr*, but I couldn't find way to do this programatically.
I am able to open my GeoTIFF in Qgis and view it (and visually comparing it with the result from the Bruker program it looks right), but I haven't really answered my question 3; what to do with this data. So, here I'm open for suggestions!
rt_raster_to_gdal: Could not load the output GDAL driver
As for the first error with ST_AsTIFF, you need to enable your GDAL drivers, which by default are not enabled for PostGIS 2.1. See the manual on ways to do this. For instance, I have an environment variable set up on a Windows computer with:
POSTGIS_GDAL_ENABLED_DRIVERS=GTiff PNG JPEG GIF XYZ DTED USGSDEM AAIGrid
which can be confirmed with PostGIS with:
SELECT short_name, long_name
FROM ST_GDALDrivers();
PostGIS to Numpy
You can export the output to a virtual memory GeoTIFF file for GDAL to read into a Numpy array. For hints on virtual files used in GDAL, see this blog post.
import os
import psycopg2
from osgeo import gdal
# Adjust this to connect to a PostGIS database
conn = psycopg2.connect(...)
curs = conn.cursor()
# Make a dummy table with raster data
curs.execute("""\
SELECT ST_AsRaster(ST_Buffer(ST_Point(1, 5), 10), 10, 10, '8BUI', 1) AS rast
INTO TEMP mytable;
""")
# Use a virtual memory file, which is named like this
vsipath = '/vsimem/from_postgis'
# Download raster data into Python as GeoTIFF, and make a virtual file for GDAL
curs.execute("SELECT ST_AsGDALRaster(rast, 'GTiff') FROM mytable;")
gdal.FileFromMemBuffer(vsipath, bytes(curs.fetchone()[0]))
# Read first band of raster with GDAL
ds = gdal.Open(vsipath)
band = ds.GetRasterBand(1)
arr = band.ReadAsArray()
# Close and clean up virtual memory file
ds = band = None
gdal.Unlink(vsipath)
print(arr) # this is a 2D numpy array
Shows a rasterised buffered point.
[[0 0 0 1 1 1 1 0 0 0]
[0 1 1 1 1 1 1 1 1 0]
[0 1 1 1 1 1 1 1 1 0]
[1 1 1 1 1 1 1 1 1 1]
[1 1 1 1 1 1 1 1 1 1]
[1 1 1 1 1 1 1 1 1 1]
[1 1 1 1 1 1 1 1 1 1]
[0 1 1 1 1 1 1 1 1 0]
[0 1 1 1 1 1 1 1 1 0]
[0 0 0 1 1 1 1 0 0 0]]
Note that I used a 'GTiff' format in the example, but other formats might be better suited. For instance, if you have a large raster that needs to be transferred across a slow internet connection, try using 'PNG' to compress it.
Best Answer
Matplotlib knows nothing about georeferenced surfaces, it only knows x,y,z coordinates. You can also use Visvis or Mayavi.
you must first extract the x,y, z coordinates of the grid ( a raster is a grid of pixels and with a DEM, the value of the pixel is the elevation, z) with osgeo.gdal. No script here because it is possible to find the solutions on Gis StackExchange or on the web.
after, you can plot the points in 3D
and you must reconstruct a 3D grid (surface) with the function griddata of matplotlib (Delaunay)
The grid (with visvis):
!
The coloured grid (with matplotlib):
but you can also use others interpolation algorithms (Scipy thin-plate spline here) and drape colours
With Visvis, you can make animations:
You can even plot the 3D contours: