Passing different output projections to ODM, eg a `--projection` flag?

Hi all - long time no see!

A long while ago someone messaged me to ask about some high latitude imagery for testing, and I vastly apologize for not responding. If that’s you, please ask again :slight_smile:

I’ve been processing imagery north of 80 degrees (up to 87.5), and it would be better to avoid UTM - because of distortion when translating to/from lats and lons). I wondered how easy it is to pass a different projection to ODM - in my case EPSG:3413 (North polar stereographic) and went looking around in projections.py.

I am confident I can build my own bespoke docker image based on north polar stereo - but - that isn’t really super useful. Is there a straightforward way to pass a --projection to ODM? Another use case for this might be someplace where you want to hammer data to the UTM zone next door to the one ODM chooses (it is not a nice practice, but sometimes needs doing…)

And - I will figure out a way to share some high latitude imagery. Because it was shot in drifting sea ice, it needed drift removed from the camera positions - which is now done. Done enough, anyway :fire:

Thanks again!

1 Like

No, unfortunately we do not have arbitrary CRS selection at the beginning of the pipeline, just at the end for products we export from the Map View.

This has increasingly become a more popular ask, and your use-case certainly makes it clear that it has a real benefit for certain workflows…

1 Like

OK - I think it might be good if I spend a bit of time and see if swapping UTM out for north polar stereo actually makes a difference to output - including output first made in UTM then reprojected.

I’ll post any interesting results… and I hope I’ve read the code right :slight_smile: Maybe more questions will arrive here too…

2 Likes

I can’t believe after working in polar studies I lead a project that only does UTM. Younger me would be very upset… .

Let us know how it goes. If it’s as simple as injecting the right proj at the right time, then perhaps it’s not so hard to allow folks to use their own.

2 Likes

…ah UTM is fine for the most part, polar drone mappers are a pretty tiny cohort!

My first approach will be just hardcoding EPSG:3413, I’d have to study quite a bit to see how parameters get passed in. At least with proj as the engine, if anyone figures out a neat way to pass in custom projections, a lot of options are already baked in!

I think it’s still fine to assume coordinates come in as lats and lons, but that is also maybe changeable.

…maybe --processing-projection and --cameracenter-projection can eventually both be things?

1 Like

We’re using a pretty back-level PROJ, so anything you’re looking to use must have a complete PROJ4/PROJ4JS-compatible definition.

1 Like

…yup. May be nice for a future command line option to accept EPSG codes or proj strings, so --projection EPSG:3413 and --projection "+proj=stere +lat_0=90 +lat_ts=70 +lon_0=-45 +k=1 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs" are both accepted and valid.

It looks like opendm/types.py and odm/location.py are the places to tinker - at least for now when I am after the photo centers being written out in EPSG:3413, and then re using that definition downstream. That’s the first step, and likely the limit of my 1337 haxxoring :smiley:

1 Like

We have an unmerged patch that adds a few thousand definitions to our database, but fundamentally, we need a pretty big restructuring (it looks like) to use the newer definitions from PROJ5+.

I like your proposal for it. Can you think of anything else you’d want from it?

Thanks :slight_smile: I think the ability to process imagery in a non-UTM projection is all I want right now, although it opens a lot of options where localised CRS in meters can help a lot, especially for people working near UTM zone edges (as well as polar cases).

I’m ready to test whether polar stereo gets better results for me - my current struggle is getting the ODM docker image to build, but maybe thats another thread

1 Like

So UTM is pretty baked in. Setting a transform in opendm/locations.py was pretty straightforward, what I’ve done so far is tell ODM to use north polar stereo for anything above a fixed latitude (right now 75, but could be 60 - the limit of NSIDC North Polar stereo).

Then I realised that coords.txt is used heavily later on. What I want to do here is use a proj string on the first line, rather than a UTM zone / hemisphere. This is done in opendm/locations.py.

So - the next target is opendm/types.py, it seems a lot of CRS parsing from coords.txt happens there. I figure all this plumbing will help open doors to user defined CRS, as long as there’s an easy default (eg, if nothing provided, just use UTM)

My polar fork is here: GitHub - adamsteer/ODM-polar: A command line toolkit to generate maps, point clouds, 3D models and DEMs from drone, balloon or kite images. 📷

1 Like

some key parts in opendm/types.py should already handle Proj strings in coords.txt - testing things now :slight_smile:

…also, completely ignoring GCPs at this point.

2 Likes

OK, first result! Image centers are reprojected to NSIDC north polar stereo before matching, so the whole workflow is in north polar stereo meters.

Georeferencing is also done in north polar stereo.

With the small test set I get about a meter offset using the same imagery. Why do I care so much for relatively small gains? Because I am also hunting down some scaling/displacement issues that are bigger than camera center GPS uncertainties, when comparing ODM results and ground data.

Plus it’d be nice to open up ODM to other crs. And it feels right to use an appropriate projection for the region.

So the main part to touch for doing that seems to be feeding a proj string into opendm/locations.py. All the other parts I touched (see the fork on github, linked higher up) were happy to take proj strings.

I also took the liberty of cleaning out utm_ prefixes on eastings and northings, preparing for not hardcoding things for utm anymore.

My polar stereo CRS is hardcoded as a proj string, triggered by throwing imagery at it with GPS latitude above 60, all in locations.py. So it’s a super janky implementation, to be tidied later - maybe :D. Ideally it would default to utm unless a --projection arg was thrown in, but that is way above my current level.

The main lesson was - there is not that much needing touching if a more flexible crs system was implemented, because most of the core parts already understand if a Proj string comes their way.

A picture because pictures! Blue overlay is the UTM:36 version, color underlay is the new EPSG:3413 version.

Now, I’ll throw this at a site with a lot more images, and ground data to line up. Fingers crossed it works better :smiley:

1 Like