lidar_label_builder.llb_tools
Utility functions for building a labeling database for Convolutional Neural Networks (CNNs).
This module provides a collection of secondary functions to assist with various tasks related to the construction of a labeling database for CNNs. Use these functions to streamline common operations involved in dataset preparation, annotation, and organization.
1""" 2Utility functions for building a labeling database for Convolutional Neural Networks (CNNs). 3 4This module provides a collection of secondary functions to assist with various tasks related to the 5construction of a labeling database for CNNs. Use these functions to streamline common operations involved in 6dataset preparation, annotation, and organization. 7 8""" 9 10import os 11import geopandas as gpd 12import lidar_label_builder as llb 13import pandas as pd 14import json 15from matplotlib import pyplot as plt 16from pathlib import Path 17 18#Connect To Global Variables 19# scriptDir = os.path.dirname(os.path.abspath(__file__)) 20# parentDir = os.path.dirname(scriptDir) 21# global_vars = os.path.join(parentDir, 'configs', 'global_variables.json') 22# with open(global_vars, 'r') as f: 23# params_dict = json.load(f) 24with (Path(__file__).resolve().parent.parent / 'configs' / 'global_variables.json').open('r') as f: 25 params_dict = json.load(f) 26 27LABEL_FILE_PATTERN = params_dict['LABEL_FILE_PATTERN'] 28LABEL_FILE_EXT = params_dict['LABEL_FILE_EXT'] 29 30 31def import_filter_concat_dfs(path, colsToFilter:list =None, filterType:str = None): 32 """ 33 Import and filter GeoDataFrames from shapefiles or directories of shapefiles. If multiple shapefiles will concatenate into one single filtered df. 34 Args: 35 path (str or list): File path to a shapefile, directory of shapeiles, or a list of file paths to shapefiles. 36 colsToFilter (list, optional): A list of columns to keep or remove from geodataframe. 37 filterType (str, optional): Used to specify if colsToFilter should been kept or removed from dataframe. 'keep' or 'remove' 38 Returns: 39 pandas.DataFrame: Filtered GeoDataFrame containing Regions of Interest (ROIs) and associated clipped DEMs. 40 Raises: 41 ValueError: If the input 'path' is of an unsupported type or if the file type or directory structure is not valid. 42 """ 43 if colsToFilter != None and filterType == None: 44 raise ValueError ('Specify keep or remove for filterType ') 45 46 if isinstance(path, str): 47 if os.path.isfile(path) and LABEL_FILE_PATTERN in path and path.lower().endswith(LABEL_FILE_EXT): 48 df = gpd.read_file(filePath, truncation=False) 49 if colsToFilter != None: 50 if filterType == 'remove': 51 filteredDf = df.drop(columns=colsToFilter) 52 elif filterType == 'keep': 53 filteredDf = df[colsToFilter] 54 else: 55 raise print('Invalid filtertype skipping filter') 56 else: 57 filteredDf = df 58 59 elif os.path.isdir(path): 60 dfs=[] 61 labelDfs = [] 62 for root, dirs, files in os.walk(path): 63 for file in files: 64 if LABEL_FILE_PATTERN in file and file.lower().endswith(LABEL_FILE_EXT): 65 filePath=os.path.join(root, file) 66 labelDfs.append(filePath) 67 df = gpd.read_file(filePath, truncation=False) 68 if colsToFilter != None: 69 if filterType == 'remove': 70 filteredDf = df.drop(columns=colsToFilter) 71 elif filterType == 'keep': 72 filteredDf = df[colsToFilter] 73 else: 74 raise print('Invalid filtertype skipping filter') 75 else: 76 filteredDf = df 77 dfs.append(filteredDf) 78 print('Joining Dataframes: ' + str(labelDfs)) 79 filteredDf = gpd.GeoDataFrame(pd.concat(dfs, ignore_index=True), crs=dfs[0].crs) 80 else: 81 raise ValueError(f"Unsupported file type or directory structure for path: {path}") 82 elif isinstance(path, list): 83 dfs = [] 84 for p in path: 85 if os.path.isfile(p) and p.lower().endswith('.shp'): 86 df = gpd.read_file(filePath, truncation=False) 87 if colsToFilter != None: 88 if filterType == 'remove': 89 filteredDf = df.drop(columns=colsToFilter) 90 elif filterType == 'keep': 91 filteredDf = df[colsToFilter] 92 else: 93 raise print('Invalid filtertype skipping filter') 94 else: 95 filteredDf = df 96 dfs.append(filteredDf) 97 else: 98 print("Unsupported input type for {p}. Extension must be {LABEL_FILE_EXT}.") 99 100 filteredDf = gpd.GeoDataFrame(pd.concat(dfs, ignore_index=True), crs=dfs[0].crs) 101 else: 102 raise ValueError("Unsupported input type for {path}. Must be a string or a list of strings.") 103 104 return filteredDf 105 106 107def load_json_params_llb(filePath:str, print_info:bool=True): 108 """Loads parameters from a specified JSON file for configuring the lidar label builder. 109 110 Args: 111 filePath (str): Path to the JSON parameter file. 112 print_info (bool, optional): If True, prints the loaded parameters and their types. Defaults to True. 113 114 Returns: 115 tuple: A tuple containing the following elements: 116 labels (list or None): List of label names or None if not provided. 117 outDirectory (str or None): Path to the output directory or None if not provided. 118 pathToPolygon (str or None): Path to the polygon file or None if not provided. 119 roiWidth (int or None): Width of the region of interest (ROI) or None if not provided. 120 numRois (int or None): Number of ROIs to generate or None if not provided. 121 aoiLabel (str or None): Area of interest (AOI) label or None if not provided. 122 polygonSource (str or None): Source of the polygon data or None if not provided. 123 roiMethod (str or None): Method for ROI generation or None if not provided. 124 rasterMethod (str or None): Method for raster processing or None if not provided. 125 rasterPaths (list or None): List of raster file paths or None if not provided. 126 plotkwargs (dict or None): Dictionary of keyword arguments for plotting or None if not provided. 127 """ 128 129 params = filePath 130 with open(params, 'r') as f: 131 params_dict = json.load(f) 132 133 134 labels = params_dict.get('labels', None) 135 outDirectory = params_dict.get('outDirectory', None) 136 pathToPolygon = params_dict.get('pathToPolygon', None) 137 roiWidth = params_dict.get('roiWidth', None) 138 numRois = params_dict.get('numRois', None) 139 aoiLabel = params_dict.get('aoiLabel', None) 140 polygonSource = params_dict.get('polygonSource', None) 141 roiMethod = params_dict.get('roiMethod', None) 142 rasterMethod = params_dict.get('rasterMethod', None) 143 144 # Dynamically handle raster paths 145 # rasterPaths = [params_dict.get(f'rasterPath{i}', None) for i in range(10) if f'rasterPath{i}' in params_dict] 146 rasterPaths = params_dict.get('rasterPaths',None) 147 148 plotkwargs = params_dict.get('plotkwargs', None) 149 150 151 if print_info: 152 # Print the parameters and their types 153 print("Labels ({}): {}".format(type(labels), labels)) 154 print("Out Directory ({}): {}".format(type(outDirectory), outDirectory)) 155 print("Path to Polygon ({}): {}".format(type(pathToPolygon), pathToPolygon)) 156 print("ROI Width ({}): {}".format(type(roiWidth), roiWidth)) 157 print("Number of ROIs ({}): {}".format(type(numRois), numRois)) 158 print("AOI Label ({}): {}".format(type(aoiLabel), aoiLabel)) 159 print("Polygon Source ({}): {}".format(type(polygonSource), polygonSource)) 160 print("ROI Method ({}): {}".format(type(roiMethod), roiMethod)) 161 print("Raster Method ({}): {}".format(type(rasterMethod), rasterMethod)) 162 print("Raster Paths ({}): {}".format(type(rasterPaths), rasterPaths)) 163 print("Plot kwargs ({}): {}".format(type(plotkwargs), plotkwargs)) 164 165 166 return labels, outDirectory, pathToPolygon, roiWidth, numRois, aoiLabel, polygonSource, \ 167 roiMethod, rasterMethod, rasterPaths, plotkwargs 168 169 170def visualize_kwargs(rasterPaths:list, plotkwargs:dict): 171 """Plots a visualization of the keyword arguments (kwargs) for the rasters. Can be useful to make sure keyword arguments are achieving the desired result. 172 173 Args: 174 rasterPaths (list): A list of raster paths corresponding to the kwargs 175 plotkwargs (dict): A dictionary of keyword arguments to plot the rasters. 176 177 Returns: 178 None 179 """ 180 181 derivs = [llb.get_raster_as_grid(path)[0] for path in rasterPaths] 182 fig,axs = plt.subplots() 183 plt.subplots_adjust(right = 0.7) 184 185 # Plot the raster images 186 for deriv, kwarg in zip(derivs, plotkwargs): 187 axs.imshow(deriv, **kwarg) 188 189 # Show the plot 190 plt.show() 191 return None 192 193def rm_filepath_cols(gdf:gpd.GeoDataFrame): 194 """Removes all columns with raster and image filepaths. 195 196 Args: 197 gdf (gpd.GeoDataFrame): Filepath to a roi geodataframe with filepaths to remove. 198 199 Returns: 200 gdf (gpd.GeoDataFrame): The modified geodataframe after filepath columns were removed. 201 """ 202 rasterCols = [col for col in gdf.columns if col.startswith('rstr_clp')] 203 imageCols = [col for col in gdf.columns if col == 'imgPaths'] 204 205 for rasterCol in rasterCols: 206 gdf.drop(rasterCol, axis=1, inplace=True) 207 208 for imgCol in imageCols: 209 gdf.drop(imgCol, axis= 1, inplace=True) 210 211 return gdf
32def import_filter_concat_dfs(path, colsToFilter:list =None, filterType:str = None): 33 """ 34 Import and filter GeoDataFrames from shapefiles or directories of shapefiles. If multiple shapefiles will concatenate into one single filtered df. 35 Args: 36 path (str or list): File path to a shapefile, directory of shapeiles, or a list of file paths to shapefiles. 37 colsToFilter (list, optional): A list of columns to keep or remove from geodataframe. 38 filterType (str, optional): Used to specify if colsToFilter should been kept or removed from dataframe. 'keep' or 'remove' 39 Returns: 40 pandas.DataFrame: Filtered GeoDataFrame containing Regions of Interest (ROIs) and associated clipped DEMs. 41 Raises: 42 ValueError: If the input 'path' is of an unsupported type or if the file type or directory structure is not valid. 43 """ 44 if colsToFilter != None and filterType == None: 45 raise ValueError ('Specify keep or remove for filterType ') 46 47 if isinstance(path, str): 48 if os.path.isfile(path) and LABEL_FILE_PATTERN in path and path.lower().endswith(LABEL_FILE_EXT): 49 df = gpd.read_file(filePath, truncation=False) 50 if colsToFilter != None: 51 if filterType == 'remove': 52 filteredDf = df.drop(columns=colsToFilter) 53 elif filterType == 'keep': 54 filteredDf = df[colsToFilter] 55 else: 56 raise print('Invalid filtertype skipping filter') 57 else: 58 filteredDf = df 59 60 elif os.path.isdir(path): 61 dfs=[] 62 labelDfs = [] 63 for root, dirs, files in os.walk(path): 64 for file in files: 65 if LABEL_FILE_PATTERN in file and file.lower().endswith(LABEL_FILE_EXT): 66 filePath=os.path.join(root, file) 67 labelDfs.append(filePath) 68 df = gpd.read_file(filePath, truncation=False) 69 if colsToFilter != None: 70 if filterType == 'remove': 71 filteredDf = df.drop(columns=colsToFilter) 72 elif filterType == 'keep': 73 filteredDf = df[colsToFilter] 74 else: 75 raise print('Invalid filtertype skipping filter') 76 else: 77 filteredDf = df 78 dfs.append(filteredDf) 79 print('Joining Dataframes: ' + str(labelDfs)) 80 filteredDf = gpd.GeoDataFrame(pd.concat(dfs, ignore_index=True), crs=dfs[0].crs) 81 else: 82 raise ValueError(f"Unsupported file type or directory structure for path: {path}") 83 elif isinstance(path, list): 84 dfs = [] 85 for p in path: 86 if os.path.isfile(p) and p.lower().endswith('.shp'): 87 df = gpd.read_file(filePath, truncation=False) 88 if colsToFilter != None: 89 if filterType == 'remove': 90 filteredDf = df.drop(columns=colsToFilter) 91 elif filterType == 'keep': 92 filteredDf = df[colsToFilter] 93 else: 94 raise print('Invalid filtertype skipping filter') 95 else: 96 filteredDf = df 97 dfs.append(filteredDf) 98 else: 99 print("Unsupported input type for {p}. Extension must be {LABEL_FILE_EXT}.") 100 101 filteredDf = gpd.GeoDataFrame(pd.concat(dfs, ignore_index=True), crs=dfs[0].crs) 102 else: 103 raise ValueError("Unsupported input type for {path}. Must be a string or a list of strings.") 104 105 return filteredDf
Import and filter GeoDataFrames from shapefiles or directories of shapefiles. If multiple shapefiles will concatenate into one single filtered df.
Arguments:
- path (str or list): File path to a shapefile, directory of shapeiles, or a list of file paths to shapefiles.
- colsToFilter (list, optional): A list of columns to keep or remove from geodataframe.
- filterType (str, optional): Used to specify if colsToFilter should been kept or removed from dataframe. 'keep' or 'remove'
Returns:
pandas.DataFrame: Filtered GeoDataFrame containing Regions of Interest (ROIs) and associated clipped DEMs.
Raises:
- ValueError: If the input 'path' is of an unsupported type or if the file type or directory structure is not valid.
108def load_json_params_llb(filePath:str, print_info:bool=True): 109 """Loads parameters from a specified JSON file for configuring the lidar label builder. 110 111 Args: 112 filePath (str): Path to the JSON parameter file. 113 print_info (bool, optional): If True, prints the loaded parameters and their types. Defaults to True. 114 115 Returns: 116 tuple: A tuple containing the following elements: 117 labels (list or None): List of label names or None if not provided. 118 outDirectory (str or None): Path to the output directory or None if not provided. 119 pathToPolygon (str or None): Path to the polygon file or None if not provided. 120 roiWidth (int or None): Width of the region of interest (ROI) or None if not provided. 121 numRois (int or None): Number of ROIs to generate or None if not provided. 122 aoiLabel (str or None): Area of interest (AOI) label or None if not provided. 123 polygonSource (str or None): Source of the polygon data or None if not provided. 124 roiMethod (str or None): Method for ROI generation or None if not provided. 125 rasterMethod (str or None): Method for raster processing or None if not provided. 126 rasterPaths (list or None): List of raster file paths or None if not provided. 127 plotkwargs (dict or None): Dictionary of keyword arguments for plotting or None if not provided. 128 """ 129 130 params = filePath 131 with open(params, 'r') as f: 132 params_dict = json.load(f) 133 134 135 labels = params_dict.get('labels', None) 136 outDirectory = params_dict.get('outDirectory', None) 137 pathToPolygon = params_dict.get('pathToPolygon', None) 138 roiWidth = params_dict.get('roiWidth', None) 139 numRois = params_dict.get('numRois', None) 140 aoiLabel = params_dict.get('aoiLabel', None) 141 polygonSource = params_dict.get('polygonSource', None) 142 roiMethod = params_dict.get('roiMethod', None) 143 rasterMethod = params_dict.get('rasterMethod', None) 144 145 # Dynamically handle raster paths 146 # rasterPaths = [params_dict.get(f'rasterPath{i}', None) for i in range(10) if f'rasterPath{i}' in params_dict] 147 rasterPaths = params_dict.get('rasterPaths',None) 148 149 plotkwargs = params_dict.get('plotkwargs', None) 150 151 152 if print_info: 153 # Print the parameters and their types 154 print("Labels ({}): {}".format(type(labels), labels)) 155 print("Out Directory ({}): {}".format(type(outDirectory), outDirectory)) 156 print("Path to Polygon ({}): {}".format(type(pathToPolygon), pathToPolygon)) 157 print("ROI Width ({}): {}".format(type(roiWidth), roiWidth)) 158 print("Number of ROIs ({}): {}".format(type(numRois), numRois)) 159 print("AOI Label ({}): {}".format(type(aoiLabel), aoiLabel)) 160 print("Polygon Source ({}): {}".format(type(polygonSource), polygonSource)) 161 print("ROI Method ({}): {}".format(type(roiMethod), roiMethod)) 162 print("Raster Method ({}): {}".format(type(rasterMethod), rasterMethod)) 163 print("Raster Paths ({}): {}".format(type(rasterPaths), rasterPaths)) 164 print("Plot kwargs ({}): {}".format(type(plotkwargs), plotkwargs)) 165 166 167 return labels, outDirectory, pathToPolygon, roiWidth, numRois, aoiLabel, polygonSource, \ 168 roiMethod, rasterMethod, rasterPaths, plotkwargs
Loads parameters from a specified JSON file for configuring the lidar label builder.
Arguments:
- filePath (str): Path to the JSON parameter file.
- print_info (bool, optional): If True, prints the loaded parameters and their types. Defaults to True.
Returns:
tuple: A tuple containing the following elements: labels (list or None): List of label names or None if not provided. outDirectory (str or None): Path to the output directory or None if not provided. pathToPolygon (str or None): Path to the polygon file or None if not provided. roiWidth (int or None): Width of the region of interest (ROI) or None if not provided. numRois (int or None): Number of ROIs to generate or None if not provided. aoiLabel (str or None): Area of interest (AOI) label or None if not provided. polygonSource (str or None): Source of the polygon data or None if not provided. roiMethod (str or None): Method for ROI generation or None if not provided. rasterMethod (str or None): Method for raster processing or None if not provided. rasterPaths (list or None): List of raster file paths or None if not provided. plotkwargs (dict or None): Dictionary of keyword arguments for plotting or None if not provided.
171def visualize_kwargs(rasterPaths:list, plotkwargs:dict): 172 """Plots a visualization of the keyword arguments (kwargs) for the rasters. Can be useful to make sure keyword arguments are achieving the desired result. 173 174 Args: 175 rasterPaths (list): A list of raster paths corresponding to the kwargs 176 plotkwargs (dict): A dictionary of keyword arguments to plot the rasters. 177 178 Returns: 179 None 180 """ 181 182 derivs = [llb.get_raster_as_grid(path)[0] for path in rasterPaths] 183 fig,axs = plt.subplots() 184 plt.subplots_adjust(right = 0.7) 185 186 # Plot the raster images 187 for deriv, kwarg in zip(derivs, plotkwargs): 188 axs.imshow(deriv, **kwarg) 189 190 # Show the plot 191 plt.show() 192 return None
Plots a visualization of the keyword arguments (kwargs) for the rasters. Can be useful to make sure keyword arguments are achieving the desired result.
Arguments:
- rasterPaths (list): A list of raster paths corresponding to the kwargs
- plotkwargs (dict): A dictionary of keyword arguments to plot the rasters.
Returns:
None
194def rm_filepath_cols(gdf:gpd.GeoDataFrame): 195 """Removes all columns with raster and image filepaths. 196 197 Args: 198 gdf (gpd.GeoDataFrame): Filepath to a roi geodataframe with filepaths to remove. 199 200 Returns: 201 gdf (gpd.GeoDataFrame): The modified geodataframe after filepath columns were removed. 202 """ 203 rasterCols = [col for col in gdf.columns if col.startswith('rstr_clp')] 204 imageCols = [col for col in gdf.columns if col == 'imgPaths'] 205 206 for rasterCol in rasterCols: 207 gdf.drop(rasterCol, axis=1, inplace=True) 208 209 for imgCol in imageCols: 210 gdf.drop(imgCol, axis= 1, inplace=True) 211 212 return gdf
Removes all columns with raster and image filepaths.
Arguments:
- gdf (gpd.GeoDataFrame): Filepath to a roi geodataframe with filepaths to remove.
Returns:
gdf (gpd.GeoDataFrame): The modified geodataframe after filepath columns were removed.