NCSU home

From point cloud to raster DEM/DSM

E. Hardin, M.O. Kurum, H. Mitasova

Preprocessing lidar point cloud text files

# Raw LIDAR data often needs to be modified or altered to make it easier to handle. 
# For example, the text files may too large and cannot be opened using common 
# text editors like notepad or gedit but editing files can be done quickly 
# and easily using awk or sed and some examples of how to do so are given here. 
# Eric Pement compiled helpful awk and sed commands  
#
# View only the first line of a file, for example, to identify a header or 
# to determine the delimiter 
sed q /path/filename 

# View the first ten lines: 
sed 10q /path/filename 

# Remove the first line with awk or comment it out with sed
# (for example a header that is not needed)
awk 'NR>1{print $0}' /path/inputFile > /path/outputFile 
sed s/E/#E/ /path/inputFile > /path/outputFile

# Change the delimiter, for example, from | to , 
awk -F"|" '{OFS=","}{print $1,$2,$3}' /pathTo/MyInputFile > /pathTo/MyOutputFile 

# Merge many tiles, each with a header, and remove the headers. 
# In this example, each tile is a text file (.txt) and the headers start with 
# the word Easting as is the case of data obtained from NOAA. 
# Within the directory with the tiles concatenate every .txt file into a text 
# file called MyRawDataWHeaders and remove every line beginning with the word
# Easting regardless of what follows: 
cat *.txt > MyRawDataWHeaders 
sed '/Easting/d' MyRawDataWHeaders > MyRawData WoutHeaders 
Binning
# IN THE FOLLOWING EXAMPLES, YOU WILL NEED TO CD TO THE DIRECTORY WHERE YOUR DATA IS
# OR CHANGE THE PATHS OF THE INPUT 
# Compute raster maps where each raster cell shows the elevation range within that cell
# Compute univariate statistics on the maps
# If the average range is greater than the LIDAR accuracy, 
# then the DEM resolution should be finer
resolutions=( '0.5' '1' '10' )
method=range
for res in ${resolutions[@]}
do
    g.region res=${res} n=250777.5 s=250623.5 w=913677.5 e=913882.5
    r.in.xyz input=JR_19990909 out=JR_rinxyz_${method}_${res}m \
	fs="," method=${method} --o
    r.univar JR_rinxyz_${method}_${res}m
done
# The average ranges from the output of the r.univar command should be:
# 0.0288m, 0.120m, and 2.613m for the three resolutions

# Find extents of data using r.in.xyz and -s flag
r.in.xyz -s input=JR_20080327 output=extentScan method=mean fs="," x=1 y=2

# Import vector points within the current computational region (the -r flag)
g.region res=0.5 n=252949 s=249152 w=911642 e=914771 
for date in 19961016 19971002 19980907 19990909 19990918 19991104 2001 20040925 20051126 20080327
do
    v.in.ascii -ztbr input=JR_${date} output=JR_${date} format=point \
	fs=, skip=0 x=1 y=2 z=3 cat=0 
done

# Interpolation, smoothing and computation of slope and curvature
dates=( 19961016 19971002 19980907 19990909 19990918 19991104 2001 20040925 20051126 20080327 )
smoothing=( 1200 1200 500 1000 1000 1000 1500 1500 2000 2000 )
i=0
while [ $i -lt ${#dates[@]} ]
do
    v.surf.rst -t JR_${dates[i]} elev=JR_${dates[i]}_05mrst slope=JR_${dates[i]}_05mrst_slp \
	pcu=JR_${dates[i]}_05mrst_pcu layer=0 segm=40 npmin=120 dmin=0.3 ten=${smoothing[i]} sm=0.5
    i=$(( $i+1 ))
done

# Create a mask to limit the area that is being interpolated to the study region, exclude 
# water surface or interpolate smaller sections to prevent v.surf.rst running out of memory
r.digit
v.digit
r.mask or g.copy rast=mymask,MASK example here

# Masking based on contours, for example, shorelines
# Extract the shoreline at mean-high water level 
# copy the contour before digitizing because changes 
# (including mistakes) are applied to the map permanently 
r.contour MyElevation out=MyShoreline_036m level=0.36 cut=300  
g.copy vect=MyShoreline_036m,MyShorelineCopy_036m 

# Use v.digit to delete spurious contours, to connect the ends of the line 
# in order to define an area, and finally to add a centroid inside of the area 
v.digit map=MyShorelineCopy_036m bgcmd="d.rast MyMap" 
# Convert the line to a boundary 
is this step needed - should we save it from v.digit as area?
v.type input= MyShorelineCopy_036m output=MyVectorArea type=line,boundary  

# Convert the vector area to a raster 
v.to.rast input=MyVectorArea output=MyRasterArea use=val type=point,line,area  

# Multiply the elevation map by this raster map (mask) 
# to get an elevation map without the ocean 
r.mapcalc 'MyElevationWOutOcean=MyElevation*MyRasterArea'

# For large data sets, the module v.surf.rst may require more RAM than available. 
# and the processing needs to be done by overlapping tiles that are patched together
show here definition of the tiles for given data set to illustrate the overlap
north=252950
south=249152
increments=3
step=$(( ($north-$south)/$increments ))
s=$south
n=$(( $s+$step ))
dates=( 19961016 19971002 19980907 19990909 19990918 19991104 2001 20040925 20051126 20080327 )
smoothing=( 1200 1200 500 1000 1000 1000 1500 1500 2000 2000 )
for inc in `seq 1 1 $increments`
do
  g.region n=$n s=$s
  i=0
  while [ $i -lt ${#dates[@]} ]
  do
    v.surf.rst -t JR_${dates[i]} elev=JR_${dates[i]}_05mrst_tile${inc} slope=JR_${dates[i]}_05mrst_slp_tile${inc} \
       	    pcu=JR_${dates[i]}_05mrst_pcu_tile${inc} layer=0 segm=40 npmin=120 dmin=0.3 ten=${smoothing[i]} sm=0.5
    i=$(( $i+1 ))
  done
done
for date in ${dates[@]}
do
  r.patch input=JR_${dates[i]}_05mrst_tile1,JR_${dates[i]}_05mrst_tile2,JR_${dates[i]}_05mrst_tile3 \
	output=JR_${dates[i]}_05mrst
done

g.region rast=coast_2001_2m -p
d.erase
d.rast coast_2001_2m
Identification and reduction of systematic error