kopia lustrzana https://github.com/OpenDroneMap/ODM
rodzic
6c64d1172c
commit
80cbc2f03b
|
@ -6,12 +6,9 @@ SuperBuild/install
|
||||||
SuperBuild/src
|
SuperBuild/src
|
||||||
build
|
build
|
||||||
opensfm
|
opensfm
|
||||||
pmvs
|
|
||||||
odm_orthophoto
|
odm_orthophoto
|
||||||
odm_texturing
|
odm_texturing
|
||||||
odm_meshing
|
odm_meshing
|
||||||
odm_georeferencing
|
odm_georeferencing
|
||||||
images_resize
|
images_resize
|
||||||
.git
|
.git
|
||||||
|
|
||||||
|
|
||||||
|
|
12
README.md
12
README.md
|
@ -105,7 +105,7 @@ or
|
||||||
|
|
||||||
python run.py --rerun-from odm_meshing project-name
|
python run.py --rerun-from odm_meshing project-name
|
||||||
|
|
||||||
The options for rerunning are: 'resize', 'opensfm', 'slam', 'cmvs', 'pmvs', 'odm_meshing', 'mvs_texturing', 'odm_georeferencing', 'odm_orthophoto'
|
The options for rerunning are: 'resize', 'opensfm', 'slam', 'smvs', 'odm_meshing', 'mvs_texturing', 'odm_georeferencing', 'odm_orthophoto'
|
||||||
|
|
||||||
### View Results
|
### View Results
|
||||||
|
|
||||||
|
@ -151,7 +151,7 @@ You can also view the orthophoto GeoTIFF in [QGIS](http://www.qgis.org/) or othe
|
||||||
|
|
||||||
## Build and Run Using Docker
|
## Build and Run Using Docker
|
||||||
|
|
||||||
(Instructions below apply to Ubuntu 14.04, but the Docker image workflow
|
(Instructions below apply to Ubuntu 14.04, but the Docker image workflow
|
||||||
has equivalent procedures for Mac OS X and Windows. See [docs.docker.com](https://docs.docker.com/))
|
has equivalent procedures for Mac OS X and Windows. See [docs.docker.com](https://docs.docker.com/))
|
||||||
|
|
||||||
OpenDroneMap is Dockerized, meaning you can use containerization to build and run it without tampering with the configuration of libraries and packages already
|
OpenDroneMap is Dockerized, meaning you can use containerization to build and run it without tampering with the configuration of libraries and packages already
|
||||||
|
@ -177,7 +177,7 @@ If you want to build your own Docker image from sources, type:
|
||||||
Using this method, the containerized ODM will process the images in the OpenDroneMap/images directory and output results
|
Using this method, the containerized ODM will process the images in the OpenDroneMap/images directory and output results
|
||||||
to the OpenDroneMap/odm_orthophoto and OpenDroneMap/odm_texturing directories as described in the [Viewing Results](https://github.com/OpenDroneMap/OpenDroneMap/wiki/Output-and-Results) section.
|
to the OpenDroneMap/odm_orthophoto and OpenDroneMap/odm_texturing directories as described in the [Viewing Results](https://github.com/OpenDroneMap/OpenDroneMap/wiki/Output-and-Results) section.
|
||||||
If you want to view other results outside the Docker image simply add which directories you're interested in to the run command in the same pattern
|
If you want to view other results outside the Docker image simply add which directories you're interested in to the run command in the same pattern
|
||||||
established above. For example, if you're interested in the dense cloud results generated by PMVS and in the orthophoto,
|
established above. For example, if you're interested in the dense cloud results generated by OpenSfM and in the orthophoto,
|
||||||
simply use the following `docker run` command after building the image:
|
simply use the following `docker run` command after building the image:
|
||||||
|
|
||||||
docker run -it --rm \
|
docker run -it --rm \
|
||||||
|
@ -195,7 +195,7 @@ If you want to get all intermediate outputs, run the following command:
|
||||||
-v "$(pwd)/odm_orthophoto:/code/odm_orthophoto" \
|
-v "$(pwd)/odm_orthophoto:/code/odm_orthophoto" \
|
||||||
-v "$(pwd)/odm_texturing:/code/odm_texturing" \
|
-v "$(pwd)/odm_texturing:/code/odm_texturing" \
|
||||||
-v "$(pwd)/opensfm:/code/opensfm" \
|
-v "$(pwd)/opensfm:/code/opensfm" \
|
||||||
-v "$(pwd)/pmvs:/code/pmvs" \
|
-v "$(pwd)/smvs:/code/smvs" \
|
||||||
opendronemap/opendronemap
|
opendronemap/opendronemap
|
||||||
|
|
||||||
To pass in custom parameters to the run.py script, simply pass it as arguments to the `docker run` command. For example:
|
To pass in custom parameters to the run.py script, simply pass it as arguments to the `docker run` command. For example:
|
||||||
|
@ -222,7 +222,7 @@ When building your own Docker image, if image size is of importance to you, you
|
||||||
This will clean up intermediate steps in the Docker build process, resulting in a significantly smaller image (about half the size).
|
This will clean up intermediate steps in the Docker build process, resulting in a significantly smaller image (about half the size).
|
||||||
|
|
||||||
Experimental flags need to be enabled in Docker to use the ```--squash``` flag. To enable this, insert the following into the file ```/etc/docker/daemon.json```:
|
Experimental flags need to be enabled in Docker to use the ```--squash``` flag. To enable this, insert the following into the file ```/etc/docker/daemon.json```:
|
||||||
|
|
||||||
{
|
{
|
||||||
"experimental": true
|
"experimental": true
|
||||||
}
|
}
|
||||||
|
@ -244,7 +244,7 @@ Coming soon...
|
||||||
|
|
||||||
## Documentation:
|
## Documentation:
|
||||||
|
|
||||||
For documentation, everything is being moved to [http://docs.opendronemap.org/](http://docs.opendronemap.org/) but you can also take a look at our [wiki](https://github.com/OpenDroneMap/OpenDroneMap/wiki). Check those places first if you are having problems. There's also help at [community forum](http://community.opendronemap.org/), and if you still need help and think you've found a bug or need an enhancement, look through the issue queue or create one.
|
For documentation, everything is being moved to [http://docs.opendronemap.org/](http://docs.opendronemap.org/) but you can also take a look at our [wiki](https://github.com/OpenDroneMap/OpenDroneMap/wiki). Check those places first if you are having problems. There's also help at [community forum](http://community.opendronemap.org/), and if you still need help and think you've found a bug or need an enhancement, look through the issue queue or create one.
|
||||||
|
|
||||||
## Developers
|
## Developers
|
||||||
|
|
||||||
|
|
|
@ -114,14 +114,12 @@ SETUP_EXTERNAL_PROJECT(Hexer 1.4 ON)
|
||||||
# ---------------------------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------------------------
|
||||||
# Open Geometric Vision (OpenGV)
|
# Open Geometric Vision (OpenGV)
|
||||||
# Open Structure from Motion (OpenSfM)
|
# Open Structure from Motion (OpenSfM)
|
||||||
# Clustering Views for Multi-view Stereo (CMVS)
|
|
||||||
# Catkin
|
# Catkin
|
||||||
# Ecto
|
# Ecto
|
||||||
#
|
#
|
||||||
|
|
||||||
set(custom_libs OpenGV
|
set(custom_libs OpenGV
|
||||||
OpenSfM
|
OpenSfM
|
||||||
CMVS
|
|
||||||
Catkin
|
Catkin
|
||||||
Ecto
|
Ecto
|
||||||
LASzip
|
LASzip
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
set(_proj_name cmvs)
|
|
||||||
set(_SB_BINARY_DIR "${SB_BINARY_DIR}/${_proj_name}")
|
|
||||||
|
|
||||||
ExternalProject_Add(${_proj_name}
|
|
||||||
PREFIX ${_SB_BINARY_DIR}
|
|
||||||
TMP_DIR ${_SB_BINARY_DIR}/tmp
|
|
||||||
STAMP_DIR ${_SB_BINARY_DIR}/stamp
|
|
||||||
#--Download step--------------
|
|
||||||
DOWNLOAD_DIR ${SB_DOWNLOAD_DIR}/${_proj_name}
|
|
||||||
URL https://github.com/edgarriba/CMVS-PMVS/archive/master.zip
|
|
||||||
URL_MD5 dbb1493f49ca099b4208381bd20d1435
|
|
||||||
#--Update/Patch step----------
|
|
||||||
UPDATE_COMMAND ""
|
|
||||||
#--Configure step-------------
|
|
||||||
SOURCE_DIR ${SB_SOURCE_DIR}/${_proj_name}
|
|
||||||
CONFIGURE_COMMAND cmake <SOURCE_DIR>/program
|
|
||||||
-DCMAKE_RUNTIME_OUTPUT_DIRECTORY:PATH=${SB_INSTALL_DIR}/bin
|
|
||||||
-DCMAKE_INSTALL_PREFIX:PATH=${SB_INSTALL_DIR}
|
|
||||||
#--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
|
|
||||||
)
|
|
||||||
|
|
|
@ -10,8 +10,6 @@ Licensing for portions of OpenDroneMap are as follows:
|
||||||
* libcv - BSD - http://opencv.org/license.html
|
* libcv - BSD - http://opencv.org/license.html
|
||||||
* libcvaux - BSD - http://opencv.org/license.html
|
* libcvaux - BSD - http://opencv.org/license.html
|
||||||
* bundler - GPLv3 - http://www.gnu.org/copyleft/gpl.html
|
* bundler - GPLv3 - http://www.gnu.org/copyleft/gpl.html
|
||||||
* cmvs - GPLv3 - http://www.gnu.org/copyleft/gpl.html
|
|
||||||
* pmvs2 - GPLv3 - http://www.gnu.org/copyleft/gpl.html
|
|
||||||
* parallel - GPLv3 - http://www.gnu.org/copyleft/gpl.html
|
* parallel - GPLv3 - http://www.gnu.org/copyleft/gpl.html
|
||||||
* PoissonRecon - BSD - http://www.cs.jhu.edu/~misha/Code/PoissonRecon/license.txt
|
* PoissonRecon - BSD - http://www.cs.jhu.edu/~misha/Code/PoissonRecon/license.txt
|
||||||
* vlfeat - BSD - http://www.vlfeat.org/license.html
|
* vlfeat - BSD - http://www.vlfeat.org/license.html
|
||||||
|
|
|
@ -7,7 +7,7 @@ from appsettings import SettingsParser
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
# parse arguments
|
# parse arguments
|
||||||
processopts = ['dataset', 'opensfm', 'slam', 'cmvs', 'pmvs', 'smvs',
|
processopts = ['dataset', 'opensfm', 'slam', 'smvs',
|
||||||
'odm_meshing', 'odm_25dmeshing', 'mvs_texturing', 'odm_georeferencing',
|
'odm_meshing', 'odm_25dmeshing', 'mvs_texturing', 'odm_georeferencing',
|
||||||
'odm_dem', 'odm_orthophoto']
|
'odm_dem', 'odm_orthophoto']
|
||||||
|
|
||||||
|
@ -241,63 +241,6 @@ def config():
|
||||||
'with --smvs-enable-shading when you have simple JPGs with '
|
'with --smvs-enable-shading when you have simple JPGs with '
|
||||||
'SRGB gamma correction. Default: %(default)s')
|
'SRGB gamma correction. Default: %(default)s')
|
||||||
|
|
||||||
parser.add_argument('--cmvs-maxImages',
|
|
||||||
metavar='<integer>',
|
|
||||||
default=500,
|
|
||||||
type=int,
|
|
||||||
help='The maximum number of images per cluster. '
|
|
||||||
'Default: %(default)s')
|
|
||||||
|
|
||||||
parser.add_argument('--pmvs-level',
|
|
||||||
metavar='<positive integer>',
|
|
||||||
default=1,
|
|
||||||
type=int,
|
|
||||||
help=('The level in the image pyramid that is used '
|
|
||||||
'for the computation. see '
|
|
||||||
'http://www.di.ens.fr/pmvs/documentation.html for '
|
|
||||||
'more pmvs documentation. Default: %(default)s'))
|
|
||||||
|
|
||||||
parser.add_argument('--pmvs-csize',
|
|
||||||
metavar='<positive integer>',
|
|
||||||
default=2,
|
|
||||||
type=int,
|
|
||||||
help='Cell size controls the density of reconstructions'
|
|
||||||
'Default: %(default)s')
|
|
||||||
|
|
||||||
parser.add_argument('--pmvs-threshold',
|
|
||||||
metavar='<float: -1.0 <= x <= 1.0>',
|
|
||||||
default=0.7,
|
|
||||||
type=float,
|
|
||||||
help=('A patch reconstruction is accepted as a success '
|
|
||||||
'and kept if its associated photometric consistency '
|
|
||||||
'measure is above this threshold. Default: %(default)s'))
|
|
||||||
|
|
||||||
parser.add_argument('--pmvs-wsize',
|
|
||||||
metavar='<positive integer>',
|
|
||||||
default=7,
|
|
||||||
type=int,
|
|
||||||
help='pmvs samples wsize x wsize pixel colors from '
|
|
||||||
'each image to compute photometric consistency '
|
|
||||||
'score. For example, when wsize=7, 7x7=49 pixel '
|
|
||||||
'colors are sampled in each image. Increasing the '
|
|
||||||
'value leads to more stable reconstructions, but '
|
|
||||||
'the program becomes slower. Default: %(default)s')
|
|
||||||
|
|
||||||
parser.add_argument('--pmvs-min-images',
|
|
||||||
metavar='<positive integer>',
|
|
||||||
default=3,
|
|
||||||
type=int,
|
|
||||||
help=('Each 3D point must be visible in at least '
|
|
||||||
'minImageNum images for being reconstructed. 3 is '
|
|
||||||
'suggested in general. Default: %(default)s'))
|
|
||||||
|
|
||||||
parser.add_argument('--pmvs-num-cores',
|
|
||||||
metavar='<positive integer>',
|
|
||||||
default=context.num_cores,
|
|
||||||
type=int,
|
|
||||||
help=('The maximum number of cores to use in dense '
|
|
||||||
'reconstruction. Default: %(default)s'))
|
|
||||||
|
|
||||||
parser.add_argument('--mesh-size',
|
parser.add_argument('--mesh-size',
|
||||||
metavar='<positive integer>',
|
metavar='<positive integer>',
|
||||||
default=100000,
|
default=100000,
|
||||||
|
@ -612,11 +555,6 @@ def config():
|
||||||
log.ODM_INFO('Fast orthophoto is turned on, automatically setting --use-25dmesh')
|
log.ODM_INFO('Fast orthophoto is turned on, automatically setting --use-25dmesh')
|
||||||
args.use_25dmesh = True
|
args.use_25dmesh = True
|
||||||
|
|
||||||
# Cannot use pmvs
|
|
||||||
if args.use_pmvs:
|
|
||||||
log.ODM_INFO('Fast orthophoto is turned on, cannot use pmvs (removing --use-pmvs)')
|
|
||||||
args.use_pmvs = False
|
|
||||||
|
|
||||||
if args.dtm and args.pc_classify == 'none':
|
if args.dtm and args.pc_classify == 'none':
|
||||||
log.ODM_INFO("DTM is turned on, automatically turning on point cloud classification")
|
log.ODM_INFO("DTM is turned on, automatically turning on point cloud classification")
|
||||||
args.pc_classify = "smrf"
|
args.pc_classify = "smrf"
|
||||||
|
|
|
@ -23,11 +23,6 @@ ccd_widths_path = os.path.join(opensfm_path, 'opensfm/data/sensor_data.json')
|
||||||
# define orb_slam2 path
|
# define orb_slam2 path
|
||||||
orb_slam2_path = os.path.join(superbuild_path, "src/orb_slam2")
|
orb_slam2_path = os.path.join(superbuild_path, "src/orb_slam2")
|
||||||
|
|
||||||
# define pmvs path
|
|
||||||
cmvs_path = os.path.join(superbuild_path, "install/bin/cmvs")
|
|
||||||
cmvs_opts_path = os.path.join(superbuild_path, "install/bin/genOption")
|
|
||||||
pmvs2_path = os.path.join(superbuild_path, "install/bin/pmvs2")
|
|
||||||
|
|
||||||
# define smvs join_paths
|
# define smvs join_paths
|
||||||
makescene_path = os.path.join(superbuild_path, 'src', 'elibs', 'mve', 'apps', 'makescene', 'makescene') #TODO: don't install in source
|
makescene_path = os.path.join(superbuild_path, 'src', 'elibs', 'mve', 'apps', 'makescene', 'makescene') #TODO: don't install in source
|
||||||
smvs_path = os.path.join(superbuild_path, 'src', 'elibs', 'smvs', 'app', 'smvsrecon')
|
smvs_path = os.path.join(superbuild_path, 'src', 'elibs', 'smvs', 'app', 'smvsrecon')
|
||||||
|
|
|
@ -8,8 +8,6 @@ from scripts.opensfm import opensfm
|
||||||
|
|
||||||
# Define pipeline tasks
|
# Define pipeline tasks
|
||||||
tasks_dict = {'1': 'opensfm',
|
tasks_dict = {'1': 'opensfm',
|
||||||
'2': 'cmvs',
|
|
||||||
'3': 'pmvs',
|
|
||||||
'4': 'odm_meshing',
|
'4': 'odm_meshing',
|
||||||
'5': 'mvs_texturing',
|
'5': 'mvs_texturing',
|
||||||
'6': 'odm_georeferencing',
|
'6': 'odm_georeferencing',
|
||||||
|
@ -52,7 +50,7 @@ class ODMTaskManager(object):
|
||||||
'args': _odm_app.args,
|
'args': _odm_app.args,
|
||||||
'photos': _odm_app.photos}
|
'photos': _odm_app.photos}
|
||||||
|
|
||||||
elif task_name in ['cmvs', 'pmvs', 'odm_meshing', 'mvs_texturing', 'odm_georeferencing', 'odm_orthophoto', 'zip_results']:
|
elif task_name in [ 'odm_meshing', 'mvs_texturing', 'odm_georeferencing', 'odm_orthophoto', 'zip_results']:
|
||||||
# setup this task
|
# setup this task
|
||||||
command = None
|
command = None
|
||||||
inputs = {}
|
inputs = {}
|
||||||
|
|
|
@ -274,14 +274,8 @@ class ODM_GeoRef(object):
|
||||||
with open(json_file, 'w') as f:
|
with open(json_file, 'w') as f:
|
||||||
f.write(pipeline)
|
f.write(pipeline)
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
# call pdal
|
# call pdal
|
||||||
system.run('{bin}/pdal pipeline -i {json} --readers.ply.filename={f_in} '
|
|
||||||
'--writers.las.filename={f_out}'.format(**kwargs))
|
|
||||||
=======
|
|
||||||
# call pdal
|
|
||||||
system.run('{bin}/pdal pipeline -i {json} --readers.ply.filename={f_in}'.format(**kwargs))
|
system.run('{bin}/pdal pipeline -i {json} --readers.ply.filename={f_in}'.format(**kwargs))
|
||||||
>>>>>>> 4a00c4d8411befc0c1b01a36f713e61633f002b3
|
|
||||||
|
|
||||||
def utm_to_latlon(self, _file, _photo, idx):
|
def utm_to_latlon(self, _file, _photo, idx):
|
||||||
|
|
||||||
|
@ -421,7 +415,6 @@ class ODM_Tree(object):
|
||||||
self.dataset_raw = io.join_paths(self.root_path, 'images')
|
self.dataset_raw = io.join_paths(self.root_path, 'images')
|
||||||
self.opensfm = io.join_paths(self.root_path, 'opensfm')
|
self.opensfm = io.join_paths(self.root_path, 'opensfm')
|
||||||
self.smvs = io.join_paths(self.root_path, 'smvs')
|
self.smvs = io.join_paths(self.root_path, 'smvs')
|
||||||
self.pmvs = io.join_paths(self.root_path, 'pmvs')
|
|
||||||
self.odm_meshing = io.join_paths(self.root_path, 'odm_meshing')
|
self.odm_meshing = io.join_paths(self.root_path, 'odm_meshing')
|
||||||
self.odm_texturing = io.join_paths(self.root_path, 'odm_texturing')
|
self.odm_texturing = io.join_paths(self.root_path, 'odm_texturing')
|
||||||
self.odm_25dtexturing = io.join_paths(self.root_path, 'odm_texturing_25d')
|
self.odm_25dtexturing = io.join_paths(self.root_path, 'odm_texturing_25d')
|
||||||
|
@ -446,13 +439,6 @@ class ODM_Tree(object):
|
||||||
self.opensfm_model = io.join_paths(self.opensfm, 'depthmaps/merged.ply')
|
self.opensfm_model = io.join_paths(self.opensfm, 'depthmaps/merged.ply')
|
||||||
self.opensfm_transformation = io.join_paths(self.opensfm, 'geocoords_transformation.txt')
|
self.opensfm_transformation = io.join_paths(self.opensfm, 'geocoords_transformation.txt')
|
||||||
|
|
||||||
# pmvs
|
|
||||||
self.pmvs_rec_path = io.join_paths(self.pmvs, 'recon0')
|
|
||||||
self.pmvs_bundle = io.join_paths(self.pmvs_rec_path, 'bundle.rd.out')
|
|
||||||
self.pmvs_visdat = io.join_paths(self.pmvs_rec_path, 'vis.dat')
|
|
||||||
self.pmvs_options = io.join_paths(self.pmvs_rec_path, 'pmvs_options.txt')
|
|
||||||
self.pmvs_model = io.join_paths(self.pmvs_rec_path, 'models/option-0000.ply')
|
|
||||||
|
|
||||||
# smvs
|
# smvs
|
||||||
self.smvs_model = io.join_paths(self.smvs, 'smvs_dense_point_cloud.ply')
|
self.smvs_model = io.join_paths(self.smvs, 'smvs_dense_point_cloud.ply')
|
||||||
self.mve_path = io.join_paths(self.opensfm, 'mve')
|
self.mve_path = io.join_paths(self.opensfm, 'mve')
|
||||||
|
|
2
run.py
2
run.py
|
@ -33,7 +33,7 @@ if __name__ == '__main__':
|
||||||
+ args.project_path + "/odm_orthophoto "
|
+ args.project_path + "/odm_orthophoto "
|
||||||
+ args.project_path + "/odm_texturing "
|
+ args.project_path + "/odm_texturing "
|
||||||
+ args.project_path + "/opensfm "
|
+ args.project_path + "/opensfm "
|
||||||
+ args.project_path + "/pmvs")
|
+ args.project_path + "/smvs")
|
||||||
|
|
||||||
# create an instance of my App BlackBox
|
# create an instance of my App BlackBox
|
||||||
# internally configure all tasks
|
# internally configure all tasks
|
||||||
|
|
|
@ -1,68 +0,0 @@
|
||||||
import ecto
|
|
||||||
|
|
||||||
from opendm import io
|
|
||||||
from opendm import log
|
|
||||||
from opendm import system
|
|
||||||
from opendm import context
|
|
||||||
|
|
||||||
|
|
||||||
class ODMCmvsCell(ecto.Cell):
|
|
||||||
|
|
||||||
def declare_params(self, params):
|
|
||||||
params.declare("max_images", 'The maximum number of images '
|
|
||||||
'per cluster', 500)
|
|
||||||
params.declare("cores", 'The maximum number of cores to use '
|
|
||||||
'in dense reconstruction.', context.num_cores)
|
|
||||||
|
|
||||||
def declare_io(self, params, inputs, outputs):
|
|
||||||
inputs.declare("tree", "Struct with paths", [])
|
|
||||||
inputs.declare("args", "Struct with paths", [])
|
|
||||||
inputs.declare("reconstruction", "list of ODMReconstructions", [])
|
|
||||||
outputs.declare("reconstruction", "list of ODMReconstructions", [])
|
|
||||||
|
|
||||||
def process(self, inputs, outputs):
|
|
||||||
|
|
||||||
# Benchmarking
|
|
||||||
start_time = system.now_raw()
|
|
||||||
|
|
||||||
log.ODM_INFO('Running ODM CMVS Cell')
|
|
||||||
|
|
||||||
# get inputs
|
|
||||||
args = self.inputs.args
|
|
||||||
tree = self.inputs.tree
|
|
||||||
|
|
||||||
# check if we rerun cell or not
|
|
||||||
rerun_cell = (args.rerun is not None and
|
|
||||||
args.rerun == 'cmvs') or \
|
|
||||||
(args.rerun_all) or \
|
|
||||||
(args.rerun_from is not None and
|
|
||||||
'cmvs' in args.rerun_from)
|
|
||||||
|
|
||||||
if not io.file_exists(tree.pmvs_bundle) or rerun_cell:
|
|
||||||
log.ODM_DEBUG('Writing CMVS vis in: %s' % tree.pmvs_bundle)
|
|
||||||
|
|
||||||
# copy bundle file to pmvs dir
|
|
||||||
from shutil import copyfile
|
|
||||||
copyfile(tree.opensfm_bundle,
|
|
||||||
tree.pmvs_bundle)
|
|
||||||
|
|
||||||
kwargs = {
|
|
||||||
'bin': context.cmvs_path,
|
|
||||||
'prefix': self.inputs.tree.pmvs_rec_path,
|
|
||||||
'max_images': self.params.max_images,
|
|
||||||
'cores': self.params.cores
|
|
||||||
}
|
|
||||||
|
|
||||||
# run cmvs
|
|
||||||
system.run('{bin} {prefix}/ {max_images} {cores}'.format(**kwargs))
|
|
||||||
else:
|
|
||||||
log.ODM_WARNING('Found a valid CMVS file in: %s' %
|
|
||||||
tree.pmvs_bundle)
|
|
||||||
|
|
||||||
outputs.reconstruction = inputs.reconstruction
|
|
||||||
|
|
||||||
if args.time:
|
|
||||||
system.benchmark(start_time, tree.benchmarking, 'CMVS')
|
|
||||||
|
|
||||||
log.ODM_INFO('Running ODM CMVS Cell - Finished')
|
|
||||||
return ecto.OK if args.end_with != 'cmvs' else ecto.QUIT
|
|
|
@ -5,8 +5,6 @@ from opendm import io
|
||||||
from opendm import system
|
from opendm import system
|
||||||
from opendm import context
|
from opendm import context
|
||||||
|
|
||||||
import pmvs2nvmcams
|
|
||||||
|
|
||||||
class ODMMvsTexCell(ecto.Cell):
|
class ODMMvsTexCell(ecto.Cell):
|
||||||
def declare_params(self, params):
|
def declare_params(self, params):
|
||||||
params.declare("data_term", 'Data term: [area, gmi] default: gmi', "gmi")
|
params.declare("data_term", 'Data term: [area, gmi] default: gmi', "gmi")
|
||||||
|
@ -38,7 +36,7 @@ class ODMMvsTexCell(ecto.Cell):
|
||||||
|
|
||||||
# define paths and create working directories
|
# define paths and create working directories
|
||||||
system.mkdir_p(tree.odm_texturing)
|
system.mkdir_p(tree.odm_texturing)
|
||||||
if args.use_25dmesh: system.mkdir_p(tree.odm_25dtexturing)
|
if args.use_25dmesh: system.mkdir_p(tree.odm_25dtexturing)
|
||||||
|
|
||||||
# check if we rerun cell or not
|
# check if we rerun cell or not
|
||||||
rerun_cell = (args.rerun is not None and
|
rerun_cell = (args.rerun is not None and
|
||||||
|
@ -62,11 +60,11 @@ class ODMMvsTexCell(ecto.Cell):
|
||||||
'model': tree.odm_25dmesh,
|
'model': tree.odm_25dmesh,
|
||||||
|
|
||||||
# We always skip the visibility test when using the 2.5D mesh
|
# We always skip the visibility test when using the 2.5D mesh
|
||||||
# because many faces end up being narrow, and almost perpendicular
|
# because many faces end up being narrow, and almost perpendicular
|
||||||
# to the ground plane. The visibility test improperly classifies
|
# to the ground plane. The visibility test improperly classifies
|
||||||
# them as "not seen" since the test is done on a single triangle vertex,
|
# them as "not seen" since the test is done on a single triangle vertex,
|
||||||
# and while one vertex might be occluded, the other two might not.
|
# and while one vertex might be occluded, the other two might not.
|
||||||
'force_skip_vis_test': True
|
'force_skip_vis_test': True
|
||||||
}]
|
}]
|
||||||
|
|
||||||
for r in runs:
|
for r in runs:
|
||||||
|
@ -82,7 +80,7 @@ class ODMMvsTexCell(ecto.Cell):
|
||||||
skipLocalSeamLeveling = ""
|
skipLocalSeamLeveling = ""
|
||||||
skipHoleFilling = ""
|
skipHoleFilling = ""
|
||||||
keepUnseenFaces = ""
|
keepUnseenFaces = ""
|
||||||
|
|
||||||
if (self.params.skip_vis_test or r['force_skip_vis_test']):
|
if (self.params.skip_vis_test or r['force_skip_vis_test']):
|
||||||
skipGeometricVisibilityTest = "--skip_geometric_visibility_test"
|
skipGeometricVisibilityTest = "--skip_geometric_visibility_test"
|
||||||
if (self.params.skip_glob_seam_leveling):
|
if (self.params.skip_glob_seam_leveling):
|
||||||
|
@ -98,8 +96,6 @@ class ODMMvsTexCell(ecto.Cell):
|
||||||
kwargs = {
|
kwargs = {
|
||||||
'bin': context.mvstex_path,
|
'bin': context.mvstex_path,
|
||||||
'out_dir': io.join_paths(r['out_dir'], "odm_textured_model"),
|
'out_dir': io.join_paths(r['out_dir'], "odm_textured_model"),
|
||||||
'pmvs_folder': tree.pmvs_rec_path,
|
|
||||||
'nvm_file': io.join_paths(tree.pmvs_rec_path, "nvmCams.nvm"),
|
|
||||||
'model': r['model'],
|
'model': r['model'],
|
||||||
'dataTerm': self.params.data_term,
|
'dataTerm': self.params.data_term,
|
||||||
'outlierRemovalType': self.params.outlier_rem_type,
|
'outlierRemovalType': self.params.outlier_rem_type,
|
||||||
|
@ -111,16 +107,8 @@ class ODMMvsTexCell(ecto.Cell):
|
||||||
'toneMapping': self.params.tone_mapping
|
'toneMapping': self.params.tone_mapping
|
||||||
}
|
}
|
||||||
|
|
||||||
if not args.use_pmvs:
|
kwargs['nvm_file'] = io.join_paths(tree.opensfm,
|
||||||
kwargs['nvm_file'] = io.join_paths(tree.opensfm,
|
"reconstruction.nvm")
|
||||||
"reconstruction.nvm")
|
|
||||||
else:
|
|
||||||
log.ODM_DEBUG('Generating .nvm file from pmvs output: %s'
|
|
||||||
% '{nvm_file}'.format(**kwargs))
|
|
||||||
|
|
||||||
# Create .nvm camera file.
|
|
||||||
pmvs2nvmcams.run('{pmvs_folder}'.format(**kwargs),
|
|
||||||
'{nvm_file}'.format(**kwargs))
|
|
||||||
|
|
||||||
# Make sure tmp directory is empty
|
# Make sure tmp directory is empty
|
||||||
mvs_tmp_dir = os.path.join(r['out_dir'], 'tmp')
|
mvs_tmp_dir = os.path.join(r['out_dir'], 'tmp')
|
||||||
|
|
|
@ -10,8 +10,6 @@ from dataset import ODMLoadDatasetCell
|
||||||
from run_opensfm import ODMOpenSfMCell
|
from run_opensfm import ODMOpenSfMCell
|
||||||
from smvs import ODMSmvsCell
|
from smvs import ODMSmvsCell
|
||||||
from odm_slam import ODMSlamCell
|
from odm_slam import ODMSlamCell
|
||||||
from pmvs import ODMPmvsCell
|
|
||||||
from cmvs import ODMCmvsCell
|
|
||||||
from odm_meshing import ODMeshingCell
|
from odm_meshing import ODMeshingCell
|
||||||
from mvstex import ODMMvsTexCell
|
from mvstex import ODMMvsTexCell
|
||||||
from odm_georeferencing import ODMGeoreferencingCell
|
from odm_georeferencing import ODMGeoreferencingCell
|
||||||
|
@ -51,13 +49,6 @@ class ODMApp(ecto.BlackBox):
|
||||||
fixed_camera_params=p.args.use_fixed_camera_params,
|
fixed_camera_params=p.args.use_fixed_camera_params,
|
||||||
hybrid_bundle_adjustment=p.args.use_hybrid_bundle_adjustment),
|
hybrid_bundle_adjustment=p.args.use_hybrid_bundle_adjustment),
|
||||||
'slam': ODMSlamCell(),
|
'slam': ODMSlamCell(),
|
||||||
'cmvs': ODMCmvsCell(max_images=p.args.cmvs_maxImages),
|
|
||||||
'pmvs': ODMPmvsCell(level=p.args.pmvs_level,
|
|
||||||
csize=p.args.pmvs_csize,
|
|
||||||
thresh=p.args.pmvs_threshold,
|
|
||||||
wsize=p.args.pmvs_wsize,
|
|
||||||
min_imgs=p.args.pmvs_min_images,
|
|
||||||
cores=p.args.pmvs_num_cores),
|
|
||||||
'smvs': ODMSmvsCell(alpha=p.args.smvs_alpha,
|
'smvs': ODMSmvsCell(alpha=p.args.smvs_alpha,
|
||||||
scale=p.args.smvs_scale,
|
scale=p.args.smvs_scale,
|
||||||
threads=p.args.max_concurrency,
|
threads=p.args.max_concurrency,
|
||||||
|
@ -135,7 +126,7 @@ class ODMApp(ecto.BlackBox):
|
||||||
self.args[:] >> self.smvs['args'],
|
self.args[:] >> self.smvs['args'],
|
||||||
self.opensfm['reconstruction'] >> self.smvs['reconstruction']]
|
self.opensfm['reconstruction'] >> self.smvs['reconstruction']]
|
||||||
|
|
||||||
# create odm mesh from pmvs point cloud
|
# create odm mesh from smvs point cloud
|
||||||
connections += [self.tree[:] >> self.meshing['tree'],
|
connections += [self.tree[:] >> self.meshing['tree'],
|
||||||
self.args[:] >> self.meshing['args'],
|
self.args[:] >> self.meshing['args'],
|
||||||
self.smvs['reconstruction'] >> self.meshing['reconstruction']]
|
self.smvs['reconstruction'] >> self.meshing['reconstruction']]
|
||||||
|
@ -169,20 +160,14 @@ class ODMApp(ecto.BlackBox):
|
||||||
connections += [self.tree[:] >> self.slam['tree'],
|
connections += [self.tree[:] >> self.slam['tree'],
|
||||||
self.args[:] >> self.slam['args']]
|
self.args[:] >> self.slam['args']]
|
||||||
|
|
||||||
# run cmvs
|
connections += [self.tree[:] >> self.smvs['tree'],
|
||||||
connections += [self.tree[:] >> self.cmvs['tree'],
|
self.args[:] >> self.smvs['args'],
|
||||||
self.args[:] >> self.cmvs['args'],
|
self.slam['reconstruction'] >> self.smvs['reconstruction']]
|
||||||
self.slam['reconstruction'] >> self.cmvs['reconstruction']]
|
|
||||||
|
|
||||||
# run pmvs
|
|
||||||
connections += [self.tree[:] >> self.pmvs['tree'],
|
|
||||||
self.args[:] >> self.pmvs['args'],
|
|
||||||
self.cmvs['reconstruction'] >> self.pmvs['reconstruction']]
|
|
||||||
|
|
||||||
# create odm mesh
|
# create odm mesh
|
||||||
connections += [self.tree[:] >> self.meshing['tree'],
|
connections += [self.tree[:] >> self.meshing['tree'],
|
||||||
self.args[:] >> self.meshing['args'],
|
self.args[:] >> self.meshing['args'],
|
||||||
self.pmvs['reconstruction'] >> self.meshing['reconstruction']]
|
self.smvs['reconstruction'] >> self.meshing['reconstruction']]
|
||||||
|
|
||||||
# create odm texture
|
# create odm texture
|
||||||
connections += [self.tree[:] >> self.texturing['tree'],
|
connections += [self.tree[:] >> self.texturing['tree'],
|
||||||
|
|
|
@ -92,13 +92,12 @@ class ODMGeoreferencingCell(ecto.Cell):
|
||||||
'verbose': verbose
|
'verbose': verbose
|
||||||
|
|
||||||
}
|
}
|
||||||
if not args.use_pmvs:
|
|
||||||
if args.fast_orthophoto:
|
if args.fast_orthophoto:
|
||||||
kwargs['pc'] = os.path.join(tree.opensfm, 'reconstruction.ply')
|
kwargs['pc'] = os.path.join(tree.opensfm, 'reconstruction.ply')
|
||||||
else:
|
|
||||||
kwargs['pc'] = tree.opensfm_model
|
|
||||||
else:
|
else:
|
||||||
kwargs['pc'] = tree.pmvs_model
|
kwargs['pc'] = tree.opensfm_model
|
||||||
|
|
||||||
|
|
||||||
# Check to see if the GCP file exists
|
# Check to see if the GCP file exists
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,6 @@ class ODMSlamCell(ecto.Cell):
|
||||||
|
|
||||||
# create working directories
|
# create working directories
|
||||||
system.mkdir_p(tree.opensfm)
|
system.mkdir_p(tree.opensfm)
|
||||||
system.mkdir_p(tree.pmvs)
|
|
||||||
|
|
||||||
vocabulary = os.path.join(context.orb_slam2_path,
|
vocabulary = os.path.join(context.orb_slam2_path,
|
||||||
'Vocabulary/ORBvoc.txt')
|
'Vocabulary/ORBvoc.txt')
|
||||||
|
@ -96,16 +95,5 @@ class ODMSlamCell(ecto.Cell):
|
||||||
'Found a valid Bundler file in: {}'.format(
|
'Found a valid Bundler file in: {}'.format(
|
||||||
tree.opensfm_reconstruction))
|
tree.opensfm_reconstruction))
|
||||||
|
|
||||||
# check if reconstruction was exported to pmvs before
|
|
||||||
if not io.file_exists(tree.pmvs_visdat) or rerun_cell:
|
|
||||||
# run PMVS converter
|
|
||||||
system.run(
|
|
||||||
'PYTHONPATH={} {}/bin/export_pmvs {} --output {}'.format(
|
|
||||||
context.pyopencv_path, context.opensfm_path, tree.opensfm,
|
|
||||||
tree.pmvs))
|
|
||||||
else:
|
|
||||||
log.ODM_WARNING('Found a valid CMVS file in: {}'.format(
|
|
||||||
tree.pmvs_visdat))
|
|
||||||
|
|
||||||
log.ODM_INFO('Running OMD Slam Cell - Finished')
|
log.ODM_INFO('Running OMD Slam Cell - Finished')
|
||||||
return ecto.OK if args.end_with != 'odm_slam' else ecto.QUIT
|
return ecto.OK if args.end_with != 'odm_slam' else ecto.QUIT
|
||||||
|
|
|
@ -1,84 +0,0 @@
|
||||||
import ecto
|
|
||||||
|
|
||||||
from opendm import io
|
|
||||||
from opendm import log
|
|
||||||
from opendm import system
|
|
||||||
from opendm import context
|
|
||||||
|
|
||||||
|
|
||||||
class ODMPmvsCell(ecto.Cell):
|
|
||||||
def declare_params(self, params):
|
|
||||||
params.declare("level", 'The level in the image pyramid that is used '
|
|
||||||
'for the computation', 1)
|
|
||||||
params.declare("csize", 'Cell size controls the density of reconstructions', 2)
|
|
||||||
params.declare("thresh", 'A patch reconstruction is accepted as a success '
|
|
||||||
'and kept, if its associcated photometric consistency '
|
|
||||||
'measure is above this threshold.', 0.7)
|
|
||||||
params.declare("wsize", 'pmvs samples wsize x wsize pixel colors from '
|
|
||||||
'each image to compute photometric consistency '
|
|
||||||
'score. For example, when wsize=7, 7x7=49 pixel '
|
|
||||||
'colors are sampled in each image. Increasing the '
|
|
||||||
'value leads to more stable reconstructions, but '
|
|
||||||
'the program becomes slower.', 7)
|
|
||||||
params.declare("min_imgs", 'Each 3D point must be visible in at least '
|
|
||||||
'minImageNum images for being reconstructed. 3 is '
|
|
||||||
'suggested in general.', 3)
|
|
||||||
params.declare("cores", 'The maximum number of cores to use in dense '
|
|
||||||
' reconstruction.', context.num_cores)
|
|
||||||
|
|
||||||
def declare_io(self, params, inputs, outputs):
|
|
||||||
inputs.declare("tree", "Struct with paths", [])
|
|
||||||
inputs.declare("args", "The application arguments.", {})
|
|
||||||
inputs.declare("reconstruction", "list of ODMReconstructions", [])
|
|
||||||
outputs.declare("reconstruction", "list of ODMReconstructions", [])
|
|
||||||
|
|
||||||
def process(self, inputs, outputs):
|
|
||||||
|
|
||||||
# Benchmarking
|
|
||||||
start_time = system.now_raw()
|
|
||||||
|
|
||||||
log.ODM_INFO('Running OMD PMVS Cell')
|
|
||||||
|
|
||||||
# get inputs
|
|
||||||
args = self.inputs.args
|
|
||||||
tree = self.inputs.tree
|
|
||||||
|
|
||||||
# check if we rerun cell or not
|
|
||||||
rerun_cell = (args.rerun is not None and
|
|
||||||
args.rerun == 'pmvs') or \
|
|
||||||
(args.rerun_all) or \
|
|
||||||
(args.rerun_from is not None and
|
|
||||||
'pmvs' in args.rerun_from)
|
|
||||||
|
|
||||||
if not io.file_exists(tree.pmvs_model) or rerun_cell:
|
|
||||||
log.ODM_DEBUG('Creating dense pointcloud in: %s' % tree.pmvs_model)
|
|
||||||
|
|
||||||
kwargs = {
|
|
||||||
'bin': context.cmvs_opts_path,
|
|
||||||
'prefix': tree.pmvs_rec_path,
|
|
||||||
'level': self.params.level,
|
|
||||||
'csize': self.params.csize,
|
|
||||||
'thresh': self.params.thresh,
|
|
||||||
'wsize': self.params.wsize,
|
|
||||||
'min_imgs': self.params.min_imgs,
|
|
||||||
'cores': self.params.cores
|
|
||||||
}
|
|
||||||
|
|
||||||
# generate pmvs2 options
|
|
||||||
system.run('{bin} {prefix}/ {level} {csize} {thresh} {wsize} '
|
|
||||||
'{min_imgs} {cores}'.format(**kwargs))
|
|
||||||
|
|
||||||
# run pmvs2
|
|
||||||
system.run('%s %s/ option-0000' %
|
|
||||||
(context.pmvs2_path, tree.pmvs_rec_path))
|
|
||||||
|
|
||||||
else:
|
|
||||||
log.ODM_WARNING('Found a valid PMVS file in %s' % tree.pmvs_model)
|
|
||||||
|
|
||||||
outputs.reconstruction = inputs.reconstruction
|
|
||||||
|
|
||||||
if args.time:
|
|
||||||
system.benchmark(start_time, tree.benchmarking, 'PMVS')
|
|
||||||
|
|
||||||
log.ODM_INFO('Running ODM PMVS Cell - Finished')
|
|
||||||
return ecto.OK if args.end_with != 'pmvs' else ecto.QUIT
|
|
|
@ -1,144 +0,0 @@
|
||||||
import os
|
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
from opendm import log
|
|
||||||
|
|
||||||
# Go from QR-factorizatoin to corresponding RQ-factorization.
|
|
||||||
def rq(A):
|
|
||||||
Q,R = np.linalg.qr(np.flipud(A).T)
|
|
||||||
R = np.flipud(R.T)
|
|
||||||
Q = Q.T
|
|
||||||
return R[:,::-1],Q[::-1,:]
|
|
||||||
|
|
||||||
# Create a unit quaternion from rotation matrix.
|
|
||||||
def rot2quat(R):
|
|
||||||
|
|
||||||
# Float epsilon (use square root to be well with the stable region).
|
|
||||||
eps = np.sqrt(np.finfo(float).eps)
|
|
||||||
|
|
||||||
# If the determinant is not 1, it's not a rotation matrix
|
|
||||||
if np.abs(np.linalg.det(R) - 1.0) > eps:
|
|
||||||
log.ODM_ERROR('Matrix passed to rot2quat was not a rotation matrix, det != 1.0')
|
|
||||||
|
|
||||||
tr = np.trace(R)
|
|
||||||
|
|
||||||
quat = np.zeros((1,4))
|
|
||||||
|
|
||||||
# Is trace big enough be computationally stable?
|
|
||||||
if tr > eps:
|
|
||||||
S = 0.5 / np.sqrt(tr + 1.0)
|
|
||||||
quat[0,0] = 0.25 / S
|
|
||||||
quat[0,1] = (R[2,1] - R[1,2]) * S
|
|
||||||
quat[0,2] = (R[0,2] - R[2,0]) * S
|
|
||||||
quat[0,3] = (R[1,0] - R[0,1]) * S
|
|
||||||
else: # It's not, use the largest diagonal.
|
|
||||||
if R[0,0] > R[1,1] and R[0,0] > R[2,2]:
|
|
||||||
S = np.sqrt(1.0 + R[0,0] - R[1,1] - R[2,2]) * 2.0
|
|
||||||
quat[0,0] = (R[2,1] - R[1,2]) / S
|
|
||||||
quat[0,1] = 0.25 * S
|
|
||||||
quat[0,2] = (R[0,1] + R[1,0]) / S
|
|
||||||
quat[0,3] = (R[0,2] + R[2,0]) / S
|
|
||||||
elif R[1,1] > R[2,2]:
|
|
||||||
S = np.sqrt(1.0 - R[0,0] + R[1,1] - R[2,2]) * 2.0
|
|
||||||
quat[0,0] = (R[0,2] - R[2,0]) / S
|
|
||||||
quat[0,1] = (R[0,1] + R[1,0]) / S
|
|
||||||
quat[0,2] = 0.25 * S
|
|
||||||
quat[0,3] = (R[1,2] + R[2,1]) / S
|
|
||||||
else:
|
|
||||||
S = np.sqrt(1.0 - R[0,0] - R[1,1] + R[2,2]) * 2.0
|
|
||||||
quat[0,0] = (R[1,0] - R[0,1]) / S
|
|
||||||
quat[0,1] = (R[0,2] + R[2,0]) / S
|
|
||||||
quat[0,2] = (R[1,2] + R[2,1]) / S
|
|
||||||
quat[0,3] = 0.25 * S
|
|
||||||
|
|
||||||
return quat
|
|
||||||
|
|
||||||
# Decompose a projection matrix into parts
|
|
||||||
# (Intrinsic projection, Rotation, Camera position)
|
|
||||||
def decomposeProjection(projectionMatrix):
|
|
||||||
|
|
||||||
# Check input:
|
|
||||||
if projectionMatrix.shape != (3,4):
|
|
||||||
log.ODM_ERROR('Unable to decompose projection matrix, shape != (3,4)')
|
|
||||||
|
|
||||||
RQ = rq(projectionMatrix[:,:3])
|
|
||||||
|
|
||||||
# Fix sign, since we know K is upper triangular and has a positive diagonal.
|
|
||||||
signMat = np.diag(np.diag(np.sign(RQ[0])))
|
|
||||||
K = signMat*RQ[0]
|
|
||||||
R = signMat*RQ[1]
|
|
||||||
|
|
||||||
# Calculate camera position from translation vector.
|
|
||||||
t = np.linalg.inv(-1.0*projectionMatrix[:,:3])*projectionMatrix[:,3]
|
|
||||||
|
|
||||||
return K, R, t
|
|
||||||
|
|
||||||
# Parses pvms contour file.
|
|
||||||
def parseContourFile(filePath):
|
|
||||||
|
|
||||||
with open(filePath, 'r') as contourFile:
|
|
||||||
if (contourFile.readline().strip() != "CONTOUR"):
|
|
||||||
return np.array([])
|
|
||||||
else:
|
|
||||||
pMatData = np.loadtxt(contourFile, float, '#', None, None, 0)
|
|
||||||
if pMatData.shape == (3,4):
|
|
||||||
return pMatData
|
|
||||||
return np.array([])
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Creates a .nvm camera file in the pmvs folder.
|
|
||||||
def run(pmvsFolder, outputFile):
|
|
||||||
|
|
||||||
projectionFolder = pmvsFolder + "/txt"
|
|
||||||
imageFolder = pmvsFolder + "/visualize"
|
|
||||||
|
|
||||||
pMatrices = []
|
|
||||||
imageFileNames = []
|
|
||||||
|
|
||||||
# for all files in the visualize folder:
|
|
||||||
for imageFileName in os.listdir(imageFolder):
|
|
||||||
fileNameNoExt = os.path.splitext(imageFileName)[0]
|
|
||||||
|
|
||||||
# look for corresponding projection matrix txt file
|
|
||||||
projectionFilePath = os.path.join(projectionFolder, fileNameNoExt)
|
|
||||||
projectionFilePath += ".txt"
|
|
||||||
if os.path.isfile(projectionFilePath):
|
|
||||||
pMatData = parseContourFile(projectionFilePath)
|
|
||||||
if pMatData.size == 0:
|
|
||||||
log.ODM_WARNING('Unable to parse contour file, skipping: %s'
|
|
||||||
% projectionFilePath)
|
|
||||||
else:
|
|
||||||
pMatrices.append(np.matrix(pMatData))
|
|
||||||
imageFileNames.append(imageFileName)
|
|
||||||
|
|
||||||
|
|
||||||
# Decompose projection matrices
|
|
||||||
focals = []
|
|
||||||
rotations = []
|
|
||||||
translations = []
|
|
||||||
for projection in pMatrices:
|
|
||||||
KRt = decomposeProjection(projection)
|
|
||||||
focals.append(KRt[0][0,0])
|
|
||||||
rotations.append(rot2quat(KRt[1]))
|
|
||||||
translations.append(KRt[2])
|
|
||||||
|
|
||||||
# Create .nvm file
|
|
||||||
with open (outputFile, 'w') as nvmFile:
|
|
||||||
nvmFile.write("NVM_V3\n\n")
|
|
||||||
nvmFile.write('%d' % len(rotations) + "\n")
|
|
||||||
|
|
||||||
for idx, imageFileName in enumerate(imageFileNames):
|
|
||||||
nvmFile.write(os.path.join("visualize", imageFileName))
|
|
||||||
nvmFile.write(" " + '%f' % focals[idx])
|
|
||||||
nvmFile.write(" " + '%f' % rotations[idx][0,0] +
|
|
||||||
" " + '%f' % rotations[idx][0,1] +
|
|
||||||
" " + '%f' % rotations[idx][0,2] +
|
|
||||||
" " + '%f' % rotations[idx][0,3])
|
|
||||||
nvmFile.write(" " + '%f' % translations[idx][0] +
|
|
||||||
" " + '%f' % translations[idx][1] +
|
|
||||||
" " + '%f' % translations[idx][2])
|
|
||||||
nvmFile.write(" 0 0\n")
|
|
||||||
nvmFile.write("0\n\n")
|
|
||||||
nvmFile.write("0\n\n")
|
|
||||||
nvmFile.write("0")
|
|
|
@ -42,7 +42,6 @@ class ODMOpenSfMCell(ecto.Cell):
|
||||||
|
|
||||||
# create working directories
|
# create working directories
|
||||||
system.mkdir_p(tree.opensfm)
|
system.mkdir_p(tree.opensfm)
|
||||||
system.mkdir_p(tree.pmvs)
|
|
||||||
|
|
||||||
# check if we rerun cell or not
|
# check if we rerun cell or not
|
||||||
rerun_cell = (args.rerun is not None and
|
rerun_cell = (args.rerun is not None and
|
||||||
|
@ -169,15 +168,6 @@ class ODMOpenSfMCell(ecto.Cell):
|
||||||
log.ODM_WARNING('Found a valid Bundler file in: %s' %
|
log.ODM_WARNING('Found a valid Bundler file in: %s' %
|
||||||
tree.opensfm_reconstruction)
|
tree.opensfm_reconstruction)
|
||||||
|
|
||||||
# if args.use_pmvs:
|
|
||||||
# # check if reconstruction was exported to pmvs before
|
|
||||||
# if not io.file_exists(tree.pmvs_visdat) or rerun_cell:
|
|
||||||
# # run PMVS converter
|
|
||||||
# system.run('PYTHONPATH=%s %s/bin/export_pmvs %s --output %s' %
|
|
||||||
# (context.pyopencv_path, context.opensfm_path, tree.opensfm, tree.pmvs))
|
|
||||||
# else:
|
|
||||||
# log.ODM_WARNING('Found a valid CMVS file in: %s' % tree.pmvs_visdat)
|
|
||||||
|
|
||||||
if reconstruction.georef:
|
if reconstruction.georef:
|
||||||
system.run('PYTHONPATH=%s %s/bin/opensfm export_geocoords %s --transformation --proj \'%s\'' %
|
system.run('PYTHONPATH=%s %s/bin/opensfm export_geocoords %s --transformation --proj \'%s\'' %
|
||||||
(context.pyopencv_path, context.opensfm_path, tree.opensfm, reconstruction.georef.projection.srs))
|
(context.pyopencv_path, context.opensfm_path, tree.opensfm, reconstruction.georef.projection.srs))
|
||||||
|
|
|
@ -66,7 +66,7 @@ class ODMSmvsCell(ecto.Cell):
|
||||||
"-a%s" % self.params.alpha,
|
"-a%s" % self.params.alpha,
|
||||||
"-s%s" % self.params.scale,
|
"-s%s" % self.params.scale,
|
||||||
"-o%s" % self.params.output_scale,
|
"-o%s" % self.params.output_scale,
|
||||||
"--debug-lvl=%s" % '1' if self.params.verbose else '0',
|
"--debug-lvl=%s" % ('1' if self.params.verbose else '0'),
|
||||||
"%s" % '-S' if self.params.shading else '',
|
"%s" % '-S' if self.params.shading else '',
|
||||||
"%s" % '-g' if self.params.gamma_srgb and self.params.shading else '',
|
"%s" % '-g' if self.params.gamma_srgb and self.params.shading else '',
|
||||||
"--force" if rerun_cell else ''
|
"--force" if rerun_cell else ''
|
||||||
|
|
Ładowanie…
Reference in New Issue