6

What steps do I need to do in order to calculate longitude and latitude for a specific pixel in a georeferenced image? For example this image http://www.shadedreliefarchive.com/medit_Mideast_africa_copy.html contains information, .tfw file:

1627.32174969982000 
0.00000000000000 
0.00000000000000 
-1627.32174969982000 
-4957506.34276705000000 
6096922.76188281000000 

and .prj file:

PROJCS["Lambert Azimuthal Equal-Area",
       GEOGCS["GCS_WGS_1984",
              DATUM["D_WGS_1984", SPHEROID["WGS_1984", 6378137, 298.257223563]],
              PRIMEM["Greenwich", 0],
              UNIT["Degree", 0.017453292519943295]],
       PROJECTION["Lambert_Azimuthal_Equal_Area"],
       PARAMETER["false_easting", 0],
       PARAMETER["false_northing", 0],
       PARAMETER["latitude_of_origin", 0],
       PARAMETER["central_meridian", 20],
       PARAMETER["xy_plane_rotation", 0],
       UNIT["Meter", 1]]

I've created this snippet of javascript to compute new x1 and y1 values for specific pixels in the image:

var A = 1627.32174969982000,
    D = 0.00000000000000,
    B = 0.00000000000000,
    E = -1627.32174969982000,
    C = -4957506.34276705000000,
    F = 6096922.76188281000000;

function x1(x, y) { return A*x + B*y + C; }

function y1(x, y) { return D*x + E*y + F; }

What more do I have to do to get longitude and latitude? For example C, F represents the top-left corner of the image, right? Then how do I translate C, F to get longitude and latitude?

I want do do it using javascript only, have looked at http://proj4js.org/ but don't really understand what to do with the values I get...

antonj
  • 169
  • 1
  • 1
  • 4
  • 1
    don't you need to reproject the raster image with a GIS package first? – Mapperz Apr 12 '11 at 14:10
  • Hopefully not, I would like to have a function to convert pixel positions in the image to long/lat positions and also preferable the reverse translation. – antonj Apr 12 '11 at 14:25
  • Just a comment: usually people use the coordinates of pixel centers for computing their (lat, lon). If that's your intention, then in your snippet you should therefore first add 1/2 to each of x and y (assuming they are row and column indices). – whuber Apr 12 '11 at 14:56
  • @whuber, that sounds reasonable – antonj Apr 12 '11 at 15:11
  • 1
    @whuber @antonj -- just a note that the .tfw already includes an offset to the pixel center; adding another 1/2 will put you at the bottom right of the pixel. (Line 5 & 6, the "origin" of the affine transform in the .tfw, are the coordinates of the center of the top-left pixel, not the coordinates of the top-left of the top-left pixel.) – Dan S. Apr 12 '11 at 15:55
  • @whuber @antonj -- my prior comment is half-remembered, but confirmed by the wikipedia link I gave in my answer. I wanted to add anyway that I'm fairly sure about the tfw and pixel centers but not 100% certain. – Dan S. Apr 12 '11 at 15:56
  • @Dan Good point. There are two conventions in use (and ESRI software uses them both): one sets the origin at a corner of the image and the other sets it in the center of a corner pixel. Furthermore, the ESRI format for world files has changed over time, adding further potential for confusion. I suspect you are correct, on the strength of the Wikipedia reference, but a prudent approach would be to test whatever software one is using. – whuber Apr 12 '11 at 17:28

2 Answers2

5

The .tfw represents the affine transform for the image -- how image pixel coordinates map to coordinates in the space defined by the .prj.

Here's an explanation of the values: http://en.wikipedia.org/wiki/World_file

Getting to geographic coordinates is thus a two-step process:

  • Find the coordinates of the pixel in the projected coordinate system
  • Unproject this coordinate back to the geographic coordinate system to arrive at lat & lon.

The formula for the first step:

X_proj = C + (A * X_img) + (B * Y_img) 
Y_proj = F + (E * Y_img) + (D * X_img)

Note: I'm using the variables A..F from the article I linked, not from your code above! I don't believe they correspond; the Wikipedia article chose labels that don't correspond to line numbers.

Now you have X & Y coordinates in your desired coordinate system. Since you're using Javascript (using proj4js; forgive me if I haven't tested the code below):

var source = new Proj4js.Proj('PROJ4_ARGS_FOR_YOUR_PROJECTION');
var dest = new Proj4js.Proj('EPSG:4326') // geographic coordinates + WGS84 (which matches the ellipsoid used in your .prj)

var p = new Proj4js.Point(X_proj, Y_proj) Proj4js.transform(source, dest, p)

// p.x & p.y are now lat & lon. (or lon & lat, can't recall coord order)

I used spatialrefrence.org to convert your .prj into arguments for Proj4; you can see it here by clicking on 'proj4': http://spatialreference.org/ref/sr-org/7119/ In general, .prj to proj4 args is a purely mechanical transformation.

PolyGeo
  • 65,136
  • 29
  • 109
  • 338
Dan S.
  • 3,549
  • 17
  • 20
2

I'm not much of a js programmer, but this works for me:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
<HTML>
<HEAD>
<TITLE>Geographic Coordinate Transformations in Javascript</TITLE>

<script src="lib/OLprototype.js"></script>
<script src="lib/proj4js-combined.js"></script>

<SCRIPT type="text/javascript">
// Put your projection definition here.
Proj4js.defs["EPSG:3575"] = "+proj=laea +lat_0=90 +lon_0=10 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs";

var A = 1627.32174969982000,
    D = 0.00000000000000,
    B = 0.00000000000000,
    E = -1627.32174969982000,
    C = -4957506.34276705000000,
    F = 6096922.76188281000000;

function frompixel(px, py) {
    px += 0.5; // Add a half-pixel offset to get the coordinates of the centre of the pixel.
    py += 0.5;
    return {x : A*px + B*py + C, y: D*px + E*py + F};
}

function tolatlong(x, y) {
    var src = new Proj4js.Proj('EPSG:3575'); // Same code as you defined above. Alternatively, let proj4js get the definition from spatialreference.org
    var dest = new Proj4js.Proj('EPSG:4326');
    var p = frompixel(x, y);

    document.write('From coordinates: ');
    document.writeln(p.x, ',', p.y);

    // This is the bit that does the transformation from map coordinates to lat/long.
    Proj4js.transform(src, dest, p);
    document.write('To lat/long: ');
    document.writeln(p.x, ',', p.y);
}
</SCRIPT>

</HEAD>
<BODY>
    <SCRIPT type="text/javascript">
    tolatlong(100, 100);
    </SCRIPT>
</BODY>
</HTML>

Naturally, you will have to play around with the code a bit to integrate it with your web page, but the principle should be right.

MerseyViking
  • 14,543
  • 1
  • 41
  • 75