azavea / loam

Javascript wrapper for GDAL in the browser

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to rotate image?

comoris opened this issue · comments

Is there a way to rotate a georeferenced geotiff?
Getting lost in all warp options or should we use GDALSetGeoTransform from gdal.js?

Hmm, I'm not sure I quite understand the question -- if the geotiff is already correctly georeferenced then rotating it would invalidate the georeferencing. Can you explain a bit more about what you're trying to do?

@ddohler , we are repositioning/georeferencing an image in mapbox, and use the convert() with the repositioned values const dataset = await file.convert(['-of', 'GTiff', '-a_srs', 'EPSG:3857', '-a_ullr', upperLeftX, upperLeftY, lowerRightX, lowerRightY]) and then send the geotiff to mapbox upload service.
if we don't georeference the image and just send it as is, no issues. But once we reposition the image, then create the geotiff and then upload, the service complains:
error creating Mapnik data Datasource: Invalid raster: Invalid pixelsize in geotransform array.

Is it possible to change the rotation properties of the geotransform? I see examples online where SetGeoTransform is being used but I don’t think this function is exposed in loam.js

Thanks @comoris , that's really helpful, I think I understand now. So basically you've got some sort of image that's not georeferenced and you're lining it up with a basemap in Mapbox, and then extracting the corner coordinates and using Loam to output a georeferenced GeoTIFF.

A few things I want to double-check before moving further:

  • Are you ensuring that upperLeftX etc. are strings before passing them to Loam? There should be validation in place to catch it if they're not, but this has been a trouble spot in the past, so I want to double-check that it's not happening again somehow.
  • Are you calling .bytes() before uploading to Mapbox? I just realized that this is not documented (it should be), but it's necessary in order to get the GeoTIFF rather than just the dataset's Javascript object representation. So that would be something like const tiff = await dataset.bytes() .
  • Are the upperLeftX etc. values in EPSG:3857 already? They will need to be in the same coordinate projection as whatever you're passing in for -a_srs.

If you're doing both of those, then the next thing I would try to do is to experiment by hand with gdal_translate on the command line; if you can find a call to gdal_translate that works for your use, you should be able to translate it directly to Loam, just drop the input / output filenames from the end. And vice-versa; if it works with gdal_translate but not Loam, you can console.log() the arguments to convert() and paste them into the command-line to run gdal_translate directly and see what's going wrong.

I will also say that I've done something similar in the past, but we used convert() to set GCPs and then used warp() to reproject to EPSG:3857. Looking around, I'm seeing some other folks using a similar two-step approach, so it might also be worth trying that to see if warp() helps everything to line up, e.g. const dataset = await file.convert('-of', 'GTiff', '-a_srs', 'EPSG:4326', '-a_ullr', ...]).warp(['-of', 'GTiff', '-t_srs', 'EPSG:3857'])

Hope one of those helps, let me know how it goes!

Nice, thanks a lot for the comment, was really helpful. One of the mistakes we made was the initial CRS we defined in the convert() (gdal_translate). We now extract GCPs in EPSG:4326 and use warp() to convert to EPSG:3857. Its quite a challenge to get to know how gdal actually works. Doing it in the frontend makes it so much easier, thanks for the wrapper!
const dataset = await file .convert(['-of', 'GTiff', '-a_srs', 'EPSG:4326', ...gcps]) .warp(['-of', 'GTiff', '-t_srs', 'EPSG:3857', '-dstalpha', '-r', 'cubic', '-co', 'COMPRESS=LZW', '-co', 'TILED=YES', '-co', 'PREDICTOR=2']);