1

I have written an image rectification function which allows a user to select 2 points on an image and 2 points on a map. The function will then rectify the image so it is translated, scaled and rotated to fit the two points on the map.

The code I have written works perfectly along the equator. However this function 'breaks' when moving further north or south. The rotation and the scale are both wrong. I believe this is because of the Mercator projection I use which stretches along the latitude axis.

I am unsure how to proceed. Is there a bit of math I am unaware of which will compensate for the stretching along the latitude? Or am I wrong in my assumption this is because of the Mercator projection?

Below you will find the code I use:

// transformFromPoints is an array with the two coordinates on the image
// They are in lat long
var fromPointA = this.transformFromPoints[0];
var fromPointB = this.transformFromPoints[1];

// transformToPoints is an array with the two coordinates on the map
// They are in lat long
var toPointA = this.transformToPoints[0];
var toPointB = this.transformToPoints[1];

// This is the img we want to transform
var img = this.activeBaseMapImg;

// First update the anchor so the anchor is exactly at fromPointA
// The anchor defines the point around which the image will be drawn
// This is also the point around which the image is rotated.
var cornerPoints = img.getCornerPoints();
var xAnchorPos = M.Math.projectPointOnLine(fromPointA, cornerPoints[0], cornerPoints[1]);
var yAnchorPos = M.Math.projectPointOnLine(fromPointA, cornerPoints[0], cornerPoints[3]);

var xAnchorDir = M.Math.subVector2(xAnchorPos, cornerPoints[0]);
var xLineDir = M.Math.subVector2(cornerPoints[1], cornerPoints[0]);
var yAnchorDir = M.Math.subVector2(yAnchorPos, cornerPoints[0]);
var yLineDir = M.Math.subVector2(cornerPoints[3], cornerPoints[0]);

var xAnchor = xAnchorDir.x / xLineDir.x;
var yAnchor = yAnchorDir.y / yLineDir.y;

// Set the anchor at the fromPointA location
img.setAnchor({x: xAnchor, y: yAnchor});

// Move the image to the toPointA location
img.setPosition(toPointA);

var fromDirection = M.Math.subVector2(fromPointB, fromPointA);
var toDirection = M.Math.subVector2(toPointB, toPointA);

// Determine scale
var scale = toDirection.length() / fromDirection.length();

// Determine rotation
var fromAngle = Math.atan2(fromDirection.y, fromDirection.x);
var toAngle = Math.atan2(toDirection.y, toDirection.x);

var angle = fromAngle - toAngle;

// Perform rotation and scale
img.setRotation(img.rotation + angle);
img.setSize({width: img.size.width * scale, height: img.size.height * scale});

If you need any more information to help in answering this question, please let me know.

  • is this python ? I also don't see any spatial reference object in the code which I think could be relevant. – jbchurchill Jul 24 '14 at 12:51
  • Hello jbchurcill, thank you for your reply. The code is Javascript not Python. What do you mean with spatial reference object? I am sorry I am still very new to this field. Should I add some more information to my original question? – Mathyn Jul 24 '14 at 14:15
  • You may get more eyes on this if you tag with the term "javascript". I was referring to arcpy.SpatialReference in python. This is probably out of my depth if using javascript for this type of thing. I would have probably pursued something like this with a Geoprocessing tool in ArcGIS server but I don't have a lot of experience with that yet either. – jbchurchill Jul 24 '14 at 16:12
  • I've added the Javascript tag, thank you for the suggestion. – Mathyn Jul 25 '14 at 7:44
2

I believe you need a minimum of 3 points to translate, scale, and rotate. The procedure and open source code for doing this is explained here: http://docs.opencv.org/doc/tutorials/imgproc/imgtrans/warp_affine/warp_affine.html I'm assuming your images are not georeferenced, so it should not matter what your map projection is since the user only has to match 3 points on the image to 3 map coordinates.

  • I agree with the above. Also, you should generally try to rectify the image with a basemap in the same projection as the image. – Stephen Lead Aug 5 '14 at 23:27
  • 1
    Would you be able to expand upon your very brief answer perhaps by referring to some relevant documentation, please? – PolyGeo Aug 5 '14 at 23:35
  • 1
    If the scale is a single scale, aka this is a 2D conformal transformation, then the minimum is 2 points. A 2D affine transformation needs 3 points. Perhaps expand your answer that the OP will get better results if he implements an affine tfm instead? – mkennedy Aug 5 '14 at 23:55
  • Thank you for the explanation and link. I have successfully implemented an image rectification function using 2 points. I believe this works because the image will remain a rectangle. Looking at the link you have given me I believe using 3 points might give better results, so I'll look into that. Thanks. – Mathyn Aug 6 '14 at 7:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.