Orthophoto georeferenced import

Hi all,

Have a request from a client who would like to import orthophotos (.tiff format) and have them come in at the correct georeferenced position. Is there a free Rhino or GH plug-in that can do this? All I know how to do is get them as Pictures, but then repositioning/scaling them is manual…

does tiff picture contain information about geo referencing? Last time i did it manually with known corners coords of each picture

1 Like

That’s what I don’t know. In my case, the image name contains the coordinates for the lower left corner; and as I know the source from which it came, the tiles are all 1 square km. So in this particular case, with a script I can parse the file name and correctly place the image.

But for a more general case and also for reliability’s sake, it would be good to have a tool/plug-in that can get this info from the file itself (if it exists).

1 Like

I haven’t used the Heron grasshopper add-on myself but the documentation indicates it can work with raster files. Its unclear if it can grab the location info from a Geotiff or similar.

Heron can import geotiff with the Import Raster component. Make sure the EarthAnchorPoint is set first (can be done with SetEAP component). And if you want a different coordinate system than WGS84 (EPSG:4326), use the SetSRS component.

-Brian

1 Like

Hi Brian,

Thanks for the info, I have no experience with Heron.

I got the file path for the file and connected it to the import raster component, I got a whole series of error messages - every time I click close a new one came up.

Finally after clicking Close a bunch of times it gave me back the canvas. I disconnected the file path and re-connected it, then I got this:

But finally, it does seem to work now without generating any more error messages, the image preview does appear in the Rhino window:

However, it isn’t at the correct geolocation as far as I can tell, the lower left corner should be at 2749,1259 (in km) or 2749000,1256000 in meters - that LLC coordinate is in the filename - but in fact the LLC ends up at 1350786.16,5875843.61 OTOH, the extents are correct at 1000 meters a side. Baking it only gets me the rectangle - is there something else I need to connect to get the image as a Picture in Rhino?

Also, I don’t really know what data I’m supposed use to connect to the EarthAnchorPoint… Maybe that’s the problem.

Image source: SWISSIMAGE 10 cm - swisstopo

Edit - the raster info does seem to have the correct corner info:

I also tried setting the EAP to the longitude and latitude of Bern and updating, but that didn’t seem to help…

Hi @Helvetosaur ,
To get what I believe you’re expecting you will need to set Rhino’s EAP to the origin of LV95 (EPSG:2056). One way to do this is to use CoordinateTransform to get LV95’s origin in LAT/LON, then SetEAP with the results.

To bake to Rhino, I typically use Human components (Create/Modify Materials, CreateAttributes, SurfaceMap, and Bake).

-Brian

OK, thanks for the additional info, I did get it to work after a bit of trying…

But it seems a bit unreliable - when I hit “Update” the Grasshopper window will sometimes disappear and I have to call it up again, and it didn’t always update correctly (Rhino 8, GH 1).

Rhino also appears to be struggling with the orthophoto - it’s 10k x 10k pixels, so 100Mpix, and is around 60Mb. It takes a good 15 seconds to load or update and the laptop fans start to wind up. I tried importing the image separately with the import image component and that knocked Rhino into an endless unresponsive loop, and I had to kill it. Looks like the image import component in GH does not support .tif format.

It would be interesting to see if one could bake the image at the correct placement using the native V8 GH components instead of Human, but I didn’t see how to get the image file into GH that way.

Hi Mitch, your graphic card might not be happy with so large textures in OpenGL.

You can run this in Rhino 8 to check it:

"""
for Rhino 8
Check maximum texture support size
"""
#! python3
# r: PyOpenGL

import rhinoscriptsyntax as rs
import scriptcontext as sc
import System
import System.Collections.Generic
import Rhino

from OpenGL.GL import glGetIntegerv, GL_MAX_TEXTURE_SIZE
import ctypes

def main():
    max_texture_size = ctypes.c_int()
    glGetIntegerv(GL_MAX_TEXTURE_SIZE, ctypes.byref(max_texture_size))
    print(f"Maximum texture size: {max_texture_size.value}")

if __name__ == "__main__":
    main()

On my 4070ti I get:
Maximum texture size: 32768

PPS! I have an inhouse tool to read in geotiff’s that we use. If you want to share the tiff through PM I can check if it works on your tiff as well.

Dunno, it imports fine in about 5 seconds via a script using Picture. But I suppose the texture is downsampled. The script parses the file title which by default in this case contains the lower left corner coordinates. But I wanted to see if it could read the coordinates directly from the file, as people might change the filename.

This is on a laptop that is maybe 5 years old with a 4Gb Quadro P2000 card. Your script errors out here when run from ScriptEditor.

You can download any square directly from here:

I just made that tool with a little help from ChatGPT so it is brand new and only testet on my machine.
You might need to restart Rhino 8. Sometimes importing new stuff with the automatet PIP # r: thing makes it stutter. A restart usually fixes that.
(ScriptEditor is the correct way to run it by the way)

Edit:
PS! I thought this was a 3D tiff, since it was just a 2D aerial it was quick to rewrite it so the tiff reader just pull out the bounds of the dataset and use this data to pictureframe the image.

I’ll PM you the script.

OK, restart fixed it. I get the same as you, 32768.

:+1:

I suppose I should just ask ChatGPT how to do this myself…

1 Like

Hi @Helvetosaur
It looks like this imagery is also served up as a Web Map Service (WMS), which, with a little effort, can be queried with the GdalWarp component. The benefits here are an arbitrary boundary and resolution without the need to download individual files. This may help with the file sizes.
20240108_SwissOrthophotos.gh (23.9 KB)

Note, the Rhino units need to match that of LV95 (meters) so the corner coordinates of the bounding box in the query make sense to the service.

-Brian

I downloaded a tile in my area. The coordinates in the title are for the lower left corner and the coordinates in the EXIF are for the top left corner.

I can extract the EXIF tag in Python but not in Grasshopper.

I found this script and somehow managed to extract a tag:

The window on the right side of the screenshot is what I get from GIMP

The ‘0x8482’ tag unfortunately results in ‘T?CA?93A’ and I have no clue what the problem is?

orthophoto_exif_coordinates.gh (4.0 KB)

Hi all,

Thanks for all the answers! I adapted Jørgen’s script using rasterio for my purposes and it seems the fastest and easiest way to go - it’s also more “portable” than a Grasshopper def.

For users of Rhino versions earlier than V8, I have a version that just parses the orthophoto’s filename to get the coordinates, it will also work fine for my clients who are here in CH if they don’t change the filename.

1 Like