diff --git a/libs/Task.js b/libs/Task.js index 662826d..3be22d3 100644 --- a/libs/Task.js +++ b/libs/Task.js @@ -286,57 +286,22 @@ module.exports = class Task{ }; }; - const handleProcessExit = (done) => { - return (err, code, signal) => { - if (err) done(err); - else{ - // Don't evaluate if we caused the process to exit via SIGINT? - if (code === 0) done(); - else done(new Error(`Process exited with code ${code}`)); - } - }; - }; - - const handleOutput = output => { - this.output.push(output); - }; - - const generateTiles = (inputFile, outputDir) => { + const runPostProcessingScript = () => { return (done) => { - const inputFilePath = path.join(this.getProjectFolderPath(), inputFile); - - // Not all datasets generate an orthophoto, so we skip - // tiling if the orthophoto is missing - if (fs.existsSync(inputFilePath)){ - this.runningProcesses.push(processRunner.runTiler({ - zoomLevels: "12-21", - inputFile: inputFilePath, - outputDir: path.join(this.getProjectFolderPath(), outputDir) - }, handleProcessExit(done), handleOutput)); - }else{ - handleOutput(`${inputFilePath} file not found, skipping tiles generation\n`); - done(); - } - }; - }; - - const generatePotreeCloud = (inputFile, outputDir) => { - return (done) => { - this.runningProcesses.push(processRunner.runPotreeConverter({ - inputFile: path.join(this.getProjectFolderPath(), inputFile), - outputDir: path.join(this.getProjectFolderPath(), outputDir) - }, handleProcessExit(done), handleOutput)); - }; - }; - - const pdalTranslate = (inputPath, outputPath, filters) => { - return (done) => { - this.runningProcesses.push(processRunner.runPdalTranslate({ - inputFile: inputPath, - outputFile: outputPath, - filters: filters - }, handleProcessExit(done), handleOutput)); - }; + this.runningProcesses.push( + processRunner.runPostProcessingScript({ + projectFolderPath: this.getProjectFolderPath() + }, (err, code, signal) => { + if (err) done(err); + else{ + if (code === 0) done(); + else done(new Error(`Process exited with code ${code}`)); + } + }, output => { + this.output.push(output); + }) + ); + } }; // All paths are relative to the project directory (./data//) @@ -351,35 +316,10 @@ module.exports = class Task{ }); } - let orthophotoPath = path.join('odm_orthophoto', 'odm_orthophoto.tif'), - lasPointCloudPath = path.join('odm_georeferencing', 'odm_georeferenced_model.las'), - plyPointCloudPath = path.join('odm_georeferencing', 'odm_georeferenced_model.ply'), - projectFolderPath = this.getProjectFolderPath(); - - let commands = [ - generateTiles(orthophotoPath, 'orthophoto_tiles'), - generatePotreeCloud(plyPointCloudPath, 'potree_pointcloud'), + async.series([ + runPostProcessingScript(), createZipArchive('all.zip', allFolders) - ]; - - // If point cloud file does not exist, it's likely because location (GPS/GPC) information - // was missing and the file was not generated. - let fullPlyPointCloudPath = path.join(projectFolderPath, plyPointCloudPath); - if (!fs.existsSync(fullPlyPointCloudPath)){ - let unreferencedPointCloudPath = path.join(projectFolderPath, "opensfm", "depthmaps", "merged.ply"); - if (fs.existsSync(unreferencedPointCloudPath)){ - logger.info(`${plyPointCloudPath} is missing, will attempt to generate it from ${unreferencedPointCloudPath}`); - commands.unshift(pdalTranslate(unreferencedPointCloudPath, fullPlyPointCloudPath, [ - { - // opensfm's ply files map colors with the diffuse_ prefix - dimensions: "diffuse_red = red, diffuse_green = green, diffuse_blue = blue", - type: "filters.ferry" - } - ])); - } - } - - async.series(commands, (err) => { + ], (err) => { if (!err){ this.setStatus(statusCodes.COMPLETED); finished(); diff --git a/libs/processRunner.js b/libs/processRunner.js index d7ccf58..3f873b0 100644 --- a/libs/processRunner.js +++ b/libs/processRunner.js @@ -69,42 +69,10 @@ function makeRunner(command, args, requiredOptions = [], outputTestFile = null){ }; } - module.exports = { - runTiler: makeRunner("gdal2tiles.py", - function(options){ - return ["-z", options.zoomLevels, - "-n", - "-w", "none", - options.inputFile, - options.outputDir - ]; - }, - ["zoomLevels", "inputFile", "outputDir"], - path.join("..", "tests", "gdal2tiles_output.txt")), - - runPotreeConverter: makeRunner("PotreeConverter", - function(options){ - return [options.inputFile, - "-o", options.outputDir]; - }, - ["inputFile", "outputDir"], - path.join("..", "tests", "potree_output.txt")), - - runPdalTranslate: makeRunner("/code/SuperBuild/build/pdal/bin/pdal", - function(options){ - let opts = ["translate", - "-i", options.inputFile, - "-o", options.outputFile]; - - if (options.filters){ - opts = opts.concat([ - "--json", - JSON.stringify(options.filters) - ]); - } - - return opts; - }, - ["inputFile", "outputFile"]) + runPostProcessingScript: makeRunner(os.path.join(__dirname, "..", "scripts", "postprocess.sh"), + function(options){ + return [options.projectFolderPath]; + }, + ["projectFolderPath"]) }; diff --git a/scripts/postprocess.sh b/scripts/postprocess.sh new file mode 100755 index 0000000..563ec25 --- /dev/null +++ b/scripts/postprocess.sh @@ -0,0 +1,57 @@ +#!/bin/bash + +# This file executes the post-processing steps for a task after a dataset +# has been processed by OpenDroneMap. It generates derivative computations. +# +# As a general rule, post-processing commands should never fail the task +#(for example, if a point cloud could not be generated, the PotreeConverter +# step will fail, but the script should still continue processing the rest and +# return a 0 code). The idea is to post-process as much as possible, knowing +# that some parts might fail and that partial results should be returned in such cases. + +if [ -z "$1" ]; then + echo "Usage: $0 " + exit 0 +fi + +# Switch to project path folder (data//) +cd "$(dirname "$0")/../$1" +echo "Postprocessing: $(pwd)" + +# Generate Tiles +if hash gdal2tiles.py 2>/dev/null; then + orthophoto_path="odm_orthophoto/odm_orthophoto.tif" + + if [ -e "$orthophoto_path" ]; then + gdal2tiles.py -z 12-21 -n -w none $orthophoto_path orthophoto_tiles + else + echo "No orthophoto found at $orthophoto_path: will skip tiling" + fi +else + echo "gdal2tiles.py is not installed, will skip tiling" +fi + +# Generate Potree point cloud (if PotreeConverter is available) +if hash PotreeConverter 2>/dev/null; then + potree_input_path="" + for path in "odm_georeferencing/odm_georeferenced_model.ply" \ + "opensfm/depthmaps/merged.ply" \ + "pmvs/recon0/models/option-0000.ply"; do + if [ -e $path ]; then + echo "Found suitable point cloud for PotreeConverter: $path" + potree_input_path=$path + break + fi + done + + if [ ! -z "$potree_input_path" ]; then + PotreeConverter $potree_input_path -o potree_pointcloud + else + echo "Potree point cloud will not be generated (no suitable input files found)" + fi +else + echo "PotreeConverter is not installed, will skip generation of Potree point cloud" +fi + +echo "Postprocessing: done (•̀ᴗ•́)و!" +exit 0 \ No newline at end of file diff --git a/scripts/test.sh b/scripts/test.sh new file mode 100644 index 0000000..9d50e69 --- /dev/null +++ b/scripts/test.sh @@ -0,0 +1,4 @@ +h="" +if [ ! -z "$h" ]; then + echo "OK" +fi \ No newline at end of file