kopia lustrzana https://github.com/OpenDroneMap/ODM
Removed odm_texturing, cleaned up 2.5d generation algorithm, added params in ODM pipeline
rodzic
5036714870
commit
f1571ceb7e
|
@ -64,18 +64,31 @@ void Odm25dMeshing::parseArguments(int argc, char **argv) {
|
|||
} else if (argument == "-verbose") {
|
||||
log.setIsPrintingInCout(true);
|
||||
} else if (argument == "-maxVertexCount" && argIndex < argc) {
|
||||
// ++argIndex;
|
||||
// if (argIndex >= argc)
|
||||
// {
|
||||
// throw OdmMeshingException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
|
||||
// }
|
||||
// std::stringstream ss(argv[argIndex]);
|
||||
// ss >> maxVertexCount_;
|
||||
// if (ss.bad())
|
||||
// {
|
||||
// throw OdmMeshingException("Argument '" + argument + "' has a bad value (wrong type).");
|
||||
// }
|
||||
// log << "Vertex count was manually set to: " << maxVertexCount_ << "\n";
|
||||
++argIndex;
|
||||
if (argIndex >= argc) throw Odm25dMeshingException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
|
||||
std::stringstream ss(argv[argIndex]);
|
||||
ss >> maxVertexCount;
|
||||
if (ss.bad()) throw Odm25dMeshingException("Argument '" + argument + "' has a bad value (wrong type).");
|
||||
maxVertexCount = std::max<unsigned int>(maxVertexCount, 0);
|
||||
log << "Vertex count was manually set to: " << maxVertexCount << "\n";
|
||||
} else if (argument == "-outliersRemovalPercentage" && argIndex < argc) {
|
||||
++argIndex;
|
||||
if (argIndex >= argc) throw Odm25dMeshingException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
|
||||
std::stringstream ss(argv[argIndex]);
|
||||
ss >> outliersRemovalPercentage;
|
||||
if (ss.bad()) throw Odm25dMeshingException("Argument '" + argument + "' has a bad value (wrong type).");
|
||||
|
||||
outliersRemovalPercentage = std::min<double>(99.99, std::max<double>(outliersRemovalPercentage, 0));
|
||||
log << "Outliers removal was manually set to: " << outliersRemovalPercentage << "\n";
|
||||
} else if (argument == "-wlopIterations" && argIndex < argc) {
|
||||
++argIndex;
|
||||
if (argIndex >= argc) throw Odm25dMeshingException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
|
||||
std::stringstream ss(argv[argIndex]);
|
||||
ss >> wlopIterations;
|
||||
if (ss.bad()) throw Odm25dMeshingException("Argument '" + argument + "' has a bad value (wrong type).");
|
||||
|
||||
wlopIterations = std::min<unsigned int>(1000, std::max<unsigned int>(wlopIterations, 1));
|
||||
log << "WLOP iterations was manually set to: " << wlopIterations << "\n";
|
||||
} else if (argument == "-inputFile" && argIndex < argc) {
|
||||
++argIndex;
|
||||
if (argIndex >= argc) {
|
||||
|
@ -141,55 +154,41 @@ void Odm25dMeshing::loadPointCloud(){
|
|||
|
||||
void Odm25dMeshing::buildMesh(){
|
||||
size_t pointCountBeforeOutRemoval = points.size();
|
||||
|
||||
if (outliersRemovalPercentage > 0)
|
||||
log << "Removing outliers\n";
|
||||
|
||||
const unsigned int NEIGHBORS = 24;
|
||||
const double REMOVED_PERCENTAGE = 5;
|
||||
|
||||
points.erase(CGAL::remove_outliers(points.begin(), points.end(),
|
||||
CGAL::Nth_of_tuple_property_map<0, PointNormalColor>(), NEIGHBORS, REMOVED_PERCENTAGE),
|
||||
CGAL::First_of_pair_property_map<Pwn>(), NEIGHBORS, outliersRemovalPercentage),
|
||||
points.end());
|
||||
std::vector<PointNormalColor>(points).swap(points);
|
||||
std::vector<Pwn>(points).swap(points);
|
||||
|
||||
size_t pointCount = points.size();
|
||||
|
||||
log << "Removed " << (pointCountBeforeOutRemoval - pointCount) << " points\n";
|
||||
|
||||
size_t pointCountBeforeSimplify = pointCount;
|
||||
const double RETAIN_PERCENTAGE = std::min<double>(((100. * (double)maxVertexCount) / (double)pointCount), 10.); // percentage of points to retain.
|
||||
std::vector<Point3> simplifiedPoints;
|
||||
|
||||
const double CELL_SIZE = 0.01;
|
||||
points.erase(CGAL::grid_simplify_point_set(points.begin(), points.end(),
|
||||
CGAL::Nth_of_tuple_property_map<0, PointNormalColor>(),
|
||||
CELL_SIZE),
|
||||
points.end());
|
||||
std::vector<PointNormalColor>(points).swap(points);
|
||||
log << "Performing weighted locally optimal projection simplification and regularization (retain: " << RETAIN_PERCENTAGE << "%, iterate: " << wlopIterations << ")" << "\n";
|
||||
|
||||
pointCount = points.size();
|
||||
CGAL::wlop_simplify_and_regularize_point_set<Concurrency_tag>(
|
||||
points.begin(),
|
||||
points.end(),
|
||||
std::back_inserter(simplifiedPoints),
|
||||
CGAL::First_of_pair_property_map<Pwn>(),
|
||||
RETAIN_PERCENTAGE,
|
||||
-1.0, // auto radius = 8 times the average spacing of the point set.
|
||||
wlopIterations,
|
||||
false); // require_uniform_sampling
|
||||
|
||||
log << "Removed " << (pointCountBeforeSimplify - pointCount) << " points\n";
|
||||
pointCount = simplifiedPoints.size();
|
||||
|
||||
if (pointCount < 3){
|
||||
throw Odm25dMeshingException("Not enough points");
|
||||
}
|
||||
|
||||
log << "Smoothing point set\n";
|
||||
|
||||
const double SHARPNESS_ANGLE = 89; // control sharpness of the result. The bigger the smoother the result will be
|
||||
const int SMOOTH_PASSES = 3;
|
||||
|
||||
for (int i = 0; i < SMOOTH_PASSES; ++i)
|
||||
{
|
||||
log << "Pass " << (i + 1) << " of " << SMOOTH_PASSES << "\n";
|
||||
|
||||
CGAL::bilateral_smooth_point_set <Concurrency_tag>(
|
||||
points.begin(),
|
||||
points.end(),
|
||||
CGAL::Nth_of_tuple_property_map<0, PointNormalColor>(),
|
||||
CGAL::Nth_of_tuple_property_map<1, PointNormalColor>(),
|
||||
NEIGHBORS,
|
||||
SHARPNESS_ANGLE);
|
||||
}
|
||||
log << "Final vertex count is " << pointCount << "\n";
|
||||
|
||||
std::vector< std::pair<cgalPoint, size_t > > pts;
|
||||
try{
|
||||
|
@ -199,7 +198,7 @@ void Odm25dMeshing::buildMesh(){
|
|||
}
|
||||
|
||||
for (size_t i = 0; i < pointCount; ++i){
|
||||
pts.push_back(std::make_pair(cgalPoint(points[i].get<0>().x(), points[i].get<0>().y()), i));
|
||||
pts.push_back(std::make_pair(cgalPoint(simplifiedPoints[i].x(), simplifiedPoints[i].y()), i));
|
||||
}
|
||||
|
||||
log << "Computing delaunay triangulation\n";
|
||||
|
@ -216,75 +215,26 @@ void Odm25dMeshing::buildMesh(){
|
|||
|
||||
// Convert to tinyply format
|
||||
std::vector<float> vertices;
|
||||
std::vector<uint8_t> colors;
|
||||
std::vector<int> vertexIndicies;
|
||||
|
||||
try{
|
||||
vertices.reserve(pointCount);
|
||||
colors.reserve(pointCount);
|
||||
vertexIndicies.reserve(triIndexes);
|
||||
} catch (const std::bad_alloc&){
|
||||
throw Odm25dMeshingException("Not enough memory");
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < pointCount; ++i){
|
||||
vertices.push_back(points[i].get<0>().x());
|
||||
vertices.push_back(points[i].get<0>().y());
|
||||
vertices.push_back(points[i].get<0>().z());
|
||||
|
||||
colors.push_back(points[i].get<2>()[0]);
|
||||
colors.push_back(points[i].get<2>()[1]);
|
||||
colors.push_back(points[i].get<2>()[2]);
|
||||
for (size_t i = 0; i < pointCount; ++i){
|
||||
vertices.push_back(simplifiedPoints[i].x());
|
||||
vertices.push_back(simplifiedPoints[i].y());
|
||||
vertices.push_back(simplifiedPoints[i].z());
|
||||
}
|
||||
|
||||
for (DT::Face_iterator face = dt.faces_begin(); face != dt.faces_end(); ++face) {
|
||||
vertexIndicies.push_back(static_cast<int>(face->vertex(0)->info()));
|
||||
vertexIndicies.push_back(static_cast<int>(face->vertex(1)->info()));
|
||||
vertexIndicies.push_back(static_cast<int>(face->vertex(2)->info()));
|
||||
}
|
||||
|
||||
log << "Removing spikes\n";
|
||||
|
||||
const float THRESHOLD = 0.2;
|
||||
const int PASSES = 5;
|
||||
|
||||
std::vector<float> heights;
|
||||
float current_threshold = THRESHOLD;
|
||||
|
||||
for (int i = 1; i <= PASSES; i++){
|
||||
log << "Pass " << i << " of " << PASSES << "\n";
|
||||
|
||||
for (DT::Vertex_iterator vertex = dt.vertices_begin(); vertex != dt.vertices_end(); ++vertex){
|
||||
// Check if the height between this vertex and its
|
||||
// incident vertices is greater than THRESHOLD
|
||||
Vertex_circulator vc = dt.incident_vertices(vertex), done(vc);
|
||||
|
||||
if (vc != 0){
|
||||
float height = vertices[vertex->info() * 3 + 2];
|
||||
bool spike = false;
|
||||
|
||||
do{
|
||||
if (dt.is_infinite(vc)) continue;
|
||||
|
||||
float ivHeight = vertices[vc->info() * 3 + 2];
|
||||
if (fabs(height - ivHeight) > current_threshold) spike = true;
|
||||
|
||||
heights.push_back(ivHeight);
|
||||
}while(++vc != done);
|
||||
|
||||
if (spike){
|
||||
// Replace the height of the vertex by the median height
|
||||
// of its incident vertices
|
||||
std::sort(heights.begin(), heights.end());
|
||||
|
||||
vertices[vertex->info() * 3 + 2] = heights[heights.size() / 2];
|
||||
}
|
||||
|
||||
heights.clear();
|
||||
}
|
||||
}
|
||||
|
||||
current_threshold /= 2;
|
||||
vertexIndicies.push_back(face->vertex(0)->info());
|
||||
vertexIndicies.push_back(face->vertex(1)->info());
|
||||
vertexIndicies.push_back(face->vertex(2)->info());
|
||||
}
|
||||
|
||||
log << "Saving mesh to file.\n";
|
||||
|
@ -295,7 +245,6 @@ void Odm25dMeshing::buildMesh(){
|
|||
|
||||
tinyply::PlyFile plyFile;
|
||||
plyFile.add_properties_to_element("vertex", {"x", "y", "z"}, vertices);
|
||||
plyFile.add_properties_to_element("vertex", { "diffuse_red", "diffuse_green", "diffuse_blue"}, colors);
|
||||
plyFile.add_properties_to_element("face", { "vertex_index" }, vertexIndicies, 3, tinyply::PlyProperty::Type::INT8);
|
||||
|
||||
plyFile.write(outputStream, false);
|
||||
|
@ -308,31 +257,18 @@ void Odm25dMeshing::printHelp() {
|
|||
bool printInCoutPop = log.isPrintingInCout();
|
||||
log.setIsPrintingInCout(true);
|
||||
|
||||
log << "odm_25dmeshing\n\n";
|
||||
log << "Usage: odm_25dmeshing -inputFile [plyFile] [optional-parameters]\n";
|
||||
log << "Create a 2.5D mesh from an oriented point cloud (points with normals) using a constrained delaunay triangulation. "
|
||||
<< "The program requires a path to an input PLY point cloud file, all other input parameters are optional.\n\n";
|
||||
|
||||
log << "Purpose:" << "\n";
|
||||
log
|
||||
<< "Create a 2.5D mesh from an oriented point cloud (points with normals) using a constrained delaunay triangulation"
|
||||
<< "\n";
|
||||
log << " -inputFile <path> to PLY point cloud\n"
|
||||
<< " -outputFile <path> where the output PLY 2.5D mesh should be saved (default: " << outputFile << ")\n"
|
||||
<< " -logFile <path> log file path (default: " << logFilePath << ")\n"
|
||||
<< " -verbose whether to print verbose output (default: " << (printInCoutPop ? "true" : "false") << ")\n"
|
||||
<< " -outliersRemovalPercentage <0 - 99.99> percentage of outliers to remove. Set to 0 to disable. (default: " << outliersRemovalPercentage << ")\n"
|
||||
<< " -maxVertexCount <0 - N> Maximum number of vertices in the output mesh. The mesh might have fewer vertices, but will not exceed this limit. (default: " << maxVertexCount << ")\n"
|
||||
<< " -wlopIterations <1 - 1000> Iterations of the Weighted Locally Optimal Projection (WLOP) simplification algorithm. Higher values take longer but produce a smoother mesh. (default: " << wlopIterations << ")\n"
|
||||
|
||||
log << "Usage:" << "\n";
|
||||
log << "The program requires a path to an input PLY point cloud file, all other input parameters are optional."
|
||||
<< "\n\n";
|
||||
|
||||
log << "The following flags are available\n";
|
||||
log << "Call the program with flag \"-help\", or without parameters to print this message, or check any generated log file.\n";
|
||||
log
|
||||
<< "Call the program with flag \"-verbose\", to print log messages in the standard output stream as well as in the log file.\n\n";
|
||||
|
||||
log << "Parameters are specified as: \"-<argument name> <argument>\", (without <>), and the following parameters are configureable: "
|
||||
<< "\n";
|
||||
log << "\"-inputFile <path>\" (mandatory)" << "\n";
|
||||
log << "\"Input ply file that must contain a point cloud with normals.\n\n";
|
||||
|
||||
log << "\"-outputFile <path>\" (optional, default: odm_mesh.ply)" << "\n";
|
||||
log << "\"Target file in which the mesh is saved.\n\n";
|
||||
|
||||
log << "\"-logFile <path>\" (optional, default: odm_25dmeshing_log.txt)"
|
||||
<< "\n";
|
||||
|
||||
log.setIsPrintingInCout(printInCoutPop);
|
||||
|
|
|
@ -10,8 +10,7 @@
|
|||
#include <CGAL/Delaunay_triangulation_2.h>
|
||||
#include <CGAL/Triangulation_2.h>
|
||||
#include <CGAL/remove_outliers.h>
|
||||
#include <CGAL/grid_simplify_point_set.h>
|
||||
#include <CGAL/bilateral_smooth_point_set.h>
|
||||
#include <CGAL/wlop_simplify_and_regularize_point_set.h>
|
||||
|
||||
#include "Logger.hpp"
|
||||
#include "PlyInterpreter.hpp"
|
||||
|
@ -60,10 +59,12 @@ private:
|
|||
Logger log;
|
||||
|
||||
std::string inputFile = "";
|
||||
std::string outputFile = "odm_mesh.ply";
|
||||
std::string outputFile = "odm_25dmesh.ply";
|
||||
std::string logFilePath = "odm_25dmeshing_log.txt";
|
||||
|
||||
std::vector<PointNormalColor> points;
|
||||
unsigned int maxVertexCount = 100000;
|
||||
double outliersRemovalPercentage = 2;
|
||||
unsigned int wlopIterations = 35;
|
||||
std::vector<Pwn> points;
|
||||
};
|
||||
|
||||
class Odm25dMeshingException: public std::exception {
|
||||
|
|
|
@ -7,10 +7,7 @@ bool PlyInterpreter::is_applicable(CGAL::Ply_reader& reader) {
|
|||
&& reader.does_tag_exist<FT> ("z")
|
||||
&& reader.does_tag_exist<FT> ("nx")
|
||||
&& reader.does_tag_exist<FT> ("ny")
|
||||
&& reader.does_tag_exist<FT> ("nz")
|
||||
&& reader.does_tag_exist<unsigned char> ("diffuse_red")
|
||||
&& reader.does_tag_exist<unsigned char> ("diffuse_green")
|
||||
&& reader.does_tag_exist<unsigned char> ("diffuse_blue");
|
||||
&& reader.does_tag_exist<FT> ("nz");
|
||||
}
|
||||
|
||||
// Describes how to process one line (= one point object)
|
||||
|
@ -18,21 +15,15 @@ void PlyInterpreter::process_line(CGAL::Ply_reader& reader) {
|
|||
FT x = (FT)0., y = (FT)0., z = (FT)0.,
|
||||
nx = (FT)0., ny = (FT)0., nz = (FT)0.;
|
||||
|
||||
Color c = {{ 0, 0, 0 }};
|
||||
|
||||
reader.assign (x, "x");
|
||||
reader.assign (y, "y");
|
||||
reader.assign (z, "z");
|
||||
reader.assign (nx, "nx");
|
||||
reader.assign (ny, "ny");
|
||||
reader.assign (nz, "nz");
|
||||
reader.assign (c[0], "diffuse_red");
|
||||
reader.assign (c[1], "diffuse_green");
|
||||
reader.assign (c[2], "diffuse_blue");
|
||||
|
||||
Point3 p(x, y, z);
|
||||
Vector3 n(nx, ny, nz);
|
||||
PointNormalColor pnc(p, n, c);
|
||||
|
||||
points.push_back(pnc);
|
||||
points.push_back(std::make_pair(p, n));
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/property_map.h>
|
||||
#include <CGAL/IO/read_ply_points.h>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
|
||||
// types
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
|
||||
|
@ -15,19 +14,14 @@ typedef Kernel::FT FT;
|
|||
typedef Kernel::Point_3 Point3;
|
||||
typedef Kernel::Vector_3 Vector3;
|
||||
|
||||
|
||||
// Point with normal vector stored as a std::pair.
|
||||
// Color is red/green/blue array
|
||||
typedef CGAL::cpp11::array<unsigned char, 3> Color;
|
||||
|
||||
// points, normals and colors
|
||||
typedef boost::tuple<Point3, Vector3, Color> PointNormalColor;
|
||||
// points, normals
|
||||
typedef std::pair<Point3, Vector3> Pwn;
|
||||
|
||||
class PlyInterpreter {
|
||||
std::vector<PointNormalColor>& points;
|
||||
std::vector<Pwn>& points;
|
||||
|
||||
public:
|
||||
PlyInterpreter (std::vector<PointNormalColor>& points)
|
||||
PlyInterpreter (std::vector<Pwn>& points)
|
||||
: points (points)
|
||||
{ }
|
||||
bool is_applicable (CGAL::Ply_reader& reader);
|
||||
|
|
|
@ -158,7 +158,6 @@ def config():
|
|||
default=False,
|
||||
help='Use 2.5D mesh to compute the orthophoto')
|
||||
|
||||
|
||||
parser.add_argument('--use-pmvs',
|
||||
action='store_true',
|
||||
default=False,
|
||||
|
@ -253,6 +252,23 @@ def config():
|
|||
'times slightly but helps reduce memory usage. '
|
||||
'Default: %(default)s'))
|
||||
|
||||
parser.add_argument('--mesh-remove-outliers',
|
||||
metavar='<percent>',
|
||||
default=2,
|
||||
type=float,
|
||||
help=('Percentage of outliers to remove from the point set. Set to 0 to disable. '
|
||||
'Applies to 2.5D mesh only. '
|
||||
'Default: %(default)s'))
|
||||
|
||||
parser.add_argument('--mesh-wlop-iterations',
|
||||
metavar='<positive integer>',
|
||||
default=35,
|
||||
type=int,
|
||||
help=('Iterations of the Weighted Locally Optimal Projection (WLOP) simplification algorithm. '
|
||||
'Higher values take longer but produce a smoother mesh. '
|
||||
'Applies to 2.5D mesh only. '
|
||||
'Default: %(default)s'))
|
||||
|
||||
parser.add_argument('--texturing-data-term',
|
||||
metavar='<string>',
|
||||
default='gmi',
|
||||
|
|
|
@ -59,6 +59,8 @@ class ODMApp(ecto.BlackBox):
|
|||
oct_tree=p.args.mesh_octree_depth,
|
||||
samples=p.args.mesh_samples,
|
||||
solver=p.args.mesh_solver_divide,
|
||||
remove_outliers=p.args.mesh_remove_outliers,
|
||||
wlop_iterations=p.args.mesh_wlop_iterations,
|
||||
verbose=p.args.verbose),
|
||||
'texturing': ODMMvsTexCell(data_term=p.args.texturing_data_term,
|
||||
outlier_rem_type=p.args.texturing_outlier_removal_type,
|
||||
|
|
|
@ -19,6 +19,14 @@ class ODMeshingCell(ecto.Cell):
|
|||
'is solved in the surface reconstruction step. '
|
||||
'Increasing this value increases computation '
|
||||
'times slightly but helps reduce memory usage.', 9)
|
||||
|
||||
params.declare("remove_outliers", 'Percentage of outliers to remove from the point set. Set to 0 to disable. '
|
||||
'Applies to 2.5D mesh only.', 2)
|
||||
|
||||
params.declare("wlop_iterations", 'Iterations of the Weighted Locally Optimal Projection (WLOP) simplification algorithm. '
|
||||
'Higher values take longer but produce a smoother mesh. '
|
||||
'Applies to 2.5D mesh only. ', 35)
|
||||
|
||||
params.declare("verbose", 'print additional messages to console', False)
|
||||
|
||||
def declare_io(self, params, inputs, outputs):
|
||||
|
@ -87,12 +95,17 @@ class ODMeshingCell(ecto.Cell):
|
|||
'outfile': tree.odm_25dmesh,
|
||||
'infile': infile,
|
||||
'log': tree.odm_25dmeshing_log,
|
||||
'verbose': verbose
|
||||
'verbose': verbose,
|
||||
'max_vertex': self.params.max_vertex,
|
||||
'remove_outliers': self.params.remove_outliers,
|
||||
'wlop_iterations': self.params.wlop_iterations
|
||||
}
|
||||
|
||||
# run 2.5D meshing binary
|
||||
system.run('{bin}/odm_25dmeshing -inputFile {infile} '
|
||||
'-outputFile {outfile} -logFile {log} {verbose} '.format(**kwargs))
|
||||
'-outputFile {outfile} -logFile {log} '
|
||||
'-maxVertexCount {max_vertex} -outliersRemovalPercentage {remove_outliers} '
|
||||
'-wlopIterations {wlop_iterations} {verbose}'.format(**kwargs))
|
||||
else:
|
||||
log.ODM_WARNING('Found a valid ODM 2.5D Mesh file in: %s' %
|
||||
tree.odm_25dmesh)
|
||||
|
|
|
@ -1,119 +0,0 @@
|
|||
import os
|
||||
|
||||
import ecto
|
||||
|
||||
from opendm import log
|
||||
from opendm import io
|
||||
from opendm import system
|
||||
from opendm import context
|
||||
|
||||
|
||||
class ODMTexturingCell(ecto.Cell):
|
||||
def declare_params(self, params):
|
||||
params.declare("resize", 'resizes images by the largest side', 2400)
|
||||
params.declare("resolution", 'The resolution of the output textures. Must be '
|
||||
'greater than textureWithSize.', 4096)
|
||||
params.declare("size", 'The resolution to rescale the images performing '
|
||||
'the texturing.', 3600)
|
||||
params.declare("verbose", 'print additional messages to console', False)
|
||||
|
||||
def declare_io(self, params, inputs, outputs):
|
||||
inputs.declare("tree", "Struct with paths", [])
|
||||
inputs.declare("args", "The application arguments.", {})
|
||||
inputs.declare("reconstruction", "Clusters output. list of ODMReconstructions", [])
|
||||
outputs.declare("reconstruction", "Clusters output. list of ODMReconstructions", [])
|
||||
|
||||
def process(self, inputs, outputs):
|
||||
|
||||
# Benchmarking
|
||||
start_time = system.now_raw()
|
||||
|
||||
log.ODM_INFO('Running ODM Texturing Cell')
|
||||
|
||||
# get inputs
|
||||
args = self.inputs.args
|
||||
tree = self.inputs.tree
|
||||
verbose = '-verbose' if self.params.verbose else ''
|
||||
|
||||
# define paths and create working directories
|
||||
system.mkdir_p(tree.odm_texturing)
|
||||
if args.use_25dmesh: system.mkdir_p(tree.odm_25dtexturing)
|
||||
|
||||
# check if we rerun cell or not
|
||||
rerun_cell = (args.rerun is not None and
|
||||
args.rerun == 'odm_texturing') or \
|
||||
(args.rerun_all) or \
|
||||
(args.rerun_from is not None and
|
||||
'odm_texturing' in args.rerun_from)
|
||||
|
||||
# Undistort radial distortion
|
||||
if not os.path.isdir(tree.odm_texturing_undistorted_image_path) or rerun_cell:
|
||||
system.run(' '.join([
|
||||
'cd {} &&'.format(tree.opensfm),
|
||||
'PYTHONPATH={}:{}'.format(context.pyopencv_path,
|
||||
context.opensfm_path),
|
||||
'python',
|
||||
os.path.join(context.odm_modules_src_path,
|
||||
'odm_slam/src/undistort_radial.py'),
|
||||
'--output',
|
||||
tree.odm_texturing_undistorted_image_path,
|
||||
tree.opensfm,
|
||||
]))
|
||||
|
||||
system.run(
|
||||
'PYTHONPATH=%s %s/bin/export_bundler %s' %
|
||||
(context.pyopencv_path, context.opensfm_path, tree.opensfm))
|
||||
else:
|
||||
log.ODM_WARNING(
|
||||
'Found a valid Bundler file in: %s' %
|
||||
(tree.opensfm_reconstruction))
|
||||
|
||||
|
||||
runs = [{
|
||||
'out_dir': tree.odm_texturing,
|
||||
'model': tree.odm_mesh
|
||||
}]
|
||||
|
||||
if args.use_25dmesh:
|
||||
runs += [{
|
||||
'out_dir': tree.odm_25dtexturing,
|
||||
'model': tree.odm_25dmesh
|
||||
}]
|
||||
|
||||
for r in runs:
|
||||
odm_textured_model_obj = os.path.join(r['out_dir'], tree.odm_textured_model_obj)
|
||||
|
||||
if not io.file_exists(odm_textured_model_obj) or rerun_cell:
|
||||
log.ODM_DEBUG('Writing ODM Textured file in: %s'
|
||||
% odm_textured_model_obj)
|
||||
|
||||
# odm_texturing definitions
|
||||
kwargs = {
|
||||
'bin': context.odm_modules_path,
|
||||
'out_dir': r['out_dir'],
|
||||
'bundle': tree.opensfm_bundle,
|
||||
'imgs_path': tree.odm_texturing_undistorted_image_path,
|
||||
'imgs_list': tree.opensfm_bundle_list,
|
||||
'model': r['model'],
|
||||
'log': os.path.join(r['out_dir'], tree.odm_texuring_log),
|
||||
'resize': self.params.resize,
|
||||
'resolution': self.params.resolution,
|
||||
'size': self.params.size,
|
||||
'verbose': verbose
|
||||
}
|
||||
|
||||
# run texturing binary
|
||||
system.run('{bin}/odm_texturing -bundleFile {bundle} '
|
||||
'-imagesPath {imgs_path} -imagesListPath {imgs_list} '
|
||||
'-inputModelPath {model} -outputFolder {out_dir}/ '
|
||||
'-textureResolution {resolution} -bundleResizedTo {resize} {verbose} '
|
||||
'-textureWithSize {size} -logFile {log}'.format(**kwargs))
|
||||
else:
|
||||
log.ODM_WARNING('Found a valid ODM Texture file in: %s'
|
||||
% odm_textured_model_obj)
|
||||
|
||||
if args.time:
|
||||
system.benchmark(start_time, tree.benchmarking, 'Texturing')
|
||||
|
||||
log.ODM_INFO('Running ODM Texturing Cell - Finished')
|
||||
return ecto.OK if args.end_with != 'odm_texturing' else ecto.QUIT
|
Ładowanie…
Reference in New Issue