[GIS] Converting LiDAR .las to .xyz with LAStools outputs incorrect projected coordinates

coordinate systemlastoolslidarutmxyz

I have an application that can import terrain data in an XYZ text format where X = latitude, Y = longitude and Z = elevation.

I am trying to convert a LiDAR .las file to this format using las2las.

I use las2las to convert the .las file and then read the converted .las file in Python using laspy to read the XYZ values. The X and Y values do not reflect the proper latitude/longitude of the area that the LiDAR file contains.

To illustrate, here is the .xml from the LiDAR file showing metadata, note that latitude around 46.XXXXXXXX and Longitude -96.XXXXXXX (which is what I expect):

<?xml version="1.0" standalone="yes"?>
<Metadata>
<EntityID>IWI_RedRiver-C_2008_000723</EntityID>
<ProjectName>IWI_RedRiver-C_2008</ProjectName>
<ProjectMetadataFiles>http://dds.cr.usgs.gov/lidar_v2/ND-MN/2008/IWI_RedRiver-C_2008/metadata/IWI_RedRiver-C_2008_metadata.zip</ProjectMetadataFiles>
<State>ND-MN</State>
<BeginDate>2008-04-21</BeginDate>
<EndDate>2008-05-16</EndDate>
<VerticalDatum>NAVD88</VerticalDatum>
<MapProjection>UTM</MapProjection>
<MapZone>14</MapZone>
<MapProjectionDefinition>PROJCS["NAD_1983_UTM_Zone_14N",GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",500000.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",-99.0],PARAMETER["Scale_Factor",0.9996],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0],AUTHORITY["EPSG",26914]]</MapProjectionDefinition>
<CenterLat>46.8520722</CenterLat>
<CenterLon>-96.8356110</CenterLon>
<ULLat>46.8613222</ULLat>
<ULLon>-96.8483721</ULLon>
<URLat>46.8608250</URLat>
<URLon>-96.8221249</URLon>
<LRLat>46.8428221</LRLat>
<LRLon>-96.8228554</LRLon>
<LLLat>46.8433194</LLLat>
<LLLon>-96.8490916</LLLon>
<MinX>664000.000</MinX>
<MaxX>665999.990</MaxX>
<MinY>5189999.998</MinY>
<MaxY>5191999.989</MaxY>
<MinZ>253.551</MinZ>
<MaxZ>330.992</MaxZ>
<VendorID>IWI_RedRiver-C_2008_R06645190</VendorID>
<NumOfPulseRecords>2559425</NumOfPulseRecords>
<NumOfPulsesByReturn>(1) 2424977 (2) 129573 (3) 4807 (4) 68</NumOfPulsesByReturn>
<NumOfPtRecords>2559425</NumOfPtRecords>
<NumOfPtsByReturn>(1) 2491531 (2) 66447 (3) 1442 (4) 5</NumOfPtsByReturn>
<Intensity>0,255</Intensity>
<NominalPulseSpacing>1.28432</NominalPulseSpacing>
<PulseDensity>0.60625</PulseDensity>
<PulseDensityNPSUnits>METER</PulseDensityNPSUnits>
<VendorNominalPulseSpacing>1.7</VendorNominalPulseSpacing>
<VendorPointDensity>.35</VendorPointDensity>
<VendorPointDensityNPSUnits>METER</VendorPointDensityNPSUnits>
<FileFormat>las</FileFormat>
<LASVersion>1.0</LASVersion>
</Metadata>

The LiDAR file I am trying to get lat/long from is called IWI_RedRiver-C_2008_000723.las so I run las2las with these parameters:

las2las -i c:\terrainfiles\lidar\IWI_RedRiver-C_2008_000723.las -o out.las -utm 14N -target_latlong

I get XYZ values in this range:

X,Y,Z:  8433152 -8240716 27584

It is not close to what I'm expecting from the .xml file (which is the correct lat/lon).

Am I using las2las wrong? I have tried other las2las params such as -epsg 26914, and -sp83 ND_S and I get different X,Y,Z values but still off.

For Example:

las2las -i c:\terrainfiles\lidar\IWI_RedRiver-C_2008_000723.las -o out.las -utm 14N -sp83 ND_S -target_latlong

produces :

X,Y,Z:  4590852 505294 27624

I see las2txt appears to do what I want from my Python script but it gives a completely different outcome as well. If I run it on the previous output of las2las with this command:

las2txt -parse xyz -i out.las -o out.xyz

I get output that looks like this:

86.4590852 -94.9494706 276.24
86.4590849 -94.9492982 276.24
86.4590847 -94.9491291 276.32
86.4590845 -94.9489549 276.24
86.4590842 -94.9487867 276.28
86.4590869 -94.9489067 284.62
86.4590894 -94.9488187 276.20

Is there a better way to convert LiDAR .las to XYZ where X and Y are latitude/longitude values?

Best Answer

I didn't expect that this would be the answer, but it turns out that las2las uses the UTM latitude band letters rather than the hemisphere 'N' (North) or 'S' (South) letters with the zone number. While not stated directly, I found an example in this help page

Here's an example from that page:

>> las2las -i s1885565.laz -o out.las -sp83 OH_S -feet -elevation_feet -target_sp83 OH_N -target_survey_feet -target_elevation_survey_feet 
>> las2las -i TO_core_last_zoom.laz -o out.laz -utm 17T
>> las2las -i TO_core_last_zoom.laz -o out.laz -utm 17T -target_latlong

Note the '-utm 17T'. The 'R', 'S', and 'T' bands are solidly in the contiguous United States (AKA lower 48). You can check out Wikipedia for more information on the latitude bands.

In this particular case, instead of using 14N, try using 14T.