Skip to content

Commit

Permalink
Merge pull request #1623 from pierotofy/class
Browse files Browse the repository at this point in the history
Automated point classification and other improvements
  • Loading branch information
pierotofy authored Mar 21, 2023
2 parents 7bd81a9 + b404366 commit 6a7ab13
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 65 deletions.
1 change: 1 addition & 0 deletions SuperBuild/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ set(custom_libs OpenSfM
FPCFilter
PyPopsift
Obj2Tiles
OpenPointClass
)

externalproject_add(mve
Expand Down
33 changes: 33 additions & 0 deletions SuperBuild/cmake/External-OpenPointClass.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
set(_proj_name openpointclass)
set(_SB_BINARY_DIR "${SB_BINARY_DIR}/${_proj_name}")

ExternalProject_Add(${_proj_name}
DEPENDS pdal eigen34
PREFIX ${_SB_BINARY_DIR}
TMP_DIR ${_SB_BINARY_DIR}/tmp
STAMP_DIR ${_SB_BINARY_DIR}/stamp
#--Download step--------------
DOWNLOAD_DIR ${SB_DOWNLOAD_DIR}
GIT_REPOSITORY https://github.com/uav4geo/OpenPointClass
GIT_TAG v1.1.3
#--Update/Patch step----------
UPDATE_COMMAND ""
#--Configure step-------------
SOURCE_DIR ${SB_SOURCE_DIR}/${_proj_name}
CMAKE_ARGS
-DPDAL_DIR=${SB_INSTALL_DIR}/lib/cmake/PDAL
-DWITH_GBT=ON
-DBUILD_PCTRAIN=OFF
-DEIGEN3_INCLUDE_DIR=${SB_SOURCE_DIR}/eigen34/
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-DCMAKE_INSTALL_PREFIX:PATH=${SB_INSTALL_DIR}
${WIN32_CMAKE_ARGS}
#--Build step-----------------
BINARY_DIR ${_SB_BINARY_DIR}
#--Install step---------------
INSTALL_DIR ${SB_INSTALL_DIR}
#--Output logging-------------
LOG_DOWNLOAD OFF
LOG_CONFIGURE OFF
LOG_BUILD OFF
)
55 changes: 0 additions & 55 deletions SuperBuild/cmake/External-PCL.cmake

This file was deleted.

2 changes: 1 addition & 1 deletion opendm/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ def config(argv=None, parser=None):
action=StoreTrue,
nargs=0,
default=False,
help='Classify the point cloud outputs using a Simple Morphological Filter. '
help='Classify the point cloud outputs. '
'You can control the behavior of this option by tweaking the --dem-* parameters. '
'Default: '
'%(default)s')
Expand Down
10 changes: 3 additions & 7 deletions opendm/gpu.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,15 @@ def has_popsift_and_can_handle_texsize(width, height):
compute_major, compute_minor = get_cuda_compute_version(0)
if compute_major < 3 or (compute_major == 3 and compute_minor < 5):
# Not supported
log.ODM_WARNING("CUDA compute platform is not supported (detected: %s.%s but we need at least 3.5)" % (compute_major, compute_minor))
log.ODM_INFO("CUDA compute platform is not supported (detected: %s.%s but we need at least 3.5)" % (compute_major, compute_minor))
return False
except Exception as e:
log.ODM_WARNING("Cannot use GPU for feature extraction: %s" % str(e))
log.ODM_INFO("Using CPU for feature extraction: %s" % str(e))
return False

try:
from opensfm import pypopsift
fits = pypopsift.fits_texture(int(width * 1.02), int(height * 1.02))
if not fits:
log.ODM_WARNING("Image size (%sx%spx) would not fit in GPU memory, try lowering --feature-quality. Falling back to CPU" % (width, height))
return fits
return pypopsift.fits_texture(int(width * 1.02), int(height * 1.02))
except (ModuleNotFoundError, ImportError):
return False
except Exception as e:
Expand Down Expand Up @@ -91,5 +88,4 @@ def has_gpu(args):
log.ODM_INFO("nvidia-smi detected")
return True
else:
log.ODM_INFO("nvidia-smi not found in PATH, using CPU")
return False
31 changes: 31 additions & 0 deletions opendm/opc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import os
from opendm.ai import get_model
from opendm import log
from opendm.system import run
from opendm import io

def classify(point_cloud):
tmp_output = io.related_file_path(point_cloud, postfix=".classified")
if os.path.isfile(tmp_output):
os.remove(tmp_output)

try:
model = get_model("openpointclass",
"https://github.com/uav4geo/OpenPointClass/releases/download/v1.1.3/vehicles-vegetation-buildings.zip",
"v1.0.0",
name="model.bin")

if model is not None:
run('pcclassify "%s" "%s" "%s" -u -s 2,64' % (point_cloud, tmp_output, model))

if os.path.isfile(tmp_output):
os.remove(point_cloud)
os.rename(tmp_output, point_cloud)
else:
log.ODM_WARNING("Cannot classify using OpenPointClass (no output generated)")
else:
log.ODM_WARNING("Cannot download/access model from %s" % (model_url))

except Exception as e:
log.ODM_WARNING("Cannot classify using OpenPointClass: %s" % str(e))

5 changes: 5 additions & 0 deletions stages/dataset.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,3 +330,8 @@ def parallel_bg_filter(item):
log.ODM_WARNING("No omega/phi/kappa angles found in input photos (%s), switching sfm-algorithm to incremental" % p.filename)
args.sfm_algorithm = 'incremental'
break

# Rolling shutter cannot be done in non-georeferenced datasets
if args.rolling_shutter and not reconstruction.is_georeferenced():
log.ODM_WARNING("Reconstruction is not georeferenced, disabling rolling shutter correction")
args.rolling_shutter = False
7 changes: 5 additions & 2 deletions stages/odm_dem.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from opendm import pseudogeo
from opendm.tiles.tiler import generate_dem_tiles
from opendm.cogeo import convert_to_cogeo

from opendm.opc import classify

class ODMDEMStage(types.ODM_Stage):
def process(self, args, outputs):
Expand Down Expand Up @@ -49,14 +49,17 @@ def process(self, args, outputs):
pc_classify_marker = os.path.join(odm_dem_root, 'pc_classify_done.txt')

if not io.file_exists(pc_classify_marker) or self.rerun():
log.ODM_INFO("Classifying {} using Simple Morphological Filter".format(dem_input))
log.ODM_INFO("Classifying {} using Simple Morphological Filter (1/2)".format(dem_input))
commands.classify(dem_input,
args.smrf_scalar,
args.smrf_slope,
args.smrf_threshold,
args.smrf_window
)

log.ODM_INFO("Classifying {} using OpenPointClass (2/2)".format(dem_input))
classify(dem_input)

with open(pc_classify_marker, 'w') as f:
f.write('Classify: smrf\n')
f.write('Scalar: {}\n'.format(args.smrf_scalar))
Expand Down

0 comments on commit 6a7ab13

Please sign in to comment.