[GRASS-dev] LiDAR LAS import

Hi all,

GRASS 7 has a new module v.in.lidar for importing LiDAR LAS files
(*.las or *.laz). The LAS file format is commonly used for storing
LiDAR point clouds, but is unfortunately not supported by OGR.
v.in.lidar uses the libLAS library [0] and is only compiled if the
libLAS library is present.

I chose to use the library instead of writing a custom LAS reading
interface because the current LAS library version 1.6.1 is stable,
supports LAS file versions 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, each of
which can store LiDAR points in up to 5 different point formats. The
user and the interface do not need to know the file version and point
format of a given file, all that is conveniently handled by the libLAS
library in the background. The library has Large File Support (LFS)
and is well tested on different platforms, also with different
endian-ness. This functionality is not that easy to replicate.

You will need to get the libLAS library and configure GRASS 7 with
--with-liblas in order to have the module available. Please test!

Markus M

[0] http://www.liblas.org

Markus Metz wrote:

Hi all,

GRASS 7 has a new module v.in.lidar for importing LiDAR LAS files
(*.las or *.laz). The LAS file format is commonly used for storing
LiDAR point clouds, but is unfortunately not supported by OGR.
v.in.lidar uses the libLAS library [0] and is only compiled if the
libLAS library is present.

I chose to use the library instead of writing a custom LAS reading
interface because the current LAS library version 1.6.1 is stable,
supports LAS file versions 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, each of
which can store LiDAR points in up to 5 different point formats. The
user and the interface do not need to know the file version and point
format of a given file, all that is conveniently handled by the libLAS
library in the background. The library has Large File Support (LFS)
and is well tested on different platforms, also with different
endian-ness. This functionality is not that easy to replicate.

You will need to get the libLAS library and configure GRASS 7 with
--with-liblas in order to have the module available. Please test!

Markus M

[0] http://www.liblas.org

neat! any time trials to say how much faster it is than piping
las2txt | v.in.ascii
?

fyi I have plans (but more ideas than time I'm afraid) to also add a
stream= option to r.in.xyz with the possible options of ascii, las, mbio.
There'll probably be another option added to select signal strength, etc.
but I might overload the z= column parameter to accept strings for that(?).

(MBIO is for MB-System's multibeam sonar input library, Bob Covill already
has this integrated in a custom fork)

cheers,
Hamish

_______________________________________________
grass-user mailing list
grass-user@lists.osgeo.org
http://lists.osgeo.org/mailman/listinfo/grass-user

Yes!!! Thank you Markus! Since you are using liblas 1.6.1 , I assume that this command can read the losslessly compressed .laz format?

Will try soon.

Doug

Doug Newcomb
USFWS
Raleigh, NC
919-856-4520 ext. 14 doug_newcomb@fws.gov

The opinions I express are my own and are not representative of the official policy of the U.S.Fish and Wildlife Service or Dept. of the Interior. Life is too short for undocumented, proprietary data formats.

Markus Metz <markus.metz.giswork@googlemail.com>
Sent by: grass-dev-bounces@lists.osgeo.org

05/25/2011 05:31 AM

To

grass-user <grass-user@lists.osgeo.org>, GRASS developers list <grass-dev@lists.osgeo.org>

cc

Subject

[GRASS-dev] LiDAR LAS import

Hi all,

GRASS 7 has a new module v.in.lidar for importing LiDAR LAS files
(*.las or *.laz). The LAS file format is commonly used for storing
LiDAR point clouds, but is unfortunately not supported by OGR.
v.in.lidar uses the libLAS library [0] and is only compiled if the
libLAS library is present.

I chose to use the library instead of writing a custom LAS reading
interface because the current LAS library version 1.6.1 is stable,
supports LAS file versions 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, each of
which can store LiDAR points in up to 5 different point formats. The
user and the interface do not need to know the file version and point
format of a given file, all that is conveniently handled by the libLAS
library in the background. The library has Large File Support (LFS)
and is well tested on different platforms, also with different
endian-ness. This functionality is not that easy to replicate.

You will need to get the libLAS library and configure GRASS 7 with
--with-liblas in order to have the module available. Please test!

Markus M

[0] ``http://www.liblas.org
_______________________________________________
grass-dev mailing list
grass-dev@lists.osgeo.org
http://lists.osgeo.org/mailman/listinfo/grass-dev

On Wed, May 25, 2011 at 12:16 PM, Hamish <hamish_b@yahoo.com> wrote:

Markus Metz wrote:

Hi all,

GRASS 7 has a new module v.in.lidar for importing LiDAR LAS files
(*.las or *.laz). The LAS file format is commonly used for storing
LiDAR point clouds, but is unfortunately not supported by OGR.
v.in.lidar uses the libLAS library [0] and is only compiled if the
libLAS library is present.

I chose to use the library instead of writing a custom LAS reading
interface because the current LAS library version 1.6.1 is stable,
supports LAS file versions 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, each of
which can store LiDAR points in up to 5 different point formats. The
user and the interface do not need to know the file version and point
format of a given file, all that is conveniently handled by the libLAS
library in the background. The library has Large File Support (LFS)
and is well tested on different platforms, also with different
endian-ness. This functionality is not that easy to replicate.

You will need to get the libLAS library and configure GRASS 7 with
--with-liblas in order to have the module available. Please test!

Markus M

[0] http://www.liblas.org

neat! any time trials to say how much faster it is than piping
las2txt | v.in.ascii
?

Note that las2txt does NOT apply scale and offset to x,y,z, this would
need to be done afterwards in order to obtain correct coordinates.
Therefore the output of las2txt | v.in.ascii with the sample las file
I used is incorrect.

I discovered a bug in v.in.ascii: from a point file with | as field
separator like

1|2|3||5|6

only the first 3 columns will be imported because column 4 is empty
which means that columns 5 and 6 are skipped.

v.in.lidar is a notch faster than las2txt | v.in.ascii. And easier to use...
Speed comparisons:

# sample las file with 1,287,775 points

# with table and topology
time las2txt -i points.las --stdout --parse xyztinrcCpedRGBau
--delimiter "|" | v.in.ascii in=- out=points_ascii -z x=1 y=2 z=3 --o

real 6m34.430s
user 4m57.530s
sys 2m3.693s

time v.in.lidar in=points.las out=points_las -o --o

real 6m13.823s
user 4m32.061s
sys 2m1.068s

# without table, with topology
time las2txt -i points.las --stdout --parse xyz --delimiter "|" |
v.in.ascii in=- out=points_ascii -zt x=1 y=2 z=3 --o

real 1m53.578s
user 1m47.032s
sys 0m9.238s

time v.in.lidar in=points.las out=points_las -ot --o

real 1m44.876s
user 1m34.450s
sys 0m8.488s

On Wed, May 25, 2011 at 1:45 PM, <Doug_Newcomb@fws.gov> wrote:

Yes!!! Thank you Markus! Since you are using liblas 1.6.1 , I assume that this command can read the losslessly compressed .laz format?

As long as libLAS is compiled with laszip support, yes (tested and working).

Markus Metz wrote:

Note that las2txt does NOT apply scale and offset to x,y,z,
this would need to be done afterwards in order to obtain
correct coordinates.
Therefore the output of las2txt | v.in.ascii with the
sample las file I used is incorrect.

I guess a v.transform step would be needed, with another hit of
rebuilding the topology.

I discovered a bug in v.in.ascii: from a point file with |
as field separator like

1|2|3||5|6

only the first 3 columns will be imported because column 4
is empty which means that columns 5 and 6 are skipped.

roughly/quickly:
echo "1|2|3||5|6" | v.in.ascii in=- out=gaptest
v.db.select gaptest

GRASS 6.4.0+42329 bug
GRASS 6.5.svn45825M no bug
GRASS 7.0.svn45737M no bug

I'll try with latest svn in the morning.

perhaps this was fixed by the v.in.ascii last-row-is-empty bugfix
some months ago?

v.in.lidar is a notch faster than las2txt | v.in.ascii. And
easier to use...

I'm not too surprised the speed difference is not so huge, as
unix pipes are very efficient. but the easier to use thing is
very important.. both las2txt and v.in.ascii are a bundle of
command line switches to get right.

Speed comparisons:

# sample las file with 1,287,775 points

# with table and topology

...

real 6m34.430s

...

real 6m13.823s

...

# without table, with topology

...

real 1m53.578s

...

real 1m44.876s

I take it that without topology it runs in just seconds?
my RAID runs at ~300mb/sec. 1.3m points isn't pushing memory
limits into swap space. there's no real tough math happening
here, just moving bits around... me thinks it's time to break
out the profiling tools. aka why shouldn't this take less than
5 sec to run, even with no-op points topology + dbf creation?

Hamish

On Wed, May 25, 2011 at 4:02 PM, Hamish <hamish_b@yahoo.com> wrote:

Markus Metz wrote:

Note that las2txt does NOT apply scale and offset to x,y,z,
this would need to be done afterwards in order to obtain
correct coordinates.
Therefore the output of las2txt | v.in.ascii with the
sample las file I used is incorrect.

I guess a v.transform step would be needed, with another hit of
rebuilding the topology.

Yes.

I discovered a bug in v.in.ascii: from a point file with |
as field separator like

1|2|3||5|6

only the first 3 columns will be imported because column 4
is empty which means that columns 5 and 6 are skipped.

roughly/quickly:
echo "1|2|3||5|6" | v.in.ascii in=- out=gaptest
v.db.select gaptest

GRASS 6.4.0+42329 bug
GRASS 6.5.svn45825M no bug
GRASS 7.0.svn45737M no bug

I'll try with latest svn in the morning.

perhaps this was fixed by the v.in.ascii last-row-is-empty bugfix
some months ago?

Weird. My local copy is a few hours old, my quick test case
"1|2|3||5|6" works, but not the stream coming from las2txt.

v.in.lidar is a notch faster than las2txt | v.in.ascii. And
easier to use...

I'm not too surprised the speed difference is not so huge, as
unix pipes are very efficient. but the easier to use thing is
very important.. both las2txt and v.in.ascii are a bundle of
command line switches to get right.

I would like to add more options, e.g. what columns to import, but
v.in.lidar works just fine with v.in.lidar in=in.las out=out_grass

[...]

I take it that without topology it runs in just seconds?

Yes.

my RAID runs at ~300mb/sec. 1.3m points isn't pushing memory
limits into swap space. there's no real tough math happening
here, just moving bits around... me thinks it's time to break
out the profiling tools. aka why shouldn't this take less than
5 sec to run, even with no-op points topology + dbf creation?

I used sqlite, no idea how long it will take with dbf. And it is still
nearly 1.3 million points with attributes, las2txt produces a 94MB
ascii file. Reading can be done in 5sec, especially if the system has
already cached the file, but writing takes a bit longer.

For GRASS 7, I want to slim down vector topology some more, I guess
the import time could be reduced by half. There is a reason to have
some topology even for points: a spatial index which would make
spatial queries and selections much faster.

Markus M

MMetz:

> I discovered a bug in v.in.ascii: from a point file with |
> as field separator like
>
> 1|2|3||5|6
>
> only the first 3 columns will be imported because column 4
> is empty which means that columns 5 and 6 are skipped.

Hamish:

roughly/quickly:
echo "1|2|3||5|6" | v.in.ascii in=- out=gaptest
v.db.select gaptest

GRASS 6.4.0+42329 bug
GRASS 6.5.svn45825M no bug
GRASS 7.0.svn45737M no bug

I'll try with latest svn in the morning.

latest svn builds, all branches: no bug with v.in.ascii.
I did not test v.in.ogr for it yet.
?

perhaps this was fixed by the v.in.ascii last-row-is-empty
bugfix some months ago?

(ticket #198)

Hamish

Hi Markus,

Just compiled again liblas svn trunk, everything is working as expected so far.

Thanks heaps for that new functionality, this is really very useful.

Pierre

2011/5/25 Markus Metz <markus.metz.giswork@googlemail.com>:

Hi all,

GRASS 7 has a new module v.in.lidar for importing LiDAR LAS files
(*.las or *.laz). The LAS file format is commonly used for storing
LiDAR point clouds, but is unfortunately not supported by OGR.
v.in.lidar uses the libLAS library [0] and is only compiled if the
libLAS library is present.

I chose to use the library instead of writing a custom LAS reading
interface because the current LAS library version 1.6.1 is stable,
supports LAS file versions 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, each of
which can store LiDAR points in up to 5 different point formats. The
user and the interface do not need to know the file version and point
format of a given file, all that is conveniently handled by the libLAS
library in the background. The library has Large File Support (LFS)
and is well tested on different platforms, also with different
endian-ness. This functionality is not that easy to replicate.

You will need to get the libLAS library and configure GRASS 7 with
--with-liblas in order to have the module available. Please test!

Markus M

[0] http://www.liblas.org
_______________________________________________
grass-dev mailing list
grass-dev@lists.osgeo.org
http://lists.osgeo.org/mailman/listinfo/grass-dev

--
Scientist
Landcare Research, New Zealand

MarkusM wrote:

I used sqlite, no idea how long it will take with dbf.

dbf is so simple that it is very fast to write to flat files.
but because it is so simple it becomes slow, or unable, when you want to
do something complex.

There is a reason to have some topology even for points: a spatial index
which would make spatial queries and selections much faster.

I believe that Howard & co. have been experimenting with different spatial
index methods for points in the development version of libLAS, with good
results. It's probably worth comparing notes about lessons learned.

Hamish

Hamish wrote:

Markus Metz wrote:

[snip]

v.in.lidar is a notch faster than las2txt | v.in.ascii. And
easier to use...

I'm not too surprised the speed difference is not so huge, as
unix pipes are very efficient. but the easier to use thing is
very important.. both las2txt and v.in.ascii are a bundle of
command line switches to get right.

Speed comparisons:

# sample las file with 1,287,775 points

# with table and topology

...

real 6m34.430s

...

real 6m13.823s

...

# without table, with topology

...

real 1m53.578s

...

real 1m44.876s

I take it that without topology it runs in just seconds?

Update: no attribute table, no topology

time las2txt -i points.las --stdout --parse xyz --delimiter "|" |
v.in.ascii in=- out=points_ascii -ztb x=1 y=2 z=3

real 0m20.932s
user 0m18.424s
sys 0m6.869s

time v.in.lidar in=points.las out=points_las -obt

real 0m9.117s
user 0m2.946s
sys 0m5.985s

Markus M

Markus,
Were you planning on adding filtering options by return number on v.in.lidar? It occurs to me that you could speed things up by only processing the subset of the data that you want to use. I could see it being a useful thing to create a vector layer composed only of 1st returns ( top of canopy/buildings) Selecting only last returns is useful, as well as selecting points that are neither first nor last returns .

I’ve been primarily working with aggregate las files that I have dumped to text ( via liblas las2txt ) and then parse via python for first, middle, and last returns. I have not taken the time to learn C yet, but perhaps the logic of these simple python programs would be useful .

The following is the python script I use to separate the last returns.

import struct,os,string,re,binascii,glob
infile = raw_input("Enter the aggregate lidar filename: ")
outfil = raw_input("Enter the ASCII output filename for the Lidar Data: ")
intxt=open(infile,‘r’)
outtxt=open(outfil,‘w’)
while 1:
lasline=intxt.readline()
lasinfo=lasline.split(‘,’)
if (len(lasinfo))< 5:break
numreturns=int(lasinfo[4])
returnnum=int(lasinfo[5])

In the data input file for this instance, the number of returns

is the fifth column, and the return number is the sixth column ( x=1,y=2,z=3,intensity=4).

If the value of these colums is equal, it should be the last return.

if ( numreturns==returnnum):
outtxt.write(lasline)

intxt.close()
outtxt.close()

For parsing the first returns, substitute if (returnnum==1):

Here is the python script I use to separate out the “middle” returns.


import struct,os,string,re,binascii,glob
infile = raw_input("Enter the aggregate lidar filename: ")
outfil = raw_input("Enter the ASCII output filename for the Lidar Data: ")
intxt=open(infile,‘r’)
outtxt=open(outfil,‘w’)
while 1:
lasline=intxt.readline()
lasinfo=lasline.split(‘,’)
if (len(lasinfo))< 5:break
numreturns=int(lasinfo[4])
returnnum=int(lasinfo[5])

In the data input file for this instance, the number of returns

is the fifth column, and the return number is the sixth column ( x=1,y=2,z=3,intensity=4).

If the value of these colums is equal, it should be the last return, so skip that entry

If the return number is 1 , skip that value. All other values are middle canopy values,which is what we want.

if ( numreturns==returnnum): continue
if (returnnum==1):continue
outtxt.write(lasline)
intxt.close()
outtxt.close()

I really appreciate your adding lidar data classifications from the standard into the program. I haven’t actually seen any lidar data with classifications yet, but I have hope for the future :-).

As a bit of background , I’m taking the last returns and then running r.in.xyz to create a raster with the intensities as the z values to get relative soil moistures, and looking at points that are neither first nor last returns as a possible measure of vegetation density. It works great for large datasets( > 4 billion points) , but I’m feeling the need for more point analysis.

Doug

Doug Newcomb
USFWS
Raleigh, NC
919-856-4520 ext. 14 doug_newcomb@fws.gov

The opinions I express are my own and are not representative of the official policy of the U.S.Fish and Wildlife Service or Dept. of the Interior. Life is too short for undocumented, proprietary data formats.

Markus Metz <markus.metz.giswork@googlemail.com>
Sent by: grass-dev-bounces@lists.osgeo.org

06/03/2011 02:20 AM

To

Hamish <hamish_b@yahoo.com>

cc

GRASS developers list <grass-dev@lists.osgeo.org>

Subject

[GRASS-dev] Re: [GRASS-user] LiDAR LAS import

Hamish wrote:
> Markus Metz wrote:
[snip]
>
>> v.in.lidar is a notch faster than las2txt | v.in.ascii. And
>> easier to use...
>
> I'm not too surprised the speed difference is not so huge, as
> unix pipes are very efficient. but the easier to use thing is
> very important.. both las2txt and v.in.ascii are a bundle of
> command line switches to get right.
>
>
>> Speed comparisons:
>>
>> # sample las file with 1,287,775 points
>>
>> # with table and topology
> ...
>> real 6m34.430s
> ...
>> real 6m13.823s
> ...
>> # without table, with topology
> ...
>> real 1m53.578s
> ...
>> real 1m44.876s
>
>
> I take it that without topology it runs in just seconds?

Update: no attribute table, no topology

time las2txt -i points.las --stdout --parse xyz --delimiter "|" |
v.in.ascii in=- out=points_ascii -ztb x=1 y=2 z=3

real 0m20.932s
user 0m18.424s
sys 0m6.869s

time v.in.lidar in=points.las out=points_las -obt

real 0m9.117s
user 0m2.946s
sys 0m5.985s

Markus M
_______________________________________________
grass-dev mailing list
grass-dev@lists.osgeo.org
http://lists.osgeo.org/mailman/listinfo/grass-dev

On Fri, Jun 3, 2011 at 3:30 PM, <Doug_Newcomb@fws.gov> wrote:

Markus,
Were you planning on adding filtering options by return number on v.in.lidar? It occurs to me that you could speed things up by only processing the subset of the data that you want to use. I could see it being a useful thing to create a vector layer composed only of 1st returns ( top of canopy/buildings) Selecting only last returns is useful, as well as selecting points that are neither first nor last returns .

Yes, I was thinking of such filter options, they would be very easy and straightforward to implement, something like v.in.lidar returns=[all,first,last,middle]. Currently there is only spatial filtering available.

I was also thinking about an option to select columns to be imported as attributes, equivalent to the las2txt --parse option, but could not yet come up with a user-friendly solution: flags don’t work because too many and conflicting with existing flags, a parse option very much like the one of las2txt is too cryptic. I think I will settle for something like v.in.lidar attributes=coords,classes,color,egde,angle,return,nreturns,… where the attributes option takes none, one or multiple answers

Markus M

I’ve been primarily working with aggregate las files that I have dumped to text ( via liblas las2txt ) and then parse via python for first, middle, and last returns. I have not taken the time to learn C yet, but perhaps the logic of these simple python programs would be useful .

The following is the python script I use to separate the last returns.

import struct,os,string,re,binascii,glob
infile = raw_input("Enter the aggregate lidar filename: ")
outfil = raw_input("Enter the ASCII output filename for the Lidar Data: ")
intxt=open(infile,‘r’)
outtxt=open(outfil,‘w’)
while 1:
lasline=intxt.readline()
lasinfo=lasline.split(‘,’)
if (len(lasinfo))< 5:break
numreturns=int(lasinfo[4])
returnnum=int(lasinfo[5])

In the data input file for this instance, the number of returns

is the fifth column, and the return number is the sixth column ( x=1,y=2,z=3,intensity=4).

If the value of these colums is equal, it should be the last return.

if ( numreturns==returnnum):
outtxt.write(lasline)

intxt.close()
outtxt.close()

For parsing the first returns, substitute if (returnnum==1):

Here is the python script I use to separate out the “middle” returns.


import struct,os,string,re,binascii,glob
infile = raw_input("Enter the aggregate lidar filename: ")
outfil = raw_input("Enter the ASCII output filename for the Lidar Data: ")
intxt=open(infile,‘r’)
outtxt=open(outfil,‘w’)
while 1:
lasline=intxt.readline()
lasinfo=lasline.split(‘,’)
if (len(lasinfo))< 5:break
numreturns=int(lasinfo[4])
returnnum=int(lasinfo[5])

In the data input file for this instance, the number of returns

is the fifth column, and the return number is the sixth column ( x=1,y=2,z=3,intensity=4).

If the value of these colums is equal, it should be the last return, so skip that entry

If the return number is 1 , skip that value. All other values are middle canopy values,which is what we want.

if ( numreturns==returnnum): continue
if (returnnum==1):continue
outtxt.write(lasline)
intxt.close()
outtxt.close()

I really appreciate your adding lidar data classifications from the standard into the program. I haven’t actually seen any lidar data with classifications yet, but I have hope for the future :-).

As a bit of background , I’m taking the last returns and then running r.in.xyz to create a raster with the intensities as the z values to get relative soil moistures, and looking at points that are neither first nor last returns as a possible measure of vegetation density. It works great for large datasets( > 4 billion points) , but I’m feeling the need for more point analysis.

Doug

Doug Newcomb
USFWS
Raleigh, NC
919-856-4520 ext. 14 doug_newcomb@fws.gov

The opinions I express are my own and are not representative of the official policy of the U.S.Fish and Wildlife Service or Dept. of the Interior. Life is too short for undocumented, proprietary data formats.

Markus Metz <markus.metz.giswork@googlemail.com>
Sent by: grass-dev-bounces@lists.osgeo.org

06/03/2011 02:20 AM

To

Hamish <hamish_b@yahoo.com>

cc

GRASS developers list <grass-dev@lists.osgeo.org>

Subject

[GRASS-dev] Re: [GRASS-user] LiDAR LAS import

Hamish wrote:
> Markus Metz wrote:
[snip]
>
>> v.in.lidar is a notch faster than las2txt | v.in.ascii. And
>> easier to use...
>
> I'm not too surprised the speed difference is not so huge, as
> unix pipes are very efficient. but the easier to use thing is
> very important.. both las2txt and v.in.ascii are a bundle of
> command line switches to get right.
>
>
>> Speed comparisons:
>>
>> # sample las file with 1,287,775 points
>>
>> # with table and topology
> ...
>> real 6m34.430s
> ...
>> real 6m13.823s
> ...
>> # without table, with topology
> ...
>> real 1m53.578s
> ...
>> real 1m44.876s
>
>
> I take it that without topology it runs in just seconds?

Update: no attribute table, no topology

time las2txt -i points.las --stdout --parse xyz --delimiter "|" |
v.in.ascii in=- out=points_ascii -ztb x=1 y=2 z=3

real 0m20.932s
user 0m18.424s
sys 0m6.869s

time v.in.lidar in=points.las out=points_las -obt

real 0m9.117s
user 0m2.946s
sys 0m5.985s

Markus M
_______________________________________________
grass-dev mailing list
[grass-dev@lists.osgeo.org](mailto:grass-dev@lists.osgeo.org)
http://lists.osgeo.org/mailman/listinfo/grass-dev

Markus,
Were you planning on adding filtering options by return number on v.in.lidar? It occurs to me that you could speed things up by only processing the subset of the data that you want to >>use. I could see it being a useful thing to create a vector layer composed only of 1st returns ( top of canopy/buildings) Selecting only last returns is useful, as well as selecting points that >>are neither first nor last returns .
Yes, I was thinking of such filter options, they would be very easy and straightforward to implement, something like v.in.lidar returns=[all,first,last,middle]. Currently there is only spatial >filtering available.
Excellent!

I was also thinking about an option to select columns to be imported as attributes, equivalent to the las2txt --parse option, but could not yet come up with a user-friendly solution: flags >don’t work because too many and conflicting with existing flags, a parse option very much like the one of las2txt is too cryptic. I think I will settle for something like v.in.lidar >attributes=coords,classes,color,egde,angle,return,nreturns,… where the attributes option takes none, one or multiple answers

Sounds good. That would have the advantage of “standardizing” the lidar attibute names for future lidar point processing modules in GRASS

Markus M

Doug

Doug Newcomb
USFWS
Raleigh, NC
919-856-4520 ext. 14 doug_newcomb@fws.gov

The opinions I express are my own and are not representative of the official policy of the U.S.Fish and Wildlife Service or Dept. of the Interior. Life is too short for undocumented, proprietary data formats.

Markus Metz <markus.metz.giswork@googlemail.com>

06/03/2011 10:36 AM

To

Doug_Newcomb@fws.gov

cc

GRASS developers list <grass-dev@lists.osgeo.org>

Subject

Re: [GRASS-dev] ] LiDAR LAS import - filter on import?

On Fri, Jun 3, 2011 at 3:30 PM, <Doug_Newcomb@fws.gov> wrote:

Markus,
Were you planning on adding filtering options by return number on v.in.lidar? It occurs to me that you could speed things up by only processing the subset of the data that you want to use. I could see it being a useful thing to create a vector layer composed only of 1st returns ( top of canopy/buildings) Selecting only last returns is useful, as well as selecting points that are neither first nor last returns .

Yes, I was thinking of such filter options, they would be very easy and straightforward to implement, something like v.in.lidar returns=[all,first,last,middle]. Currently there is only spatial filtering available.

I was also thinking about an option to select columns to be imported as attributes, equivalent to the las2txt --parse option, but could not yet come up with a user-friendly solution: flags don’t work because too many and conflicting with existing flags, a parse option very much like the one of las2txt is too cryptic. I think I will settle for something like v.in.lidar attributes=coords,classes,color,egde,angle,return,nreturns,… where the attributes option takes none, one or multiple answers

Markus M

I’ve been primarily working with aggregate las files that I have dumped to text ( via liblas las2txt ) and then parse via python for first, middle, and last returns. I have not taken the time to learn C yet, but perhaps the logic of these simple python programs would be useful .

The following is the python script I use to separate the last returns.

import struct,os,string,re,binascii,glob
infile = raw_input("Enter the aggregate lidar filename: ")
outfil = raw_input("Enter the ASCII output filename for the Lidar Data: ")
intxt=open(infile,‘r’)
outtxt=open(outfil,‘w’)
while 1:
lasline=intxt.readline()
lasinfo=lasline.split(‘,’)
if (len(lasinfo))< 5:break
numreturns=int(lasinfo[4])
returnnum=int(lasinfo[5])

In the data input file for this instance, the number of returns

is the fifth column, and the return number is the sixth column ( x=1,y=2,z=3,intensity=4).

If the value of these colums is equal, it should be the last return.

if ( numreturns==returnnum):
outtxt.write(lasline)

intxt.close()
outtxt.close()

For parsing the first returns, substitute if (returnnum==1):

Here is the python script I use to separate out the “middle” returns.


import struct,os,string,re,binascii,glob
infile = raw_input("Enter the aggregate lidar filename: ")
outfil = raw_input("Enter the ASCII output filename for the Lidar Data: ")
intxt=open(infile,‘r’)
outtxt=open(outfil,‘w’)
while 1:
lasline=intxt.readline()
lasinfo=lasline.split(‘,’)
if (len(lasinfo))< 5:break
numreturns=int(lasinfo[4])
returnnum=int(lasinfo[5])

In the data input file for this instance, the number of returns

is the fifth column, and the return number is the sixth column ( x=1,y=2,z=3,intensity=4).

If the value of these colums is equal, it should be the last return, so skip that entry

If the return number is 1 , skip that value. All other values are middle canopy values,which is what we want.

if ( numreturns==returnnum): continue
if (returnnum==1):continue
outtxt.write(lasline)
intxt.close()
outtxt.close()

I really appreciate your adding lidar data classifications from the standard into the program. I haven’t actually seen any lidar data with classifications yet, but I have hope for the future :-).

As a bit of background , I’m taking the last returns and then running r.in.xyz to create a raster with the intensities as the z values to get relative soil moistures, and looking at points that are neither first nor last returns as a possible measure of vegetation density. It works great for large datasets( > 4 billion points) , but I’m feeling the need for more point analysis.

Doug

Doug Newcomb
USFWS
Raleigh, NC
919-856-4520 ext. 14 doug_newcomb@fws.gov

The opinions I express are my own and are not representative of the official policy of the U.S.Fish and Wildlife Service or Dept. of the Interior. Life is too short for undocumented, proprietary data formats.

Markus Metz <markus.metz.giswork@googlemail.com>
Sent by: grass-dev-bounces@lists.osgeo.org

06/03/2011 02:20 AM

To

Hamish <hamish_b@yahoo.com>

cc

GRASS developers list <grass-dev@lists.osgeo.org>

Subject

[GRASS-dev] Re: [GRASS-user] LiDAR LAS import

Hamish wrote:
> Markus Metz wrote:
[snip]
>
>> v.in.lidar is a notch faster than las2txt | v.in.ascii. And
>> easier to use...
>
> I'm not too surprised the speed difference is not so huge, as
> unix pipes are very efficient. but the easier to use thing is
> very important.. both las2txt and v.in.ascii are a bundle of
> command line switches to get right.
>
>
>> Speed comparisons:
>>
>> # sample las file with 1,287,775 points
>>
>> # with table and topology
> ...
>> real 6m34.430s
> ...
>> real 6m13.823s
> ...
>> # without table, with topology
> ...
>> real 1m53.578s
> ...
>> real 1m44.876s
>
>
> I take it that without topology it runs in just seconds?

Update: no attribute table, no topology

time las2txt -i points.las --stdout --parse xyz --delimiter "|" |
v.in.ascii in=- out=points_ascii -ztb x=1 y=2 z=3

real 0m20.932s
user 0m18.424s
sys 0m6.869s

time v.in.lidar in=points.las out=points_las -obt

real 0m9.117s
user 0m2.946s
sys 0m5.985s

Markus M
_______________________________________________
grass-dev mailing list
grass-dev@lists.osgeo.org
http://lists.osgeo.org/mailman/listinfo/grass-dev

Markus Metz wrote:

Hi all,

GRASS 7 has a new module v.in.lidar for importing LiDAR LAS files
(*.las or *.laz). The LAS file format is commonly used for storing
LiDAR point clouds, but is unfortunately not supported by OGR.
v.in.lidar uses the libLAS library [0] and is only compiled if the
libLAS library is present.

The equivalent r.in.lidar is now available in GRASS 7. It behaves
exactly like r.in.xyz, but takes LAS files as input.

Additionally, all bugs mentioned in the r.in.xyz manual should be
fixed in r.in.lidar and can easily be ported to r.in.xyz. In the
long(mid?)-term, r.in.xyz and r.in.lidar should be merged, as
described in the r.in.xyz TODO.

Markus M

That's great, thanks, Markus!

I don't know if I understood that 100% correctly - do I need to compile
GRASS 7 from source in order to be able to use it? Is there a way to get it
running on an already installed version of GRASS 7 from the repository?

--
View this message in context: http://osgeo-org.1803224.n2.nabble.com/LiDAR-LAS-import-tp6402014p6416885.html
Sent from the Grass - Users mailing list archive at Nabble.com.

hi mark,

great job. and thanks for supporting both LAS and LAZ.

supports LAS file versions 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, each of
which can store LiDAR points in up to 5 different point formats.

Just a minor correction. the supported LAS file versions range from 1.0 to
1.3. And yes, the 1.3 version can store LiDAR points in up to 5 different
point formats.

Note that las2txt does NOT apply scale and offset to x,y,z, this would
need to be done afterwards in order to obtain correct coordinates.
Therefore the output of las2txt | v.in.ascii with the sample las file
I used is incorrect.

I don't think this is true. Obviously you are using the las2txt version from
libLAS but when libLAS branched off LAStools the scaling and offsetting was
already correctly supported. If not, you could maybe compare the outputs of
LAStools txt2las and libLAS txt2las and let Howard know if there is
something wrong.

# with table and topology
time las2txt -i points.las --stdout --parse xyztinrcCpedRGBau
--delimiter "|" | v.in.ascii in=- out=points_ascii -z x=1 y=2 z=3 --o

Why did you use this elaborate parse string when all you need is xyz? The
temporary ASCII representation that goes through the pipe with parse string
"xyztinrcCpedRGBau" will be several multiples the size of a parse string
"xyz".

I would have expected that the libLAS import module would be several times
faster than piping route via temporary ASCII conversion. Is the reason that
the ASCII translation costs are not bigger because you are running of a
multi-core machine? Or maybe the built-in routines that I am using are much
slower than yours. How do you do ASCII conversion?

Again, kudos for adding LAS and LAZ to GRASS. Wow ... that rhymes. (-:

Martin

--
View this message in context: http://osgeo-org.1803224.n2.nabble.com/LiDAR-LAS-import-tp6402014p6431063.html
Sent from the Grass - Users mailing list archive at Nabble.com.

On Thu, Jun 2, 2011 at 3:06 PM, isenburg <martin.isenburg@gmail.com> wrote:

Note that las2txt does NOT apply scale and offset to x,y,z, this would
need to be done afterwards in order to obtain correct coordinates.
Therefore the output of las2txt | v.in.ascii with the sample las file
I used is incorrect.

I don't think this is true. Obviously you are using the las2txt version from
libLAS but when libLAS branched off LAStools the scaling and offsetting was
already correctly supported. If not, you could maybe compare the outputs of
LAStools txt2las and libLAS txt2las and let Howard know if there is
something wrong.

Found it, the libLAS documentation is wrong:
-->
LAS_DLL double LASPoint_GetX(const LASPointH hPoint)

Returns the X value for the point.

This value is not scaled or offset by any header values and stands on
its own. If you need points to have a scale and/or offset applied,
this must be done in conjunction with the header values after the
value is read.
<--

This not true, scale and offset are applied, I checked the libLAS
source code. I will fix v.in.lidar asap.

# with table and topology
time las2txt -i points.las --stdout --parse xyztinrcCpedRGBau
--delimiter "|" | v.in.ascii in=- out=points_ascii -z x=1 y=2 z=3 --o

Why did you use this elaborate parse string when all you need is xyz? The
temporary ASCII representation that goes through the pipe with parse string
"xyztinrcCpedRGBau" will be several multiples the size of a parse string
"xyz".

Because v.in.ascii will import all the other fields into an attribute
table, and I wanted to test that.

I would have expected that the libLAS import module would be several times
faster than piping route via temporary ASCII conversion. Is the reason that
the ASCII translation costs are not bigger because you are running of a
multi-core machine? Or maybe the built-in routines that I am using are much
slower than yours. How do you do ASCII conversion?

It was a quadcore 64bit machine, and linux pipes are really fast. The
time goes into creating an attribute table and creating a spatial
index, not so much in reading the las (or laz) file.

Markus M

Hello,

Just trying to install GRASS 7 on Ubuntu 10.04 to try out the las import functions but I’m getting error messages during the configure that it is unable to find the liblas library, however the liblas library is installed in usr/bin/lib/ so I’m a bit puzzled…

Did anyone else get stuck here or am I missing something obvious?

Thanks for reading,
Rebecca


From: Markus Metz markus.metz.giswork@googlemail.com
To: Hamish hamish_b@yahoo.com
Cc: grass-user grass-user@lists.osgeo.org; GRASS developers list grass-dev@lists.osgeo.org
Sent: Wednesday, 25 May 2011, 12:48
Subject: Re: [GRASS-user] LiDAR LAS import

On Wed, May 25, 2011 at 12:16 PM, Hamish <hamish_b@yahoo.com> wrote:

Markus Metz wrote:

Hi all,

GRASS 7 has a new module v.in.lidar for importing LiDAR LAS files
(*.las or *.laz). The LAS file format is commonly used for storing
LiDAR point clouds, but is unfortunately not supported by OGR.
v.in.lidar uses the libLAS library [0] and is only compiled if the
libLAS library is present.

I chose to use the library instead of writing a custom LAS reading
interface because the current LAS library version 1.6.1 is stable,
supports LAS file versions 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, each of
which can store LiDAR points in up to 5 different point formats. The
user and the interface do not need to know the file version and point
format of a given file, all that is conveniently handled by the libLAS
library in the background. The library has Large File Support (LFS)
and is well tested on different platforms, also with different
endian-ness. This functionality is not that easy to replicate.

You will need to get the libLAS library and configure GRASS 7 with
–with-liblas in order to have the module available. Please test!

Markus M

[0] http://www.liblas.org

neat! any time trials to say how much faster it is than piping
las2txt | v.in.ascii
?

Note that las2txt does NOT apply scale and offset to x,y,z, this would
need to be done afterwards in order to obtain correct coordinates.
Therefore the output of las2txt | v.in.ascii with the sample las file
I used is incorrect.

I discovered a bug in v.in.ascii: from a point file with | as field
separator like

1|2|3||5|6

only the first 3 columns will be imported because column 4 is empty
which means that columns 5 and 6 are skipped.

v.in.lidar is a notch faster than las2txt | v.in.ascii. And easier to use…
Speed comparisons:

sample las file with 1,287,775 points

with table and topology

time las2txt -i points.las --stdout --parse xyztinrcCpedRGBau
–delimiter “|” | v.in.ascii in=- out=points_ascii -z x=1 y=2 z=3 --o

real 6m34.430s
user 4m57.530s
sys 2m3.693s

time v.in.lidar in=points.las out=points_las -o --o

real 6m13.823s
user 4m32.061s
sys 2m1.068s

without table, with topology

time las2txt -i points.las --stdout --parse xyz --delimiter “|” |
v.in.ascii in=- out=points_ascii -zt x=1 y=2 z=3 --o

real 1m53.578s
user 1m47.032s
sys 0m9.238s

time v.in.lidar in=points.las out=points_las -ot --o

real 1m44.876s
user 1m34.450s
sys 0m8.488s


grass-user mailing list
grass-user@lists.osgeo.org
http://lists.osgeo.org/mailman/listinfo/grass-user

Rebecca Bennett wrote:

Hello,
Just trying to install GRASS 7 on Ubuntu 10.04 to try out the las import
functions but I'm getting error messages during the configure that it is
unable to find the liblas library, however the liblas library is installed
in usr/bin/lib/ so I'm a bit puzzled...

Can you post the exact error message? Also, liblas support will only
be available if liblas-config exists.

Markus M

Did anyone else get stuck here or am I missing something obvious?
Thanks for reading,
Rebecca

________________________________
From: Markus Metz <markus.metz.giswork@googlemail.com>
To: Hamish <hamish_b@yahoo.com>
Cc: grass-user <grass-user@lists.osgeo.org>; GRASS developers list
<grass-dev@lists.osgeo.org>
Sent: Wednesday, 25 May 2011, 12:48
Subject: Re: [GRASS-user] LiDAR LAS import

On Wed, May 25, 2011 at 12:16 PM, Hamish <hamish_b@yahoo.com> wrote:

Markus Metz wrote:

Hi all,

GRASS 7 has a new module v.in.lidar for importing LiDAR LAS files
(*.las or *.laz). The LAS file format is commonly used for storing
LiDAR point clouds, but is unfortunately not supported by OGR.
v.in.lidar uses the libLAS library [0] and is only compiled if the
libLAS library is present.

I chose to use the library instead of writing a custom LAS reading
interface because the current LAS library version 1.6.1 is stable,
supports LAS file versions 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, each of
which can store LiDAR points in up to 5 different point formats. The
user and the interface do not need to know the file version and point
format of a given file, all that is conveniently handled by the libLAS
library in the background. The library has Large File Support (LFS)
and is well tested on different platforms, also with different
endian-ness. This functionality is not that easy to replicate.

You will need to get the libLAS library and configure GRASS 7 with
--with-liblas in order to have the module available. Please test!

Markus M

[0] http://www.liblas.org

neat! any time trials to say how much faster it is than piping
las2txt | v.in.ascii
?

Note that las2txt does NOT apply scale and offset to x,y,z, this would
need to be done afterwards in order to obtain correct coordinates.
Therefore the output of las2txt | v.in.ascii with the sample las file
I used is incorrect.

I discovered a bug in v.in.ascii: from a point file with | as field
separator like

1|2|3||5|6

only the first 3 columns will be imported because column 4 is empty
which means that columns 5 and 6 are skipped.

v.in.lidar is a notch faster than las2txt | v.in.ascii. And easier to use...
Speed comparisons:

# sample las file with 1,287,775 points

# with table and topology
time las2txt -i points.las --stdout --parse xyztinrcCpedRGBau
--delimiter "|" | v.in.ascii in=- out=points_ascii -z x=1 y=2 z=3 --o

real 6m34.430s
user 4m57.530s
sys 2m3.693s

time v.in.lidar in=points.las out=points_las -o --o

real 6m13.823s
user 4m32.061s
sys 2m1.068s

# without table, with topology
time las2txt -i points.las --stdout --parse xyz --delimiter "|" |
v.in.ascii in=- out=points_ascii -zt x=1 y=2 z=3 --o

real 1m53.578s
user 1m47.032s
sys 0m9.238s

time v.in.lidar in=points.las out=points_las -ot --o

real 1m44.876s
user 1m34.450s
sys 0m8.488s
_______________________________________________
grass-user mailing list
grass-user@lists.osgeo.org
http://lists.osgeo.org/mailman/listinfo/grass-user

_______________________________________________
grass-user mailing list
grass-user@lists.osgeo.org
http://lists.osgeo.org/mailman/listinfo/grass-user