Skip to content
Snippets Groups Projects
Commit 8c2077f7 authored by Maciej Wielgosz's avatar Maciej Wielgosz
Browse files

sparsification implemented

parent 64725988
No related branches found
No related tags found
No related merge requests found
...@@ -7,15 +7,24 @@ from scipy.spatial import ConvexHull ...@@ -7,15 +7,24 @@ from scipy.spatial import ConvexHull
import logging import logging
class SparsifyPointCloudToDensity: class SparsifyLasBasedSqM:
def __init__(self, input_file, output_folder=None, target_density=10, verbose=False): def __init__(self, input_file, output_folder=None, target_density=10, verbose=False):
self.input_file = input_file self.input_file = input_file
if output_folder is None: if output_folder is None:
self.output_folder = os.path.dirname(input_file) self.output_folder = os.path.dirname(input_file)
self.target_density = target_density self.target_density = target_density
self.desity = None
self.new_point_cloud_density = None
self.verbose = verbose self.verbose = verbose
# Initialize logging
self.logger = logging.getLogger(__name__)
if self.verbose: if self.verbose:
logging.info(f"Initialized with input file: {self.input_file}, target density: {self.target_density}") self.logger.setLevel(logging.INFO)
else:
self.logger.setLevel(logging.WARNING)
self.logger.info(f"Initialized with input file: {self.input_file}, target density: {self.target_density}")
def calculate_density_convex_hull(self, las): def calculate_density_convex_hull(self, las):
points_3D = np.vstack((las.x, las.y, las.z)).transpose() points_3D = np.vstack((las.x, las.y, las.z)).transpose()
...@@ -27,20 +36,18 @@ class SparsifyPointCloudToDensity: ...@@ -27,20 +36,18 @@ class SparsifyPointCloudToDensity:
return density return density
def sparsify(self, point_cloud): def sparsify(self, point_cloud):
density = self.calculate_density_convex_hull(point_cloud)
if self.verbose:
logging.info(f"Point cloud density: {density} points per square meter.") self.density = self.calculate_density_convex_hull(point_cloud)
self.logger.info(f"Point cloud density: {self.density} points per square meter.")
x = point_cloud.x x = point_cloud.x
keep_count = int(len(x) * (self.target_density / density)) keep_count = int(len(x) * (self.target_density / self.density))
sampled_indices = random.sample(range(len(x)), keep_count) sampled_indices = random.sample(range(len(x)), keep_count)
filtered_point_cloud = point_cloud.points[sampled_indices] filtered_point_cloud = point_cloud.points[sampled_indices]
if self.verbose: self.new_point_cloud_density =self.calculate_density_convex_hull(filtered_point_cloud)
logging.info(f"Reduced point cloud size from {len(x)} to {len(filtered_point_cloud)} points.") self.logger.info(f"Reduced point cloud size from {len(x)} to {len(filtered_point_cloud)} points.")
logging.info(f"Reduced point cloud by {(1 - len(filtered_point_cloud) / len(x)) * 100}%.") self.logger.info(f"Reduced point cloud by {(1 - len(filtered_point_cloud) / len(x)) * 100}%.")
density = self.calculate_density_convex_hull(filtered_point_cloud) self.logger.info(f"New point cloud density: {self.new_point_cloud_density} points per square meter.")
density = round(density, 2)
logging.info(f"Filtered point cloud density: {density} points per square meter.")
return filtered_point_cloud return filtered_point_cloud
def process(self): def process(self):
...@@ -48,18 +55,18 @@ class SparsifyPointCloudToDensity: ...@@ -48,18 +55,18 @@ class SparsifyPointCloudToDensity:
os.makedirs(self.output_folder) os.makedirs(self.output_folder)
inFile = laspy.read(self.input_file) inFile = laspy.read(self.input_file)
filtered_points = self.sparsify(inFile) filtered_points = self.sparsify(inFile)
if self.verbose: self.logger.info("Creating output laspy object")
logging.info("Creating output laspy object")
outFile = laspy.create(point_format=inFile.point_format, file_version=inFile.header.version) outFile = laspy.create(point_format=inFile.point_format, file_version=inFile.header.version)
outFile.header = inFile.header outFile.header = inFile.header
outFile.points = filtered_points outFile.points = filtered_points
# save the point cloud to the output folder with the same name as the input file but suffixed with _sparse and desired density
output_file_path = os.path.join(self.output_folder, os.path.basename(self.input_file).replace(".las", f"_sparse_{self.target_density}.las")) output_file_path = os.path.join(self.output_folder, os.path.basename(self.input_file).replace(".las", f"_sparse_{self.target_density}.las"))
outFile.write(output_file_path) outFile.write(output_file_path)
if __name__ == "__main__": if __name__ == "__main__":
# Configure logging
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.INFO)
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument("-i", "--input_file", help="The .las file to sparsify.") parser.add_argument("-i", "--input_file", help="The .las file to sparsify.")
parser.add_argument("--output_folder", default=None, help="The folder where the sparse point cloud will be saved.") parser.add_argument("--output_folder", default=None, help="The folder where the sparse point cloud will be saved.")
...@@ -67,5 +74,5 @@ if __name__ == "__main__": ...@@ -67,5 +74,5 @@ if __name__ == "__main__":
parser.add_argument("-v", "--verbose", help="Enable verbose logging", action="store_true") parser.add_argument("-v", "--verbose", help="Enable verbose logging", action="store_true")
args = parser.parse_args() args = parser.parse_args()
sparsifier = SparsifyPointCloudToDensity(args.input_file, args.output_folder, args.target_density, args.verbose) sparsifier = SparsifyLasBasedSqM(args.input_file, args.output_folder, args.target_density, args.verbose)
sparsifier.process() sparsifier.process()
import argparse
import os
import logging
import laspy
from tqdm import tqdm
from nibio_preprocessing.sparsify_las_based_sq_m import SparsifyLasBasedSqM
class SparsifyLasBasedSqMInFolder(SparsifyLasBasedSqM):
def __init__(self, input_folder, output_folder=None, target_density=10, verbose=False):
super().__init__(input_file=None, output_folder=output_folder, target_density=target_density, verbose=verbose)
self.directory_with_point_clouds = input_folder
self.output_folder = output_folder
self.report = None
# Initialize logging for the subclass
self.logger = logging.getLogger(__name__)
if self.verbose:
self.logger.setLevel(logging.INFO)
else:
self.logger.setLevel(logging.WARNING)
def reduce_point_clouds(self):
# get paths to all point clouds in the directory and subdirectories
point_cloud_paths = []
# create output folder if it doesn't exist, if it does, delete all files in it
if not os.path.exists(self.output_folder):
os.makedirs(self.output_folder)
else:
files = os.listdir(self.output_folder)
for f in files:
os.remove(os.path.join(self.output_folder, f))
for root, dirs, files in os.walk(self.directory_with_point_clouds):
for file in files:
if file.endswith(".las"):
point_cloud_paths.append(os.path.join(root, file))
self.logger.info(f"Found {len(point_cloud_paths)} point clouds.")
# iterate over all point clouds and save outputs to the output folder
for point_cloud_path in tqdm(point_cloud_paths):
self.input_file = point_cloud_path
self.process()
# append information about the point cloud to a report as a dictionary
if self.report is None:
self.report = {
"input_file": [self.input_file],
"density": [self.density],
"target_density": [self.target_density],
"new_density": [self.new_point_cloud_density]
}
else:
self.report["input_file"].append(self.input_file)
self.report["density"].append(self.density),
self.report["target_density"].append(self.target_density),
self.report["new_density"].append(self.new_point_cloud_density)
if self.verbose:
# print the dictionary as a pandas dataframe
import pandas as pd
df = pd.DataFrame.from_dict(self.report, orient="index").transpose()
print(df)
if __name__ == "__main__":
# Configure logging
logging.basicConfig(level=logging.INFO)
parser = argparse.ArgumentParser()
parser.add_argument("-i", "--input_folder", help="The folder with .las files to sparsify.")
parser.add_argument("-o", "--output_folder", default=None, help="The folder where the sparse point clouds will be saved.")
parser.add_argument("-d", "--target_density", help="The target density in points per square meter.", default=10, type=int)
parser.add_argument("-v", "--verbose", action="store_true", help="Print information about the process")
args = parser.parse_args()
sparsifier = SparsifyLasBasedSqMInFolder(
args.input_folder,
args.output_folder,
args.target_density,
args.verbose
)
sparsifier.reduce_point_clouds()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment