Example #1
0
def load_lidar_file_by_polygon(lasfile,
                               polygon,
                               max_pts_per_tree=10**6,
                               print_keep=False):
    W = polygon[:, 0].min()
    E = polygon[:, 0].max()
    S = polygon[:, 1].min()
    N = polygon[:, 1].max()
    tile_pts = load_lidar_data_by_bbox(lasfile, N, S, E, W, print_npts=False)
    pts = lidar.filter_lidar_data_by_polygon(tile_pts, polygon, print_keep)
    # now create KDTrees
    starting_ids, trees = create_KDTree(pts)

    print "loaded ", pts.shape[0], " points"
    return pts, starting_ids, trees
def calculate_bestfit_LAD_profile(subplot_coordinate_file,
                                  LAI_file,
                                  las_file,
                                  Plot_name,
                                  minimum_height=0):
    subplot_polygons, subplot_labels = aux.load_boundaries(
        subplot_coordinate_file)
    field_LAI = aux.load_field_LAI(LAI_file)
    lidar_pts = lidar.load_lidar_data(las_file)

    n_subplots = subplot_polygons[Plot_name].shape[0]
    max_height = 80
    layer_thickness = 1
    n_layers = np.ceil(max_height / layer_thickness)
    subplot_lidar_profiles = np.zeros((n_subplots, n_layers))
    n_ground_returns = np.zeros(n_subplots)
    subplot_LAI = np.zeros(n_subplots)

    for i in range(0, n_subplots):
        print "Subplot: ", subplot_labels[Plot_name][i]
        sp_pts = lidar.filter_lidar_data_by_polygon(
            lidar_pts, subplot_polygons[Plot_name][i, :, :])
        heights, subplot_lidar_profiles[
            i, :], n_ground_returns[i] = bin_returns(sp_pts, max_height,
                                                     layer_thickness)
        subplot_LAI[i] = field_LAI['LAI'][np.all(
            (field_LAI['Subplot']
             == subplot_labels[Plot_name][i], field_LAI['Plot'] == Plot_name),
            axis=0)]

    kmin = 0.20
    kmax = 5.
    kinc = 0.005
    misfit, ks, best_k_LAD_profiles, best_k = minimise_misfit_for_k(
        kmin, kmax, kinc, subplot_LAI, subplot_lidar_profiles,
        n_ground_returns, layer_thickness, minimum_height)
    return heights, best_k_LAD_profiles
 #-------------------
 starting_ids, trees = io.create_KDTree(pts_iter)
 # loop through each sampling resolution
 for ss in range(0, sample_res.size):
     print('\t - sample res = ', keys[ss])
     n_subplots = len(subplots[keys[ss]])
     # for each of the subplots, clip point cloud and model PAD and get the metrics
     for pp in range(0, n_subplots):
         # query the tree to locate points of interest
         # note that we will only have one tree for the number of points in sensitivity analysis
         centre_x = np.mean(subplots[keys[ss]][pp][0:4, 0])
         centre_y = np.mean(subplots[keys[ss]][pp][0:4, 1])
         radius = np.sqrt(sample_res[ss]**2 / 2.)
         ids = trees[0].query_ball_point([centre_x, centre_y], radius)
         sp_pts = lidar.filter_lidar_data_by_polygon(
             pts_iter[ids],
             subplots[keys[ss]][pp],
             filter_by_first_return_location=True)
         #------
         if np.sum(sp_pts[:, 3] ==
                   1) > 0:  # check for returns within this column
             heights, first_return_profile, n_ground_returns = LAD1.bin_returns(
                 sp_pts, max_height, layer_thickness)
             mh_profile = LAD1.estimate_LAD_MacArthurHorn(
                 first_return_profile, n_ground_returns,
                 layer_thickness, kappa)
             pen_limit = np.cumsum(first_return_profile) == 0
             #------
             heights, weighted_return_profile, weighted_n_ground_returns = LAD1.bin_returns_weighted_by_num_returns(
                 sp_pts, max_height, layer_thickness)
             mh_wt_profile = LAD1.estimate_LAD_MacArthurHorn(
                 weighted_return_profile,
Example #4
0
            # get pixel boundaries
            pixel_bbox = np.array(
                [[x_iter - raster_res / 2., y_iter - raster_res / 2.],
                 [x_iter - raster_res / 2., y_iter + raster_res / 2.],
                 [x_iter + raster_res / 2., y_iter + raster_res / 2.],
                 [x_iter + raster_res / 2., y_iter - raster_res / 2.],
                 [x_iter - raster_res / 2., y_iter - raster_res / 2.]])

            # retrieve point clouds samples
            sample_pts = np.array([])
            for tt in range(0, N_trees):
                ids = trees[tt].query_ball_point([x_iter, y_iter], radius)
                if len(ids) > 0:
                    if sample_pts.size == 0:
                        sample_pts = lidar.filter_lidar_data_by_polygon(
                            lidar_pts[np.asarray(ids) +
                                      starting_ids_for_trees[tt]], pixel_bbox)
                        #sample_pts = lidar_pts[np.asarray(ids)+starting_ids_for_trees[tt]]
                    else:
                        sample_iter = lidar.filter_lidar_data_by_polygon(
                            lidar_pts[np.asarray(ids) +
                                      starting_ids_for_trees[tt]], pixel_bbox)
                        sample_pts = np.concatenate((sample_pts, sample_iter),
                                                    axis=0)
                        sample_iter = None

            # If we have the returns, then calculate metric of interest - in
            # this case the PAI
            if sample_pts.size > 0:
                if np.sum(sample_pts[:, 3] == 1) > 0:
                    # calculate PAD profile
Example #5
0
def load_lidar_data_by_polygon(file_list,
                               polygon,
                               max_pts_per_tree=10**6,
                               laz_files=False,
                               print_keep=False):
    W = polygon[:, 0].min()
    E = polygon[:, 0].max()
    S = polygon[:, 1].min()
    N = polygon[:, 1].max()
    if laz_files:
        keep_files = find_laz_files_by_polygon(file_list, polygon, print_keep)
    else:
        keep_files = find_las_files_by_polygon(file_list, polygon, print_keep)

    n_files = len(keep_files)
    trees = []
    starting_ids = np.asarray([])

    # first case scenario that no points in ROI
    print '\t\tloading %.0f tiles...' % n_files
    start = time.time()
    if n_files == 0:
        print 'WARNING: No files within specified polygon - try again'
        pts = np.array([])

    # otherwise, we have work to do!
    else:
        if laz_files:
            os.system("las2las %s temp.las" % keep_files[0])
            tile_pts = load_lidar_data_by_bbox('temp.las',
                                               N,
                                               S,
                                               E,
                                               W,
                                               print_npts=False)
            os.system("rm temp.las")
        else:
            tile_pts = load_lidar_data_by_bbox(keep_files[0],
                                               N,
                                               S,
                                               E,
                                               W,
                                               print_npts=False)

        pts = lidar.filter_lidar_data_by_polygon(tile_pts, polygon)

        # now repeat for subsequent tiles
        for i in range(1, n_files):
            if laz_files:
                os.system("las2las %s temp.las" % keep_files[i])
                tile_pts = load_lidar_data_by_bbox('temp.las',
                                                   N,
                                                   S,
                                                   E,
                                                   W,
                                                   print_npts=False)
                os.system("rm temp.las")
            else:
                tile_pts = load_lidar_data_by_bbox(keep_files[i],
                                                   N,
                                                   S,
                                                   E,
                                                   W,
                                                   print_npts=False)

            pts_ = lidar.filter_lidar_data_by_polygon(tile_pts, polygon)
            pts = np.concatenate((pts, pts_), axis=0)

    end = time.time()
    print '\t\t\t...%.3f s' % (end - start)
    # now create KDTrees
    print '\t\tbuilding KD-trees...'
    start = time.time()
    starting_ids, trees = create_KDTree(pts)
    end = time.time()
    print '\t\t\t...%.3f s' % (end - start)

    print "loaded ", pts.shape[0], " points into ", len(trees), " KDTrees"
    return pts, starting_ids, trees
                ids = trees_collated[pp][tt].query_ball_point(
                    np.array([centre_x, centre_y]), radius)
                if len(ids) > 0:
                    if sample_pts.size == 0:
                        sample_pts = lidar_pts[np.asarray(ids) +
                                               starting_ids_for_trees[tt]]
                    else:
                        sample_pts = np.concatenate(
                            (sample_pts,
                             lidar_pts[np.asarray(ids) +
                                       starting_ids_for_trees[tt]]),
                            axis=0)

            # keep only first returns
            sample_pts = sample_pts[sample_pts[:, 3] == 1, :]
            sp_pts = lidar.filter_lidar_data_by_polygon(
                sample_pts, subplots[pp][keys[ss]][sp])
            #------
            heights, first_return_profile, n_ground_returns = MH.bin_returns(
                sp_pts, max_height, layer_thickness)
            PADprof = MH.estimate_LAD_MacArthurHorn(first_return_profile,
                                                    n_ground_returns,
                                                    layer_thickness, k)
            # remove lowermost portion of profile
            PADprof[heights < min_height] = 0
            PAI_res[keys[ss]][pp, sp] = PADprof.sum()
        PAI_mean[pp, ss] = np.mean(PAI_res[keys[ss]][pp, :])
        PAI_sd[pp, ss] = np.std(PAI_res[keys[ss]][pp, :])

PAI_serr = np.zeros(PAI_sd.shape)
for pp in range(0, 3):
    for ss in range(0, res.size):
Example #7
0
        N_trees = len(trees)
        # for each of the subplots, clip point cloud and model PAD and get the metrics
        for pp in range(0,n_subplots):
            # query the tree to locate points of interest
            # note that we will only have one tree for the number of points in sensitivity analysis
            centre_x = np.mean(subplots[pp][0:4,0])
            centre_y = np.mean(subplots[pp][0:4,1])
            radius = np.sqrt(sample_res**2/2.)

            # retrieve point clouds samples
            sp_pts = np.array([])
            for tt in range(0,N_trees):
                ids = trees[tt].query_ball_point([centre_x,centre_y], radius)
                if len(ids)>0:
                    if sp_pts.size==0:
                        sp_pts = lidar.filter_lidar_data_by_polygon(pts_iter[np.asarray(ids)+starting_ids[tt]],subplots[pp])
                    else:
                        sp_iter = lidar.filter_lidar_data_by_polygon(pts_iter[np.asarray(ids)+starting_ids[tt]],subplots[pp])
                        sp_pts = np.concatenate((sp_pts,sp_iter),axis=0)
                        sp_iter = None
                #------
            if sp_pts.size==0:
                PAD_profiles_MH[keys[dd]][ii,pp,:] = np.nan
                PAD_profiles_rad2[keys[dd]][ii,pp,:]=np.nan
                penetration_limit[keys[dd]][ii,pp,:] = 1.
            elif np.sum(sp_pts[:,3]==1)>0:
                heights,first_return_profile,n_ground_returns = LAD1.bin_returns(sp_pts, max_height, layer_thickness)
                PAD_profiles_MH[keys[dd]][ii,pp,:] = LAD1.estimate_LAD_MacArthurHorn(first_return_profile, n_ground_returns, layer_thickness, kappa)
                penetration_limit[keys[dd]][ii,pp,:] = np.cumsum(first_return_profile)==0
                #------
                u,n,I,U = LAD2.calculate_LAD_DTM(sp_pts,heights_rad,max_k,'spherical')
a_ht, b_ht, CF_ht, a_A, b_A, CF_A = field.calculate_allometric_equations_from_survey(
    field_data)

# load LAI estimates from hemiphotos
field_LAI = aux.load_field_LAI(LAI_file)

# loop through all plots to be analysed
for pp in range(0, N_plots):
    print Plots[pp]
    Plot_name = Plots[pp]
    # clip LiDAR point cloud to plot level (this makes subsequent processing much faster)
    n_coord_pairs = subplot_polygons[Plot_name].shape[0] * subplot_polygons[
        Plot_name].shape[1]
    coord_pairs = subplot_polygons[Plot_name].reshape(n_coord_pairs, 2)
    bbox_polygon = aux.get_bounding_box(coord_pairs)
    plot_lidar_pts = lidar.filter_lidar_data_by_polygon(
        all_lidar_pts, bbox_polygon)

    # get some subplot-level information
    n_subplots = subplot_polygons[Plot_name].shape[0]
    # set up some arrays to host the radiative transfer based profiles
    heights_rad = np.arange(0, max_height + layer_thickness, layer_thickness)
    LAD_rad = np.zeros((n_subplots, heights_rad.size, max_return))
    LAD_rad_DTM = np.zeros((n_subplots, heights_rad.size, max_return))

    # set up some arrays to host the MacArthur-Horn profiles
    #heights = np.arange(0,max_height)+1
    heights = np.arange(0, max_height, layer_thickness) + layer_thickness
    LAD_MH = np.zeros((n_subplots, heights.size))

    # set up array to host the lidar return profiles
    lidar_return_profiles = np.zeros(
Example #9
0
# MAIN ANALYSIS
# LiDAR PROFILES LOOP
# loop through all plots to be analysed
for pp in range(0, N_plots):
    print(Plots[pp])
    Plot_name = Plots[pp]
    n_subplots = subplot_polygons[Plot_name].shape[0]

    #------------------------------------------------------------------------------------
    # CLIP DATA TO PLOT
    # clip LiDAR point cloud to plot level (this makes subsequent processing much faster)
    n_coord_pairs = subplot_polygons[Plot_name].shape[0] * subplot_polygons[
        Plot_name].shape[1]
    coord_pairs = subplot_polygons[Plot_name].reshape(n_coord_pairs, 2)
    bbox_polygon = aux.get_bounding_box(coord_pairs)
    plot_lidar_pts = lidar.filter_lidar_data_by_polygon(
        all_lidar_pts, bbox_polygon, filter_by_first_return_location=True)

    #------------------------------------------------------------------------------------
    # SET UP ARRAYS TO HOST RESULTS
    # get some subplot-level information
    n_subplots = subplot_polygons[Plot_name].shape[0]
    for ss in range(0, n_subplots):
        subplot_index = int(subplot_labels[Plot_name][ss] - 1)
        # filter lidar points into subplot
        sp_pts = lidar.filter_lidar_data_by_polygon(
            plot_lidar_pts,
            subplot_polygons[Plot_name][ss, :, :],
            filter_by_first_return_location=True)

    # set up some arrays to host the radiative transfer based profiles
    PAD_pla = np.zeros((n_subplots, heights_rad.size, max_return))
# store profiles in dictionaries
radiative_spherical_LAD = {}
radiative_spherical_adjusted_LAD = {}
radiative_spherical_no_azimuth_LAD = {}
lidar_profiles ={}
lidar_profiles_adjusted = {}

#subplot_polygons, subplot_labels = aux.load_boundaries(subplot_coordinate_file)
subplot_polygons = aux.load_generic_boundaries(coordinate_file)
all_pts = lidar.load_lidar_data(las_file)

for pp in range(0,N_plots):
    Plot_name=Plots[pp]
    bbox_polygon = subplot_polygons[Plot_name] 
    print Plot_name
    lidar_pts = lidar.filter_lidar_data_by_polygon(all_pts,bbox_polygon)

    heights_rad = np.arange(0,max_height+1)
    LAD_profiles_spherical=np.zeros((heights_rad.size,max_return))
    LAD_profiles_spherical_adjusted=np.zeros((heights_rad.size,max_return))
    LAD_profiles_spherical_no_azimuth=np.zeros((heights_rad.size,max_return))
    # first get LAD distribution following Detto et al., 2015
    for rr in range(0,max_return):
        max_k=rr+1
        u,n,I,U = LAD2.calculate_LAD(lidar_pts,heights_rad,max_k,'spherical')
        LAD_profiles_spherical[:,rr]=u.copy()
    lidar_profiles[Plot_name] = np.sum(n.copy(),axis=1)
    # now retrieve LAD distribution using correction for imperfect penetration
    for rr in range(0,max_return):
        max_k=rr+1
        u,n,I,U = LAD2.calculate_LAD_DTM(lidar_pts,heights_rad,max_k,'spherical')
chm = np.zeros((rows,cols),dtype='float')*np.nan

#-----------------------------------------------------
# now get highest return in each grid cell to define the CHM
print("generating CHM")
#-------------------
starting_ids, trees = io.create_KDTree(pts)
# for each of the subplots, clip point cloud and model PAD and get the metrics
for pp in range(0,n_subplots):
    # query the tree to locate points of interest
    # note that we will only have one tree for the number of points in sensitivity analysis
    centre_x = np.mean(subplots[pp][0:4,0])
    centre_y = np.mean(subplots[pp][0:4,1])
    radius = np.sqrt(sample_res**2/2.)
    ids = trees[0].query_ball_point([centre_x,centre_y], radius)
    sp_pts = lidar.filter_lidar_data_by_polygon(pts[ids],subplots[pp],filter_by_first_return_location=False)
    #------
    if np.sum(sp_pts[:,2]>=0)>0: # check for returns within this column
        chm[row_idx[pp],col_idx[pp]] = np.max(sp_pts[:,2])
    else:
        # adaptive neighbourhood expansion to account for penetration
        # limitations, particularly for fine grids/low point densities
        nodata_test = np.isnan(chm[row_idx[pp],col_idx[pp]])

        while nodata_test:
            # expand neighbourhood for point cloud sample
            sp_pts_iter = pts[trees[0].query_ball_point([centre_x,centre_y], radius)]
            if np.sum(sp_pts_iter[:,2]>=0)>0: # check for returns within this column
                chm[row_idx[pp],col_idx[pp]] = np.max(sp_pts_iter[:,2])
            radius+=0.5
            nodata_test = np.isnan(chm[row_idx[pp],col_idx[pp]])
Example #12
0
# MAIN ANALYSIS
# LiDAR PROFILES LOOP
# loop through all plots to be analysed
for pp in range(0, N_plots):
    print(Plots[pp])
    Plot_name = Plots[pp]
    n_subplots = subplot_polygons[Plot_name].shape[0]

    #------------------------------------------------------------------------------------
    # CLIP DATA TO PLOT
    # clip LiDAR point cloud to plot level (this makes subsequent processing much faster)
    n_coord_pairs = subplot_polygons[Plot_name].shape[0] * subplot_polygons[
        Plot_name].shape[1]
    coord_pairs = subplot_polygons[Plot_name].reshape(n_coord_pairs, 2)
    bbox_polygon = aux.get_bounding_box(coord_pairs)
    plot_lidar_pts = lidar.filter_lidar_data_by_polygon(
        all_lidar_pts, bbox_polygon, filter_by_first_return_location=True)
    starting_ids, trees = io.create_KDTree(
        plot_lidar_pts)  # build kd-tree for plot lidar points
    print("canopy height = ",
          np.percentile(plot_lidar_pts[plot_lidar_pts[:, 3] == 1, 2], 99), "m")

    #------------------------------------------------------------------------------------
    # SET UP ARRAYS TO HOST RESULTS
    # get some subplot-level information
    n_subplots = subplot_polygons[Plot_name].shape[0]

    # set up some arrays to host the MacArthur-Horn profiles
    LAD_MH = np.zeros((n_subplots, heights.size))

    #------------------------------------------------------------------------------------
    # LOOP THROUGH SUBPLOTS, CALCULATING CANOPY PROFILES
Example #13
0
                                                   6, 0, :][0]
    elif plot == 'DC1':
        plot_origin[plot] = subplot_polygons[plot][subplot_labels['DC1'] == 1,
                                                   3, :][0]
    elif plot == 'DC2':
        plot_origin[plot] = subplot_polygons[plot][subplot_labels['DC2'] == 1,
                                                   3, :][0]
    else:
        plot_origin[plot] = subplot_polygons[plot][0, 0, :]

    # clip LiDAR point cloud to plot level (this makes subsequent processing much faster)
    n_coord_pairs = subplot_polygons[plot].shape[0] * subplot_polygons[
        plot].shape[1]
    coord_pairs = subplot_polygons[plot].reshape(n_coord_pairs, 2)
    bbox_polygon = aux.get_bounding_box_with_buffer(coord_pairs, buffer_width)
    plot_pts[plot] = lidar.filter_lidar_data_by_polygon(
        lidar_pts, bbox_polygon)

# clear up some memory
lidar_pts = None

# Load in the traits
cleaning_scheme = 1  # 0 = mine, 1 = Sabine's, 2 = conservative
branch, spp, genus, N, Narea, C, CNratio, SLA, LMA, LeafArea, LeafThickness, LeafHeight, VPD, Rd, Vcmax, Jmax, ShadeTag, gs, ftype = field.collate_branch_level_traits(
    chem_file, photo_file, branch_file, leaf_file, spp_file, cleaning_scheme)

# Filter traits data
LeafThickness[LeafThickness > 0.60] = np.nan
Vcmax[Vcmax > 150] = np.nan
#LMA[LMA>0.025]=np.nan
N[N > 4] = np.nan
#Narea*=10.**3
        #print '\t\t', target_point_density[dd],'-' , pts_iter.shape[0]/100.**2 , count
        starting_ids, trees = io.create_KDTree(pts_iter)
        # loop through each sampling resolution
        for ss in range(0, sample_res.size):
            print '\t - sample res = ', keys[ss]
            n_subplots = len(subplots[keys[ss]])
            # for each of the subplots, clip point cloud and model PAD and get the metrics
            for pp in range(0, n_subplots):
                # query the tree to locate points of interest
                # note that we will only have one tree for number of points in sensitivity analysis
                centre_x = np.mean(subplots[keys[ss]][pp][0:4, 0])
                centre_y = np.mean(subplots[keys[ss]][pp][0:4, 1])
                radius = np.sqrt(sample_res[ss]**2 / 2.)
                ids = trees[0].query_ball_point([centre_x, centre_y], radius)
                sp_pts = lidar.filter_lidar_data_by_polygon(
                    pts_iter[ids], subplots[keys[ss]][pp])
                #------
                heights, first_return_profile, n_ground_returns = LAD1.bin_returns(
                    sp_pts, max_height, layer_thickness)
                PAD_profiles_MH[keys[ss]][keys_2[dd]][
                    ii, pp, :] = LAD1.estimate_LAD_MacArthurHorn(
                        first_return_profile, n_ground_returns,
                        layer_thickness, kappa)
                #------
                u, n, I, U = LAD2.calculate_LAD(sp_pts, heights_rad, max_k,
                                                'spherical')
                PAD_profiles_rad1[keys[ss]][keys_2[dd]][
                    ii, pp, :] = u[::-1][1:].copy()
                #------
                u, n, I, U = LAD2.calculate_LAD_DTM(sp_pts, heights_rad, max_k,
                                                    'spherical')