kopia lustrzana https://github.com/OpenDroneMap/NodeODM
Refactored Task.js to move postprocessing code in a bash script for ease of maintenance, fix existing problem with failing tasks when assets are not in the right place
rodzic
2a9591347b
commit
1deff5ec6c
96
libs/Task.js
96
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/<uuid>/)
|
||||
|
@ -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();
|
||||
|
|
|
@ -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"])
|
||||
};
|
||||
|
|
|
@ -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 <projectPath>"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Switch to project path folder (data/<uuid>/)
|
||||
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
|
|
@ -0,0 +1,4 @@
|
|||
h=""
|
||||
if [ ! -z "$h" ]; then
|
||||
echo "OK"
|
||||
fi
|
Ładowanie…
Reference in New Issue