Skip to content

381 helmert#385

Open
mradamcox wants to merge 10 commits into
mainfrom
381_helmert
Open

381 helmert#385
mradamcox wants to merge 10 commits into
mainfrom
381_helmert

Conversation

@mradamcox
Copy link
Copy Markdown
Member

@mradamcox mradamcox commented Jun 3, 2026

Initial work to support 4-parameter helmert transformation, i.e. georeferencing with only two GCPs, as requested by @danvk in #381.

I've wired up the front-end to show a preview after two GCPs have been added. Helmert is automatically used as the transformation at that point.

image

If you click the checkmark to submit at this point, a modal appears with a warning:

image

On the backend, the transformation is run just the same as before, but different arguments are passed to GDAL's warp operation. A proj pipeline is used to pass the 4 parameters and define the transformation. These parameters are:

  • scale
    • the ratio of the distance between the GCPs geographic locations over the pixel space distance on the original
    • this is straightforward, no problems
  • rotation
    • the difference in calculated angles between the GCPs geographic coords and the GCPs pixel coords
    • this is a little tricker, and it is being calculated correctly, but I'm suspicious there are some extra 360 rotations or something...
  • x and y offset
    • the geographic position of the top left corner of the image
    • this was very tricky to figure out, and it is not completely handled (see below)
    • the current strategy goes like this:
      • take the location of a single GCP
      • calculate the geographic distance to the top and left edge of the page
      • use some trig functions to anticipate the offset based on these distances and the rotation angle

To do:

  • Finish the offset calculation
    The x and y offset does not work properly when the GCPs are in specific quadrants / at specific angles. In these instances the result also differs based on which of the two GCPs is used for the calculations (though neither works properly):
    image
  • Better modal content
  • Add docs (link in the modal?)
  • Should helmert even be in the transformation options list in the georeferencing interface? I'm inclined to remove it actually, and just force helmert when there are 2 gcps, and then default to polynomial 1 when there are 3 or more

@mradamcox
Copy link
Copy Markdown
Member Author

This is fully functional, so it is ready to merge to get more feedback. After that, documentation and an update to the modal can follow. For now, the new feature is behind a permissions wall (this served as a good excuse to set the foundation of a better permissions system anyway).

For users with permissions:

  1. In the georeferencing interface there is a new transformation option called "Helmert 4-param"
    • This option is disabled by default
  2. Once two GCPs have been added, the option is enabled, and the user can switch to it in the dropdown.
    • This enables the live preview, and also enables the "submit" button
  3. If a third GCP is added, then the transformation switches to Polynomial 1 automatically, and the Helmert 4-param option is disabled
    • Technically helmert can take more than 4 parameters, but as currently implemented, it is only written for 4, and the logic that generates the 4 parameters only uses two GCPs.

Further note about the permissions system:

Django has "Permissions" objects, "Groups", and "Users". Permission objects can be assigned to Groups, or directly to individual Users, while a User can be added to one or more Groups. So a User's full Permissions list is an aggregation of Permissions assigned to any Groups they are members of, plus any individual Permissions that have been directly assigned to them.

For the highest level of granularity, I think it is good practice for the code base to test against specific permissions rather to test against group membership.

With that in mind, this helmert transformation option tests against the core.use_helmert permission. In production, that permission could be added to a new Group, "beta testers" (or something like that) and any users added to that group would get the Helmert 4-param transformation as described above. Or, it could just be directly assigned to specific users.

@mradamcox mradamcox marked this pull request as ready for review June 5, 2026 15:56
difference = pt_degrees - px_degrees
return difference

def _calculate_helmert_offsets(self, scale: float, rotation: float) -> Tuple[float, float]:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have any unit tests for this code? It should be pretty amenable to it, and this would encourage me to try and clean up some of the if statements here :)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately no unit tests. It was a lot of trial and error within the interface to figure the math out, and those if clauses just ended up working. I'd have to take some time to actually figure out what the proper test cases would be, and yeah, I bet that section could be consolidated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants