diff --git a/nibio_postprocessing/las_to_pandas.py b/nibio_postprocessing/las_to_pandas.py index 05ca58a38f87e7a518986e0183203269f7a9c63e..08acfa2e8222d7d6c2836ba2e49d1a80bc38954e 100644 --- a/nibio_postprocessing/las_to_pandas.py +++ b/nibio_postprocessing/las_to_pandas.py @@ -2,7 +2,7 @@ import numpy as np import pandas as pd import laspy -def las_to_pandas(las_file_path, csv_file_path): +def las_to_pandas(las_file_path, csv_file_path, save_csv=True): """ Reads a LAS file and converts it to a pandas dataframe, then saves it to a CSV file. @@ -30,4 +30,7 @@ def las_to_pandas(las_file_path, csv_file_path): points_df = pd.DataFrame(all_points, columns=all_columns) # Save pandas dataframe to csv - points_df.to_csv(csv_file_path, index=False, header=True, sep=',') + if save_csv: + points_df.to_csv(csv_file_path, index=False, header=True, sep=',') + + return points_df diff --git a/nibio_preprocessing/label_based_low_veg_relabelling.py b/nibio_preprocessing/label_based_low_veg_relabelling.py new file mode 100644 index 0000000000000000000000000000000000000000..cbf4069bd20e3721db191f9e2dc4efba503176fb --- /dev/null +++ b/nibio_preprocessing/label_based_low_veg_relabelling.py @@ -0,0 +1,58 @@ +from typing import Any +from nibio_postprocessing.las_to_pandas import las_to_pandas +from nibio_postprocessing.pandas_to_las import pandas_to_las + + +class LabelBasedLowVegRelabelling(object): + GROUND_CLASS = 1 + VEGETATION_CLASS = 2 + + def __init__(self, input_las_file, output_las_file, verbose) -> None: + self.input_las_file = input_las_file + self.output_las_file = output_las_file + self.verbose = verbose + + def relabel(self): + # Read the file + df = las_to_pandas(self.input_las_file, self.verbose, save_csv=False) + + # get all the rows which belong to the vegetation (2) class (label) and have treeID 0 and move it to ground class (1) + df.loc[(df['label'] == self.VEGETATION_CLASS) & (df['treeID'] == 0), 'label'] = self.GROUND_CLASS + + # save the dataframe to a new las file + pandas_to_las(df, self.output_las_file, csv_file_provided=False, verbose=self.verbose) + + if self.verbose: + print(f"Relabelled {self.input_las_file} and saved to {self.output_las_file}") + + def run(self): + self.relabel() + if self.verbose: + print("Relabelling complete.") + + def __call__(self) -> Any: + self.run() + + +if __name__ == '__main__': + import argparse + parser = argparse.ArgumentParser(description='Relabel low vegetation to ground class') + parser.add_argument('-i', '--input_las_file', help='Input LAS file', required=True) + parser.add_argument('-o', '--output_las_file', help='Output LAS file', required=True) + parser.add_argument('-v', '--verbose', action='store_true', help="Print information about the process") + + args = vars(parser.parse_args()) + + input_las_file = args['input_las_file'] + output_las_file = args['output_las_file'] + verbose = args['verbose'] + + # create an instance of LabelBasedLowVegRelabelling class + label_based_low_veg_relabelling = LabelBasedLowVegRelabelling( + input_las_file=input_las_file, + output_las_file=output_las_file, + verbose=verbose + ) + + # call main function + label_based_low_veg_relabelling() \ No newline at end of file diff --git a/nibio_preprocessing/label_based_low_veg_relabelling_in_folder.py b/nibio_preprocessing/label_based_low_veg_relabelling_in_folder.py new file mode 100644 index 0000000000000000000000000000000000000000..e803811f8d1fcf93d58d8235ed3a6674a430987c --- /dev/null +++ b/nibio_preprocessing/label_based_low_veg_relabelling_in_folder.py @@ -0,0 +1,49 @@ +import os +import glob +from joblib import Parallel, delayed +from nibio_preprocessing.label_based_low_veg_relabelling import LabelBasedLowVegRelabelling + +def process_single_file(input_file, output_folder, verbose): + try: + file_name = os.path.basename(input_file) + file_name = file_name.replace('.las', '_relabeled.las') + output_file = os.path.join(output_folder, file_name) + + if verbose: + print(f"Processing {file_name}...") + + relabeller = LabelBasedLowVegRelabelling(input_file, output_file, verbose) + relabeller() + + except Exception as e: + print(f"Error processing {file_name}: {e}") + import traceback + print(traceback.format_exc()) + +def process_directory(input_folder, output_folder, verbose=False): + # Make sure output folder exists, if not, create it + if not os.path.exists(output_folder): + os.makedirs(output_folder) + + # List all .las files in the input folder + input_files = glob.glob(os.path.join(input_folder, "*.las")) + + # Parallel processing + n_jobs = -1 # Use all available cores + Parallel(n_jobs=n_jobs)(delayed(process_single_file)(input_file, output_folder, verbose) for input_file in input_files) + + +if __name__ == "__main__": + import argparse + parser = argparse.ArgumentParser(description='Process all LAS files in a folder to relabel low vegetation to ground class.') + parser.add_argument('-i', '--input_folder', help='Input folder containing LAS files', required=True) + parser.add_argument('-o', '--output_folder', help='Output folder to store relabeled LAS files', required=True) + parser.add_argument('-v', '--verbose', action='store_true', help="Print information about the process") + + args = vars(parser.parse_args()) + + input_folder = args['input_folder'] + output_folder = args['output_folder'] + verbose = args['verbose'] + + process_directory(input_folder, output_folder, verbose)