Fix merge conflicts

pull/351/head
Dakota Benjamin 2016-08-01 14:55:52 +00:00
commit 66f3fe3057
26 zmienionych plików z 1410 dodań i 607 usunięć

Wyświetl plik

@ -3,4 +3,12 @@ tests/test_data
SuperBuild/build
SuperBuild/download
SuperBuild/install
SuperBuild/src
SuperBuild/src
build
opensfm
pmvs
odm_orthophoto
odm_texturing
odm_meshing
odm_georeferencing
images_resize

Wyświetl plik

@ -1,80 +1,32 @@
FROM ubuntu:14.04
MAINTAINER Danilo Bargen <mail@dbrgn.ch>
# Env variables
ENV DEBIAN_FRONTEND noninteractive
# Install dependencies
RUN apt-get update \
&& sudo apt-get remove libdc1394-22-dev \
&& apt-get install -y --install-recommends \
build-essential \
cmake \
git \
python-pip \
libgdal-dev \
libgeotiff-dev \
pkg-config \
libgtk2.0-dev \
libavcodec-dev \
libavformat-dev \
libswscale-dev \
python-dev \
python-numpy \
libtbb2 \
libtbb-dev \
libjpeg-dev \
libpng-dev \
libtiff-dev \
libjasper-dev \
libflann-dev \
libproj-dev \
libxext-dev \
liblapack-dev \
libeigen3-dev \
libvtk5-dev \
python-networkx \
libgoogle-glog-dev \
libsuitesparse-dev \
libboost-filesystem-dev \
libboost-iostreams-dev \
libboost-regex-dev \
libboost-python-dev \
libboost-date-time-dev \
libboost-thread-dev \
python-empy \
python-nose \
python-pyside \
python-pyexiv2 \
python-scipy \
jhead \
liblas-bin \
&& apt-get autoremove \
&& apt-get clean
# Add users
RUN useradd -m -U odm
#Pull in previously built packages image with lots of libraries.
FROM packages
# Prepare directories
RUN mkdir /code
WORKDIR /code
# Add repository files
ADD . /code/
# Copy repository files
COPY ccd_defs_check.py /code/ccd_defs_check.py
COPY CMakeLists.txt /code/CMakeLists.txt
COPY configure.sh /code/configure.sh
COPY /.git/ /code/.git/
COPY .gitignore /code/.gitignore
COPY .gitmodules /code/.gitmodules
COPY /modules/ /code/modules/
COPY /opendm/ /code/opendm/
COPY /patched_files/ /code/patched_files/
COPY run.py /code/run.py
COPY /scripts/ /code/scripts/
COPY /SuperBuild/cmake/ /code/SuperBuild/cmake/
COPY /SuperBuild/CMakeLists.txt /code/SuperBuild/CMakeLists.txt
COPY /tests/ /code/tests/
# Update submodules
RUN git submodule init && git submodule update
# Build OpenDroneMap
RUN bash ./configure.sh && \
mkdir build && cd build && cmake .. && make && cd .. && \
chown -R odm:odm /code
USER odm
ENV PYTHONPATH=${PYTHONPATH}:/code/SuperBuild/install/lib/python2.7/dist-packages:/code/SuperBuild/src/opensfm \
LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/code/SuperBuild/install/lib
#Compile code in SuperBuild and root directories
RUN cd SuperBuild && mkdir build && cd build && cmake .. && make -j$(nproc) \
&& cd ../.. && mkdir build && cd build && cmake .. && make -j$(nproc)
# Entry point
VOLUME ["/images"]
# WORKDIR /images
ENTRYPOINT ["python", "/code/run.py", "--project-path", "/images"]
ENTRYPOINT ["python", "/code/run.py", "--project-path", "/code/"]

105
README.md
Wyświetl plik

@ -2,8 +2,7 @@
![](https://raw.githubusercontent.com/OpenDroneMap/OpenDroneMap/master/img/odm_image.png)
What is it?
===========
## What is it?
OpenDroneMap is an open source toolkit for processing aerial drone imagery. Typical drones use simple point-and-shoot cameras, so the images from drones, while from a different perspective, are similar to any pictures taken from point-and-shoot cameras, i.e. non-metric imagery. OpenDroneMap turns those simple images into three dimensional geographic data that can be used in combination with other geographic datasets.
@ -19,16 +18,15 @@ In a word, OpenDroneMap is a toolchain for processing raw civilian UAS imagery t
6. Digital Elevation Models
7. etc.
So far, it does Point Clouds, Digital Surface Models, Textured Digital Surface Models, and Orthorectified Imagery.
So far, it does Point Clouds, Digital Surface Models, Textured Digital Surface Models, and Orthorectified Imagery. Open Drone Map now includes state-of-the-art 3D reconstruction work by Michael Waechter, Nils Moehrle, and Michael Goesele. See their publication at http://www.gcc.tu-darmstadt.de/media/gcc/papers/Waechter-2014-LTB.pdf.
Users' mailing list: http://lists.osgeo.org/cgi-bin/mailman/listinfo/opendronemap-users
Developer's mailing list: http://lists.osgeo.org/cgi-bin/mailman/listinfo/opendronemap-dev
Developers' mailing list: http://lists.osgeo.org/cgi-bin/mailman/listinfo/opendronemap-dev
Overview video: https://www.youtube.com/watch?v=0UctfoeNB_Y
Developers
=================
## Developers
Help improve our software!
@ -37,40 +35,44 @@ Help improve our software!
1. Try to keep commits clean and simple
2. Submit a pull request with detailed changes and test results
Steps to get OpenDroneMap running:
==================================
## Build and Run OpenDroneMap in Ubuntu:
(Requires Ubuntu 14.04 or later, see https://github.com/OpenDroneMap/odm_vagrant for running on Windows in a VM)
Support for Ubuntu 12.04 is currently BROKEN with the addition of OpenSfM and Ceres-Solver. We are working hard to get it working again in the future.
Support for Ubuntu 12.04 is currently BROKEN with the addition of OpenSfM and Ceres-Solver. We are working hard to get it working again in the future.
#### Building OpenDroneMap using git
### Build OpenDroneMap
Start with the following:
cd path/to/odm/dir
git clone https://github.com/OpenDroneMap/OpenDroneMap.git .
export PYTHONPATH=$PYTHONPATH:`pwd`/SuperBuild/install/lib/python2.7/dist-packages:`pwd`/SuperBuild/src/opensfm
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:`pwd`/SuperBuild/install/lib
git clone https://github.com/OpenDroneMap/OpenDroneMap.git
Next, open the ~/.bashrc file on your machine and add the following 3 lines at the end. The file can be opened with ```gedit ~/.bashrc```. Be sure to replace the "/your/path/" with the correct path to the location where you cloned OpenDroneMap:
export PYTHONPATH=$PYTHONPATH:/your/path/OpenDroneMap/SuperBuild/install/lib/python2.7/dist-packages
export PYTHONPATH=$PYTHONPATH:/your/path/OpenDroneMap/SuperBuild/src/opensfm
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/your/path/OpenDroneMap/SuperBuild/install/lib
Now, enter the OpenDroneMap directory and compile all of the code by executing a single configuration script:
cd OpenDroneMap
bash configure.sh
mkdir build && cd build && cmake .. && make && cd ..
For Ubuntu 15.10 users, this will help you get running:
For Ubuntu 15.10 users, this will help you get running:
sudo apt-get install python-xmltodict
sudo ln -s /usr/lib/x86_64-linux-gnu/libproj.so.9 /usr/lib/libproj.so
#### Running OpenDroneMap
### Run OpenDroneMap
First you need a set of images, which may or may not be georeferenced. There are two ways OpenDroneMap can understand geographic coordinates. First, the images can be geotagged in their EXIF data. This is the default. Alternatively, you can create a GCP file, [a process detailed here](https://github.com/OpenDroneMap/OpenDroneMap/wiki/2.-Running-OpenDroneMap#running-odm-with-ground-control)
Create a project folder and places your images in an "images" directory:
|-- /path/to/project/
|-- images/
|-- img-1234.jpg
|-- ...
Example data can be cloned from https://github.com/OpenDroneMap/odm_data
Then run:
@ -79,7 +81,9 @@ Then run:
There are many options for tuning your project. See the [wiki](https://github.com/OpenDroneMap/OpenDroneMap/wiki/3.-Run-Time-Parameters) or run `python run.py -h`
When the process finishes, the results will be organized as follows
### View Results
When the process finishes, the results will be organized as follows:
|-- images/
|-- img-1234.jpg
@ -112,44 +116,65 @@ When the process finishes, the results will be organized as follows
|-- odm_orthophoto_log.txt # Log file
|-- gdal_translate_log.txt # Log for georeferencing the png file
##### Viewing your results
Any file ending in .obj or .ply can be opened and viewed in [MeshLab](http://meshlab.sourceforge.net/) or similar software. That includes `pmvs/recon0/models/option-000.ply`, `odm_meshing/odm_mesh.ply`, `odm_texturing/odm_textured_model[_geo].obj`, or `odm_georeferencing/odm_georeferenced_model.ply`. Below is an example textured mesh:
![](https://raw.githubusercontent.com/OpenDroneMap/OpenDroneMap/master/img/tol_text.png)
![](https://raw.githubusercontent.com/alexhagiopol/OpenDroneMap/feature-better-docker/toledo_dataset_example_mesh.jpg)
You can also view the orthophoto GeoTIFF in QGIS or other mapping software:
![](https://raw.githubusercontent.com/OpenDroneMap/OpenDroneMap/master/img/bellus_map.png)
#### Using Docker
## Build and Run Using Docker
You can build and run OpenDroneMap in a Docker container:
(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](docs.docker.com))
export IMAGES=/absolute/path/to/your/project
docker build -t opendronemap:latest .
docker run -v $IMAGES:/images opendronemap:latest
OpenDroneMap is Dockerized, meaning you can use containerization to build and run it without tampering with the configuration of libraries and packages already
installed on your machine. Docker software is free to install and use in this context. If you don't have it installed,
see the [Docker Ubuntu installation tutorial] (https://docs.docker.com/engine/installation/linux/ubuntulinux/) and follow the
instructions up until "Create a Docker group" inclusive. Once Docker is installed, an OpenDroneMap Docker image can be created
like so:
Replace /absolute/path/to/your/images with an absolute path to the directory containing your project (where the images are)
To pass in custom parameters to the `run.py` script, simply pass it as arguments to the `docker run` command.
git clone https://github.com/OpenDroneMap/OpenDroneMap.git
cd OpenDroneMap
docker build -t packages -f packages.Dockerfile .
docker build -t odm_image .
docker run -it --user root\
-v $(pwd)/images:/code/images\
-v $(pwd)/odm_orthophoto:/code/odm_orthophoto\
-v $(pwd)/odm_texturing:/code/odm_texturing\
--rm odm_image
---
Using this method, the containerized ODM will process the images in the OpenDroneMap/images directory and output results
to the OpenDroneMao/odm_orthophoto and OpenDroneMap/odm_texturing directories as described in the **Viewing 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
established above. For example, if you're interested in the dense cloud results generated by PMVS and in the orthophoto,
simply use the following `docker run` command after building the image:
docker run -it --user root\
-v $(pwd)/images:/code/images\
-v $(pwd)/pmvs:/code/pmvs\
-v $(pwd)/odm_orthophoto:/code/odm_orthophoto\
--rm odm_image
To pass in custom parameters to the run.py script, simply pass it as arguments to the `docker run` command.
## Examples
Here are some other videos, which may be outdated:
- https://www.youtube.com/watch?v=7ZTufQkODLs (2015-01-30)
- https://www.youtube.com/watch?v=m0i4GQdfl8A (2015-03-15)
Now that texturing is in the code base, you can access the full textured meshes using MeshLab. Open MeshLab, choose `File:Import Mesh` and choose your textured mesh from a location similar to the following: `reconstruction-with-image-size-1200-results\odm_texturing\odm_textured_model.obj`
Now that texturing is in the code base, you can access the full textured meshes using MeshLab.
Open MeshLab, choose `File:Import Mesh` and choose your textured mesh from a location similar to the following:
`reconstruction-with-image-size-1200-results\odm_texturing\odm_textured_model.obj`. Long term, the aim is for
the toolchain to also be able to optionally push to a variety of online data repositories, pushing hi-resolution
aerials to [OpenAerialMap](https://openaerialmap.org/), point clouds to [OpenTopography](http://opentopography.org/),
and pushing digital elevation models to an emerging global repository (yet to be named...). That leaves only
digital surface model meshes and UV textured meshes with no global repository home.
---
Long term, the aim is for the toolchain to also be able to optionally push to a variety of online data repositories, pushing hi-resolution aerials to [OpenAerialMap](http://opentopography.org/), point clouds to [OpenTopography](http://opentopography.org/), and pushing digital elevation models to an emerging global repository (yet to be named...). That leaves only digital surface model meshes and UV textured meshes with no global repository home.
---
Documentation:
==============
## Documentation:
For documentation, please take a look at our [wiki](https://github.com/OpenDroneMap/OpenDroneMap/wiki).

Wyświetl plik

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 2.8)
cmake_minimum_required(VERSION 3.1)
project(ODM-SuperBuild)
@ -101,7 +101,9 @@ set(custom_libs OpenGV
CMVS
Catkin
Ecto
PDAL)
PDAL
MvsTexturing
)
foreach(lib ${custom_libs})
SETUP_EXTERNAL_PROJECT_CUSTOM(${lib})

Wyświetl plik

@ -0,0 +1,29 @@
set(_proj_name mvstexuring)
set(_SB_BINARY_DIR "${SB_BINARY_DIR}/${_proj_name}")
ExternalProject_Add(${_proj_name}
DEPENDS
PREFIX ${_SB_BINARY_DIR}
TMP_DIR ${_SB_BINARY_DIR}/tmp
STAMP_DIR ${_SB_BINARY_DIR}/stamp
#--Download step--------------
DOWNLOAD_DIR ${SB_DOWNLOAD_DIR}
URL https://github.com/nmoehrle/mvs-texturing/archive/dab68acaa693275c183c254a958130ee6d29c3e4.zip
URL_MD5 0b0466f5d1046699594ce7fc77bdad02
#--Update/Patch step----------
UPDATE_COMMAND ""
#--Configure step-------------
SOURCE_DIR ${SB_SOURCE_DIR}/${_proj_name}
CMAKE_ARGS
-DRESEARCH=OFF
-DCMAKE_BUILD_TYPE:STRING=Release
-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
)

0
ccd_defs_check.py 100755 → 100644
Wyświetl plik

104
configure.sh 100644 → 100755
Wyświetl plik

@ -1,43 +1,27 @@
#!/bin/bash
# Check OS
if [ ! $(command -v apt-get) ]; then
echo -e "\e[1;31mERROR: Not a Debian-based linux system.
Impossible to install OpenCV with this script\e[0;39m"
exit 1
fi
## Before installing
echo -e "\e[1;34mUpdating the system\e[0;39m"
echo "Updating the system"
sudo apt-get update
END_CMD1=$?
# sudo apt-get upgrade -y
# END_CMD2=$?
if [ $END_CMD1 -ne 0 ]
then
echo -e "\e[1;31mERROR: \e[39mWhen Updating the system\e[0m"
exit 1
fi
## Install Required Requisites
echo -e "\e[1;34mInstalling Required Requisites\e[0;39m"
sudo apt-get install build-essential \
cmake \
echo "Installing Required Requisites"
sudo apt-get install -y -qq build-essential \
git \
cmake \
python-pip \
libgdal-dev \
gdal-bin \
libgeotiff-dev \
pkg-config -y -qq
if [ $? -ne 0 ]
then
echo -e "\e[1;31mERROR: \e[39mWhen Installing Required Requisites\e[0m"
exit 1
fi
pkg-config
## Installing Optional Requisites
echo -e "\e[1;34mInstalling OpenCV Dependencies\e[0;39m"
sudo apt-get install libgtk2.0-dev \
echo "Getting CMake 3.1 for MVS-Texturing"
sudo apt-get install -y software-properties-common python-software-properties
sudo add-apt-repository -y ppa:george-edison55/cmake-3.x
sudo apt-get update -y
sudo apt-get install -y --only-upgrade cmake
echo "Installing OpenCV Dependencies"
sudo apt-get install -y -qq libgtk2.0-dev \
libavcodec-dev \
libavformat-dev \
libswscale-dev \
@ -54,20 +38,14 @@ sudo apt-get install libgtk2.0-dev \
libxext-dev \
liblapack-dev \
libeigen3-dev \
libvtk5-dev -y -qq
if [ $? -ne 0 ]
then
echo -e "\e[1;31mERROR: \e[39mError when Installing Dependencies Requisites\e[0m"
exit 1
fi
libvtk5-dev
## Remove libdc1394-22-dev due to python opencv issue
echo -e "\e[1;34mRemoving libdc1394-22-dev\e[0;39m"
echo "Removing libdc1394-22-dev due to python opencv issue"
sudo apt-get remove libdc1394-22-dev
## Installing OpenSfM Requisites
echo -e "\e[1;34mInstalling OpenSfM Dependencies\e[0;39m"
sudo apt-get install python-networkx \
echo "Installing OpenSfM Dependencies"
sudo apt-get install -y -qq python-networkx \
libgoogle-glog-dev \
libsuitesparse-dev \
libboost-filesystem-dev \
@ -75,51 +53,33 @@ sudo apt-get install python-networkx \
libboost-regex-dev \
libboost-python-dev \
libboost-date-time-dev \
libboost-thread-dev -y -qq
libboost-thread-dev
sudo pip install -U PyYAML \
exifread \
gpxpy \
xmltodict
if [ $? -ne 0 ]
then
echo -e "\e[1;31mERROR: \e[39mError when Installing OpenSfM Dependencies\e[0m"
exit 1
fi
## Installing Ecto Requisites
echo -e "\e[1;34mInstalling Ecto Dependencies\e[0;39m"
echo "Installing Ecto Dependencies"
sudo pip install -U catkin-pkg
sudo apt-get install python-empy \
sudo apt-get install -y -qq python-empy \
python-nose \
python-pyside -y -qq
if [ $? -ne 0 ]
then
echo -e "\e[1;31mERROR: \e[39mError when Installing Ecto Dependencies\e[0m"
exit 1
fi
python-pyside
## Installing OpenDroneMap Requisites
echo -e "\e[1;34mInstalling OpenDroneMap Dependencies\e[0;39m"
sudo apt-get install python-pyexiv2 \
echo "Installing OpenDroneMap Dependencies"
sudo apt-get install -y -qq python-pyexiv2 \
python-scipy \
jhead \
liblas-bin -y -qq
if [ $? -ne 0 ]
then
echo -e "\e[1;31mERROR: \e[39mError when Installing OpenDroneMap Dependencies\e[0m"
exit 1
fi
liblas-bin
## Get sys vars
NUM_CORES=`grep -c processor /proc/cpuinfo`
## Add SuperBuild path to the python path
export PYTHONPATH=$PYTHONPATH:`pwd`/SuperBuild/install/lib/python2.7/dist-packages:`pwd`/SuperBuild/src/opensfm
## Compile SuperBuild
echo "Compiling SuperBuild"
cd SuperBuild
mkdir -p build && cd build
cmake .. && make -j${NUM_CORES}
cmake .. && make -j$(nproc)
echo -e "\e[1;34mScript finished\e[0;39m"
echo "Compiling build"
cd ../..
mkdir -p build && cd build
cmake .. && make -j$(nproc)
echo "Configuration Finished"

0
hooks/pre-commit 100755 → 100644
Wyświetl plik

Wyświetl plik

@ -24,3 +24,4 @@ Licensing for portions of OpenDroneMap are as follows:
* vtk5 - BSD - http://www.vtk.org/VTK/project/license.html
* libext - https://github.com/OpenDroneMap/OpenDroneMap/blob/gh-pages/licenses/libext_copyright.txt
* libx11 - https://github.com/OpenDroneMap/OpenDroneMap/blob/gh-pages/licenses/libx11_copyright.txt
* MVS Texturing - BSD - https://github.com/nmoehrle/mvs-texturing/blob/master/LICENSE.txt

Wyświetl plik

@ -1,203 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by Qt Creator 2.4.1, 2015-02-03T10:36:15. -->
<qtcreator>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
<value type="int">0</value>
</data>
<data>
<variable>ProjectExplorer.Project.EditorSettings</variable>
<valuemap type="QVariantMap">
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
<value type="QString" key="language">Cpp</value>
<valuemap type="QVariantMap" key="value">
<value type="QString" key="CurrentPreferences">CppGlobal</value>
</valuemap>
</valuemap>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
<value type="QString" key="language">QmlJS</value>
<valuemap type="QVariantMap" key="value">
<value type="QString" key="CurrentPreferences">QmlJSGlobal</value>
</valuemap>
</valuemap>
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
<value type="QByteArray" key="EditorConfiguration.Codec">System</value>
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
<value type="int" key="EditorConfiguration.IndentSize">4</value>
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
<value type="int" key="EditorConfiguration.TabSize">8</value>
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.PluginSettings</variable>
<valuemap type="QVariantMap"/>
</data>
<data>
<variable>ProjectExplorer.Project.Target.0</variable>
<valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.DefaultCMakeTarget</value>
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
<value type="QString" key="CMakeProjectManager.CMakeBuildConfiguration.BuildDirectory">/home/spotscale/odm/OpenDroneMap-texturing_orthophoto_spotscale_additions/odm_georef-build</value>
<value type="QString" key="CMakeProjectManager.CMakeBuildConfiguration.ToolChain">ProjectExplorer.ToolChain.Gcc:/usr/bin/g++.x86-linux-generic-elf-32bit./usr/bin/gdb</value>
<value type="QString" key="ProjectExplorer.BuildCOnfiguration.ToolChain">ProjectExplorer.ToolChain.Gcc:/usr/bin/g++.x86-linux-generic-elf-32bit./usr/bin/gdb</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.AdditionalArguments"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets"/>
<value type="bool" key="CMakeProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.AdditionalArguments">clean</value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets"/>
<value type="bool" key="CMakeProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">all</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">No deployment</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
<value type="bool" key="Analyzer.Project.UseGlobal">true</value>
<value type="bool" key="Analyzer.Project.UseGlobal">true</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
<value type="int">0</value>
<value type="int">1</value>
<value type="int">2</value>
<value type="int">3</value>
<value type="int">4</value>
<value type="int">5</value>
<value type="int">6</value>
<value type="int">7</value>
<value type="int">8</value>
<value type="int">9</value>
<value type="int">10</value>
<value type="int">11</value>
<value type="int">12</value>
<value type="int">13</value>
<value type="int">14</value>
</valuelist>
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
<value type="int">0</value>
<value type="int">1</value>
<value type="int">2</value>
<value type="int">3</value>
<value type="int">4</value>
<value type="int">5</value>
<value type="int">6</value>
<value type="int">7</value>
<value type="int">8</value>
<value type="int">9</value>
<value type="int">10</value>
<value type="int">11</value>
<value type="int">12</value>
<value type="int">13</value>
<value type="int">14</value>
</valuelist>
<value type="int" key="CMakeProjectManager.BaseEnvironmentBase">2</value>
<value type="QString" key="CMakeProjectManager.CMakeRunConfiguation.Title">odm_georef</value>
<value type="QString" key="CMakeProjectManager.CMakeRunConfiguration.Arguments">-verbose -bundleFile ../../../shared_folder/seneca/reconstruction-with-image-size-1200/pmvs/bundle.rd.out -inputFile ../../../shared_folder/seneca/reconstruction-with-image-size-1200-results/odm_texturing/odm_textured_model.obj -imagesListPath ../../../shared_folder/seneca/reconstruction-with-image-size-1200/pmvs/list.rd.txt -gcpFile ../../../shared_folder/seneca_georef_input/gcp_list.txt -imagesPath ../../../shared_folder/seneca/ -bundleResizedTo 1200</value>
<value type="bool" key="CMakeProjectManager.CMakeRunConfiguration.UseTerminal">false</value>
<valuelist type="QVariantList" key="CMakeProjectManager.CMakeRunConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="CMakeProjectManager.CMakeRunConfiguration.UserWorkingDirectory"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">odm_georef</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeRunConfiguration.</value>
<value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
<value type="bool" key="RunConfiguration.UseCppDebugger">true</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">false</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.TargetCount</variable>
<value type="int">1</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.EnvironmentId</variable>
<value type="QString">{785a73be-b55f-490c-9d46-e1451c235840}</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
<value type="int">10</value>
</data>
</qtcreator>

Wyświetl plik

@ -6,9 +6,6 @@
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
// Modified PCL
#include "modifiedPclFunctions.hpp"
// This
#include "Georef.hpp"
@ -753,7 +750,7 @@ void Georef::performGeoreferencingWithGCP()
log_ << "Reading mesh file " << inputObjFilename_ <<"\n";
log_ << '\n';
pcl::TextureMesh mesh;
if (pcl::io::loadOBJFile(inputObjFilename_, mesh) == -1)
if (loadObjFile(inputObjFilename_, mesh) == -1)
{
throw GeorefException("Error when reading model from:\n" + inputObjFilename_ + "\n");
}
@ -1077,7 +1074,7 @@ void Georef::createGeoreferencedModelFromExifData()
log_ << '\n';
log_ << "Reading mesh file...\n";
pcl::TextureMesh mesh;
pcl::io::loadOBJFile(inputObjFilename_, mesh);
loadObjFile(inputObjFilename_, mesh);
log_ << ".. mesh file read.\n";
// Contains the vertices of the mesh.
@ -1249,3 +1246,364 @@ void Georef::printGeorefSystem()
}
bool Georef::loadObjFile(std::string inputFile, pcl::TextureMesh &mesh)
{
int data_type;
unsigned int data_idx;
int file_version;
int offset = 0;
Eigen::Vector4f origin;
Eigen::Quaternionf orientation;
if (!readHeader(inputFile, mesh.cloud, origin, orientation, file_version, data_type, data_idx, offset))
{
throw GeorefException("Problem reading header in modelfile!\n");
}
std::ifstream fs;
fs.open (inputFile.c_str (), std::ios::binary);
if (!fs.is_open () || fs.fail ())
{
//PCL_ERROR ("[pcl::OBJReader::readHeader] Could not open file '%s'! Error : %s\n", file_name.c_str (), strerror(errno));
fs.close ();
log_<<"Could not read mesh from file ";
log_ << inputFile.c_str();
log_ <<"\n";
throw GeorefException("Problem reading mesh from file!\n");
}
// Seek at the given offset
fs.seekg (data_idx, std::ios::beg);
// Get normal_x field indices
int normal_x_field = -1;
for (std::size_t i = 0; i < mesh.cloud.fields.size (); ++i)
{
if (mesh.cloud.fields[i].name == "normal_x")
{
normal_x_field = i;
break;
}
}
std::size_t v_idx = 0;
std::size_t vn_idx = 0;
std::size_t vt_idx = 0;
std::size_t f_idx = 0;
std::string line;
std::vector<std::string> st;
std::vector<Eigen::Vector2f> coordinates;
std::vector<Eigen::Vector2f> allTexCoords;
std::map<int, int> f2vt;
try
{
while (!fs.eof ())
{
getline (fs, line);
// Ignore empty lines
if (line == "")
continue;
// Tokenize the line
std::stringstream sstream (line);
sstream.imbue (std::locale::classic ());
line = sstream.str ();
boost::trim (line);
boost::split (st, line, boost::is_any_of ("\t\r "), boost::token_compress_on);
// Ignore comments
if (st[0] == "#")
continue;
// Vertex
if (st[0] == "v")
{
try
{
for (int i = 1, f = 0; i < 4; ++i, ++f)
{
float value = boost::lexical_cast<float> (st[i]);
memcpy (&mesh.cloud.data[v_idx * mesh.cloud.point_step + mesh.cloud.fields[f].offset], &value, sizeof (float));
}
++v_idx;
}
catch (const boost::bad_lexical_cast &e)
{
log_<<"Unable to convert %s to vertex coordinates!\n";
throw GeorefException("Unable to convert %s to vertex coordinates!");
}
continue;
}
// Vertex normal
if (st[0] == "vn")
{
try
{
for (int i = 1, f = normal_x_field; i < 4; ++i, ++f)
{
float value = boost::lexical_cast<float> (st[i]);
memcpy (&mesh.cloud.data[vn_idx * mesh.cloud.point_step + mesh.cloud.fields[f].offset],
&value,
sizeof (float));
}
++vn_idx;
}
catch (const boost::bad_lexical_cast &e)
{
log_<<"Unable to convert %s to vertex normal!\n";
throw GeorefException("Unable to convert %s to vertex normal!");
}
continue;
}
// Texture coordinates
if (st[0] == "vt")
{
try
{
Eigen::Vector3f c (0, 0, 0);
for (std::size_t i = 1; i < st.size (); ++i)
c[i-1] = boost::lexical_cast<float> (st[i]);
if (c[2] == 0)
coordinates.push_back (Eigen::Vector2f (c[0], c[1]));
else
coordinates.push_back (Eigen::Vector2f (c[0]/c[2], c[1]/c[2]));
++vt_idx;
}
catch (const boost::bad_lexical_cast &e)
{
log_<<"Unable to convert %s to vertex texture coordinates!\n";
throw GeorefException("Unable to convert %s to vertex texture coordinates!");
}
continue;
}
// Material
if (st[0] == "usemtl")
{
mesh.tex_polygons.push_back (std::vector<pcl::Vertices> ());
mesh.tex_materials.push_back (pcl::TexMaterial ());
for (std::size_t i = 0; i < companions_.size (); ++i)
{
std::vector<pcl::TexMaterial>::const_iterator mat_it = companions_[i].getMaterial (st[1]);
if (mat_it != companions_[i].materials_.end ())
{
mesh.tex_materials.back () = *mat_it;
break;
}
}
// We didn't find the appropriate material so we create it here with name only.
if (mesh.tex_materials.back ().tex_name == "")
mesh.tex_materials.back ().tex_name = st[1];
mesh.tex_coordinates.push_back (coordinates);
coordinates.clear ();
continue;
}
// Face
if (st[0] == "f")
{
//We only care for vertices indices
pcl::Vertices face_v; face_v.vertices.resize (st.size () - 1);
for (std::size_t i = 1; i < st.size (); ++i)
{
int v;
sscanf (st[i].c_str (), "%d", &v);
v = (v < 0) ? v_idx + v : v - 1;
face_v.vertices[i-1] = v;
int v2, vt, vn;
sscanf (st[i].c_str (), "%d/%d/%d", &v2, &vt, &vn);
f2vt[3*(f_idx) + i-1] = vt-1;
}
mesh.tex_polygons.back ().push_back (face_v);
++f_idx;
continue;
}
}
}
catch (const char *exception)
{
fs.close ();
log_<<"Unable to read file!\n";
throw GeorefException("Unable to read file!");
}
if (vt_idx != v_idx)
{
std::vector<Eigen::Vector2f> texcoordinates = std::vector<Eigen::Vector2f>(0);
for (size_t faceIndex = 0; faceIndex < f_idx; ++faceIndex)
{
for(size_t i = 0; i < 3; ++i)
{
Eigen::Vector2f vt = mesh.tex_coordinates[0][f2vt[3*faceIndex+i]];
texcoordinates.push_back(vt);
}
}
mesh.tex_coordinates.clear();
mesh.tex_coordinates.push_back(texcoordinates);
}
fs.close();
return (0);
}
bool Georef::readHeader (const std::string &file_name, pcl::PCLPointCloud2 &cloud,
Eigen::Vector4f &origin, Eigen::Quaternionf &orientation,
int &file_version, int &data_type, unsigned int &data_idx,
const int offset)
{
origin = Eigen::Vector4f::Zero ();
orientation = Eigen::Quaternionf::Identity ();
file_version = 0;
cloud.width = cloud.height = cloud.point_step = cloud.row_step = 0;
cloud.data.clear ();
data_type = 0;
data_idx = offset;
std::ifstream fs;
std::string line;
if (file_name == "" || !boost::filesystem::exists (file_name))
{
return false;
}
// Open file in binary mode to avoid problem of
// std::getline() corrupting the result of ifstream::tellg()
fs.open (file_name.c_str (), std::ios::binary);
if (!fs.is_open () || fs.fail ())
{
fs.close ();
return false;
}
// Seek at the given offset
fs.seekg (offset, std::ios::beg);
// Read the header and fill it in with wonderful values
bool vertex_normal_found = false;
bool vertex_texture_found = false;
// Material library, skip for now!
// bool material_found = false;
std::vector<std::string> material_files;
std::size_t nr_point = 0;
std::vector<std::string> st;
try
{
while (!fs.eof ())
{
getline (fs, line);
// Ignore empty lines
if (line == "")
continue;
// Tokenize the line
std::stringstream sstream (line);
sstream.imbue (std::locale::classic ());
line = sstream.str ();
boost::trim (line);
boost::split (st, line, boost::is_any_of ("\t\r "), boost::token_compress_on);
// Ignore comments
if (st.at (0) == "#")
continue;
// Vertex
if (st.at (0) == "v")
{
++nr_point;
continue;
}
// Vertex texture
if ((st.at (0) == "vt") && !vertex_texture_found)
{
vertex_texture_found = true;
continue;
}
// Vertex normal
if ((st.at (0) == "vn") && !vertex_normal_found)
{
vertex_normal_found = true;
continue;
}
// Material library, skip for now!
if (st.at (0) == "mtllib")
{
material_files.push_back (st.at (1));
continue;
}
}
}
catch (const char *exception)
{
fs.close ();
return false;
}
if (!nr_point)
{
fs.close ();
return false;
}
int field_offset = 0;
for (int i = 0; i < 3; ++i, field_offset += 4)
{
cloud.fields.push_back (pcl::PCLPointField ());
cloud.fields[i].offset = field_offset;
cloud.fields[i].datatype = pcl::PCLPointField::FLOAT32;
cloud.fields[i].count = 1;
}
cloud.fields[0].name = "x";
cloud.fields[1].name = "y";
cloud.fields[2].name = "z";
if (vertex_normal_found)
{
std::string normals_names[3] = { "normal_x", "normal_y", "normal_z" };
for (int i = 0; i < 3; ++i, field_offset += 4)
{
cloud.fields.push_back (pcl::PCLPointField ());
pcl::PCLPointField& last = cloud.fields.back ();
last.name = normals_names[i];
last.offset = field_offset;
last.datatype = pcl::PCLPointField::FLOAT32;
last.count = 1;
}
}
if (material_files.size () > 0)
{
for (std::size_t i = 0; i < material_files.size (); ++i)
{
pcl::MTLReader companion;
if (companion.read (file_name, material_files[i]))
{
log_<<"Problem reading material file.";
}
companions_.push_back (companion);
}
}
cloud.point_step = field_offset;
cloud.width = nr_point;
cloud.height = 1;
cloud.row_step = cloud.point_step * cloud.width;
cloud.is_dense = true;
cloud.data.resize (cloud.point_step * nr_point);
fs.close ();
return true;
}

Wyświetl plik

@ -8,6 +8,8 @@
// PCL
#include <pcl/common/eigen.h>
#include <pcl/common/common.h>
// Modified PCL
#include "modifiedPclFunctions.hpp"
// Logger
#include "Logger.hpp"
@ -204,6 +206,24 @@ private:
**/
void printGeorefSystem();
/*!
* \brief Loads a model from an .obj file (replacement for the pcl obj loader).
*
* \param inputFile Path to the .obj file.
* \param mesh The model.
* \return True if model was loaded successfully.
*/
bool loadObjFile(std::string inputFile, pcl::TextureMesh &mesh);
/*!
* \brief Function is compied straight from the function in the pcl::io module.
*/
bool readHeader (const std::string &file_name, pcl::PCLPointCloud2 &cloud,
Eigen::Vector4f &origin, Eigen::Quaternionf &orientation,
int &file_version, int &data_type, unsigned int &data_idx,
const int offset);
Logger log_; /**< Logging object. */
std::string logFile_; /**< The path to the output log file. */
@ -230,6 +250,10 @@ private:
std::vector<std::string> imageList_; /**< A vector containing the names of the corresponding cameras. **/
GeorefSystem georefSystem_; /**< Contains the georeference system. **/
bool multiMaterial_; /**< True if the mesh has multiple materials. **/
std::vector<pcl::MTLReader> companions_; /**< Materials (used by loadOBJFile). **/
};
/*!

Wyświetl plik

@ -8,6 +8,7 @@
#include <pcl/point_types.h>
#include <pcl/surface/texture_mapping.h>
#include <pcl/io/ply_io.h>
#include <pcl/io/obj_io.h>
int saveOBJFile(const std::string &file_name, const pcl::TextureMesh &tex_mesh, unsigned precision);

Wyświetl plik

@ -1,203 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by Qt Creator 2.4.1, 2015-02-04T09:12:31. -->
<qtcreator>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
<value type="int">0</value>
</data>
<data>
<variable>ProjectExplorer.Project.EditorSettings</variable>
<valuemap type="QVariantMap">
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
<value type="QString" key="language">Cpp</value>
<valuemap type="QVariantMap" key="value">
<value type="QString" key="CurrentPreferences">CppGlobal</value>
</valuemap>
</valuemap>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
<value type="QString" key="language">QmlJS</value>
<valuemap type="QVariantMap" key="value">
<value type="QString" key="CurrentPreferences">QmlJSGlobal</value>
</valuemap>
</valuemap>
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
<value type="QByteArray" key="EditorConfiguration.Codec">System</value>
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
<value type="int" key="EditorConfiguration.IndentSize">4</value>
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
<value type="int" key="EditorConfiguration.TabSize">8</value>
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.PluginSettings</variable>
<valuemap type="QVariantMap"/>
</data>
<data>
<variable>ProjectExplorer.Project.Target.0</variable>
<valuemap type="QVariantMap">
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.DefaultCMakeTarget</value>
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
<value type="QString" key="CMakeProjectManager.CMakeBuildConfiguration.BuildDirectory">/home/spotscale/odm/OpenDroneMap-texturing_orthophoto_spotscale_additions/odm_orthophoto-build</value>
<value type="QString" key="CMakeProjectManager.CMakeBuildConfiguration.ToolChain">ProjectExplorer.ToolChain.Gcc:/usr/bin/g++.x86-linux-generic-elf-32bit./usr/bin/gdb</value>
<value type="QString" key="ProjectExplorer.BuildCOnfiguration.ToolChain">ProjectExplorer.ToolChain.Gcc:/usr/bin/g++.x86-linux-generic-elf-32bit./usr/bin/gdb</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.AdditionalArguments"></value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets"/>
<value type="bool" key="CMakeProjectManager.MakeStep.Clean">false</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="QString" key="CMakeProjectManager.MakeStep.AdditionalArguments">clean</value>
<valuelist type="QVariantList" key="CMakeProjectManager.MakeStep.BuildTargets"/>
<value type="bool" key="CMakeProjectManager.MakeStep.Clean">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.MakeStep</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">all</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeBuildConfiguration</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">No deployment</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
<value type="bool" key="Analyzer.Project.UseGlobal">true</value>
<value type="bool" key="Analyzer.Project.UseGlobal">true</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
<value type="int">0</value>
<value type="int">1</value>
<value type="int">2</value>
<value type="int">3</value>
<value type="int">4</value>
<value type="int">5</value>
<value type="int">6</value>
<value type="int">7</value>
<value type="int">8</value>
<value type="int">9</value>
<value type="int">10</value>
<value type="int">11</value>
<value type="int">12</value>
<value type="int">13</value>
<value type="int">14</value>
</valuelist>
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
<value type="int">0</value>
<value type="int">1</value>
<value type="int">2</value>
<value type="int">3</value>
<value type="int">4</value>
<value type="int">5</value>
<value type="int">6</value>
<value type="int">7</value>
<value type="int">8</value>
<value type="int">9</value>
<value type="int">10</value>
<value type="int">11</value>
<value type="int">12</value>
<value type="int">13</value>
<value type="int">14</value>
</valuelist>
<value type="int" key="CMakeProjectManager.BaseEnvironmentBase">2</value>
<value type="QString" key="CMakeProjectManager.CMakeRunConfiguation.Title">odm_orthophoto</value>
<value type="QString" key="CMakeProjectManager.CMakeRunConfiguration.Arguments"></value>
<value type="bool" key="CMakeProjectManager.CMakeRunConfiguration.UseTerminal">false</value>
<valuelist type="QVariantList" key="CMakeProjectManager.CMakeRunConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="CMakeProjectManager.CMakeRunConfiguration.UserWorkingDirectory"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">odm_orthophoto</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">CMakeProjectManager.CMakeRunConfiguration.</value>
<value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
<value type="bool" key="RunConfiguration.UseCppDebugger">true</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">false</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.TargetCount</variable>
<value type="int">1</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.EnvironmentId</variable>
<value type="QString">{785a73be-b55f-490c-9d46-e1451c235840}</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
<value type="int">10</value>
</data>
</qtcreator>

Wyświetl plik

@ -266,7 +266,7 @@ void OdmOrthoPhoto::printHelp()
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_ << "Parameters are specified as: \"-<argument name> <argument>\", (without <>), and the following parameters are configureable:\n";
log_ << "\"-inputFile <path>\" (mandatory)\n";
log_ << "\"Input obj file that must contain a textured mesh.\n\n";
@ -321,18 +321,20 @@ void OdmOrthoPhoto::createOrthoPhoto()
log_ << "Reading mesh file...\n";
// The textureds mesh.
pcl::TextureMesh mesh;
pcl::io::loadOBJFile(inputFile_, mesh);
loadObjFile(inputFile_, mesh);
log_ << ".. mesh file read.\n\n";
// Does the model have more than one material?
multiMaterial_ = 1 < mesh.tex_materials.size();
bool splitModel = false;
if(multiMaterial_)
{
// Need to check relationship between texture coordinates and faces.
if(!isModelOk(mesh))
{
throw OdmOrthoPhotoException("Could not generate ortho photo: The given mesh has multiple textures, but the number of texture coordinates is NOT equal to 3 times the number of faces.");
splitModel = true;
}
}
@ -386,6 +388,58 @@ void OdmOrthoPhoto::createOrthoPhoto()
pcl::PointCloud<pcl::PointXYZ>::Ptr meshCloud (new pcl::PointCloud<pcl::PointXYZ>);
pcl::fromPCLPointCloud2 (mesh.cloud, *meshCloud);
// Split model and make copies of vertices and texture coordinates for all faces
//if (splitModel)
if (splitModel)
{
pcl::PointCloud<pcl::PointXYZ>::Ptr meshCloudSplit (new pcl::PointCloud<pcl::PointXYZ>);
std::vector<Eigen::Vector2f> textureCoordinates = std::vector<Eigen::Vector2f>(0);
size_t vertexIndexCount = 0;
for(size_t t = 0; t < mesh.tex_polygons.size(); ++t)
{
for(size_t faceIndex = 0; faceIndex < mesh.tex_polygons[t].size(); ++faceIndex)
{
pcl::Vertices polygon = mesh.tex_polygons[t][faceIndex];
// The index to the vertices of the polygon.
size_t v1i = polygon.vertices[0];
size_t v2i = polygon.vertices[1];
size_t v3i = polygon.vertices[2];
// The polygon's points.
pcl::PointXYZ v1 = meshCloud->points[v1i];
pcl::PointXYZ v2 = meshCloud->points[v2i];
pcl::PointXYZ v3 = meshCloud->points[v3i];
Eigen::Vector2f vt1 = mesh.tex_coordinates[0][3*faceIndex];
Eigen::Vector2f vt2 = mesh.tex_coordinates[0][3*faceIndex + 1];
Eigen::Vector2f vt3 = mesh.tex_coordinates[0][3*faceIndex + 2];
meshCloudSplit->points.push_back(v1);
textureCoordinates.push_back(vt1);
mesh.tex_polygons[t][faceIndex].vertices[0] = vertexIndexCount;
++vertexIndexCount;
meshCloudSplit->points.push_back(v2);
textureCoordinates.push_back(vt2);
mesh.tex_polygons[t][faceIndex].vertices[1] = vertexIndexCount;
++vertexIndexCount;
meshCloudSplit->points.push_back(v3);
textureCoordinates.push_back(vt3);
mesh.tex_polygons[t][faceIndex].vertices[2] = vertexIndexCount;
++vertexIndexCount;
}
}
mesh.tex_coordinates.clear();
mesh.tex_coordinates.push_back(textureCoordinates);
meshCloud = meshCloudSplit;
}
// Creates a transformation which aligns the area for the ortho photo.
Eigen::Transform<float, 3, Eigen::Affine> transform = getROITransform(xMin, -yMax);
@ -401,6 +455,7 @@ void OdmOrthoPhoto::createOrthoPhoto()
{
uvs.insert(uvs.end(), mesh.tex_coordinates[t].begin(), mesh.tex_coordinates[t].end());
}
//cv::namedWindow("dsfs");
// The current material texture
cv::Mat texture;
@ -416,7 +471,7 @@ void OdmOrthoPhoto::createOrthoPhoto()
// The material of the current submesh.
pcl::TexMaterial material = mesh.tex_materials[t];
texture = cv::imread(material.tex_file);
// Check for missing files.
if(texture.empty())
{
@ -659,6 +714,7 @@ void OdmOrthoPhoto::drawTexturedTriangle(const cv::Mat &texture, const pcl::Vert
v1u = uvs[3*faceIndex][0]; v1v = uvs[3*faceIndex][1];
v2u = uvs[3*faceIndex+1][0]; v2v = uvs[3*faceIndex+1][1];
v3u = uvs[3*faceIndex+2][0]; v3v = uvs[3*faceIndex+2][1];
}
else
{
@ -994,3 +1050,365 @@ bool OdmOrthoPhoto::isModelOk(const pcl::TextureMesh &mesh)
return 3*nFaces == nTextureCoordinates;
}
bool OdmOrthoPhoto::loadObjFile(std::string inputFile, pcl::TextureMesh &mesh)
{
int data_type;
unsigned int data_idx;
int file_version;
int offset = 0;
Eigen::Vector4f origin;
Eigen::Quaternionf orientation;
if (!readHeader(inputFile, mesh.cloud, origin, orientation, file_version, data_type, data_idx, offset))
{
throw OdmOrthoPhotoException("Problem reading header in modelfile!\n");
}
std::ifstream fs;
fs.open (inputFile.c_str (), std::ios::binary);
if (!fs.is_open () || fs.fail ())
{
//PCL_ERROR ("[pcl::OBJReader::readHeader] Could not open file '%s'! Error : %s\n", file_name.c_str (), strerror(errno));
fs.close ();
log_<<"Could not read mesh from file ";
log_ << inputFile.c_str();
log_ <<"\n";
throw OdmOrthoPhotoException("Problem reading mesh from file!\n");
}
// Seek at the given offset
fs.seekg (data_idx, std::ios::beg);
// Get normal_x field indices
int normal_x_field = -1;
for (std::size_t i = 0; i < mesh.cloud.fields.size (); ++i)
{
if (mesh.cloud.fields[i].name == "normal_x")
{
normal_x_field = i;
break;
}
}
std::size_t v_idx = 0;
std::size_t vn_idx = 0;
std::size_t vt_idx = 0;
std::size_t f_idx = 0;
std::string line;
std::vector<std::string> st;
std::vector<Eigen::Vector2f> coordinates;
std::vector<Eigen::Vector2f> allTexCoords;
std::map<int, int> f2vt;
try
{
while (!fs.eof ())
{
getline (fs, line);
// Ignore empty lines
if (line == "")
continue;
// Tokenize the line
std::stringstream sstream (line);
sstream.imbue (std::locale::classic ());
line = sstream.str ();
boost::trim (line);
boost::split (st, line, boost::is_any_of ("\t\r "), boost::token_compress_on);
// Ignore comments
if (st[0] == "#")
continue;
// Vertex
if (st[0] == "v")
{
try
{
for (int i = 1, f = 0; i < 4; ++i, ++f)
{
float value = boost::lexical_cast<float> (st[i]);
memcpy (&mesh.cloud.data[v_idx * mesh.cloud.point_step + mesh.cloud.fields[f].offset], &value, sizeof (float));
}
++v_idx;
}
catch (const boost::bad_lexical_cast &e)
{
log_<<"Unable to convert %s to vertex coordinates!\n";
throw OdmOrthoPhotoException("Unable to convert %s to vertex coordinates!");
}
continue;
}
// Vertex normal
if (st[0] == "vn")
{
try
{
for (int i = 1, f = normal_x_field; i < 4; ++i, ++f)
{
float value = boost::lexical_cast<float> (st[i]);
memcpy (&mesh.cloud.data[vn_idx * mesh.cloud.point_step + mesh.cloud.fields[f].offset],
&value,
sizeof (float));
}
++vn_idx;
}
catch (const boost::bad_lexical_cast &e)
{
log_<<"Unable to convert %s to vertex normal!\n";
throw OdmOrthoPhotoException("Unable to convert %s to vertex normal!");
}
continue;
}
// Texture coordinates
if (st[0] == "vt")
{
try
{
Eigen::Vector3f c (0, 0, 0);
for (std::size_t i = 1; i < st.size (); ++i)
c[i-1] = boost::lexical_cast<float> (st[i]);
if (c[2] == 0)
coordinates.push_back (Eigen::Vector2f (c[0], c[1]));
else
coordinates.push_back (Eigen::Vector2f (c[0]/c[2], c[1]/c[2]));
++vt_idx;
}
catch (const boost::bad_lexical_cast &e)
{
log_<<"Unable to convert %s to vertex texture coordinates!\n";
throw OdmOrthoPhotoException("Unable to convert %s to vertex texture coordinates!");
}
continue;
}
// Material
if (st[0] == "usemtl")
{
mesh.tex_polygons.push_back (std::vector<pcl::Vertices> ());
mesh.tex_materials.push_back (pcl::TexMaterial ());
for (std::size_t i = 0; i < companions_.size (); ++i)
{
std::vector<pcl::TexMaterial>::const_iterator mat_it = companions_[i].getMaterial (st[1]);
if (mat_it != companions_[i].materials_.end ())
{
mesh.tex_materials.back () = *mat_it;
break;
}
}
// We didn't find the appropriate material so we create it here with name only.
if (mesh.tex_materials.back ().tex_name == "")
mesh.tex_materials.back ().tex_name = st[1];
mesh.tex_coordinates.push_back (coordinates);
coordinates.clear ();
continue;
}
// Face
if (st[0] == "f")
{
//We only care for vertices indices
pcl::Vertices face_v; face_v.vertices.resize (st.size () - 1);
for (std::size_t i = 1; i < st.size (); ++i)
{
int v;
sscanf (st[i].c_str (), "%d", &v);
v = (v < 0) ? v_idx + v : v - 1;
face_v.vertices[i-1] = v;
int v2, vt, vn;
sscanf (st[i].c_str (), "%d/%d/%d", &v2, &vt, &vn);
f2vt[3*(f_idx) + i-1] = vt-1;
}
mesh.tex_polygons.back ().push_back (face_v);
++f_idx;
continue;
}
}
}
catch (const char *exception)
{
fs.close ();
log_<<"Unable to read file!\n";
throw OdmOrthoPhotoException("Unable to read file!");
}
if (vt_idx != v_idx)
{
std::vector<Eigen::Vector2f> texcoordinates = std::vector<Eigen::Vector2f>(0);
for (size_t faceIndex = 0; faceIndex < f_idx; ++faceIndex)
{
for(size_t i = 0; i < 3; ++i)
{
Eigen::Vector2f vt = mesh.tex_coordinates[0][f2vt[3*faceIndex+i]];
texcoordinates.push_back(vt);
}
}
mesh.tex_coordinates.clear();
mesh.tex_coordinates.push_back(texcoordinates);
}
fs.close();
return (0);
}
bool OdmOrthoPhoto::readHeader (const std::string &file_name, pcl::PCLPointCloud2 &cloud,
Eigen::Vector4f &origin, Eigen::Quaternionf &orientation,
int &file_version, int &data_type, unsigned int &data_idx,
const int offset)
{
origin = Eigen::Vector4f::Zero ();
orientation = Eigen::Quaternionf::Identity ();
file_version = 0;
cloud.width = cloud.height = cloud.point_step = cloud.row_step = 0;
cloud.data.clear ();
data_type = 0;
data_idx = offset;
std::ifstream fs;
std::string line;
if (file_name == "" || !boost::filesystem::exists (file_name))
{
return false;
}
// Open file in binary mode to avoid problem of
// std::getline() corrupting the result of ifstream::tellg()
fs.open (file_name.c_str (), std::ios::binary);
if (!fs.is_open () || fs.fail ())
{
fs.close ();
return false;
}
// Seek at the given offset
fs.seekg (offset, std::ios::beg);
// Read the header and fill it in with wonderful values
bool vertex_normal_found = false;
bool vertex_texture_found = false;
// Material library, skip for now!
// bool material_found = false;
std::vector<std::string> material_files;
std::size_t nr_point = 0;
std::vector<std::string> st;
try
{
while (!fs.eof ())
{
getline (fs, line);
// Ignore empty lines
if (line == "")
continue;
// Tokenize the line
std::stringstream sstream (line);
sstream.imbue (std::locale::classic ());
line = sstream.str ();
boost::trim (line);
boost::split (st, line, boost::is_any_of ("\t\r "), boost::token_compress_on);
// Ignore comments
if (st.at (0) == "#")
continue;
// Vertex
if (st.at (0) == "v")
{
++nr_point;
continue;
}
// Vertex texture
if ((st.at (0) == "vt") && !vertex_texture_found)
{
vertex_texture_found = true;
continue;
}
// Vertex normal
if ((st.at (0) == "vn") && !vertex_normal_found)
{
vertex_normal_found = true;
continue;
}
// Material library, skip for now!
if (st.at (0) == "mtllib")
{
material_files.push_back (st.at (1));
continue;
}
}
}
catch (const char *exception)
{
fs.close ();
return false;
}
if (!nr_point)
{
fs.close ();
return false;
}
int field_offset = 0;
for (int i = 0; i < 3; ++i, field_offset += 4)
{
cloud.fields.push_back (pcl::PCLPointField ());
cloud.fields[i].offset = field_offset;
cloud.fields[i].datatype = pcl::PCLPointField::FLOAT32;
cloud.fields[i].count = 1;
}
cloud.fields[0].name = "x";
cloud.fields[1].name = "y";
cloud.fields[2].name = "z";
if (vertex_normal_found)
{
std::string normals_names[3] = { "normal_x", "normal_y", "normal_z" };
for (int i = 0; i < 3; ++i, field_offset += 4)
{
cloud.fields.push_back (pcl::PCLPointField ());
pcl::PCLPointField& last = cloud.fields.back ();
last.name = normals_names[i];
last.offset = field_offset;
last.datatype = pcl::PCLPointField::FLOAT32;
last.count = 1;
}
}
if (material_files.size () > 0)
{
for (std::size_t i = 0; i < material_files.size (); ++i)
{
pcl::MTLReader companion;
if (companion.read (file_name, material_files[i]))
{
log_<<"Problem reading material file.";
}
companions_.push_back (companion);
}
}
cloud.point_step = field_offset;
cloud.width = nr_point;
cloud.height = 1;
cloud.row_step = cloud.point_step * cloud.width;
cloud.is_dense = true;
cloud.data.resize (cloud.point_step * nr_point);
fs.close ();
return true;
}

Wyświetl plik

@ -172,6 +172,23 @@ private:
*/
bool isModelOk(const pcl::TextureMesh &mesh);
/*!
* \brief Loads a model from an .obj file (replacement for the pcl obj loader).
*
* \param inputFile Path to the .obj file.
* \param mesh The model.
* \return True if model was loaded successfully.
*/
bool loadObjFile(std::string inputFile, pcl::TextureMesh &mesh);
/*!
* \brief Function is compied straight from the function in the pcl::io module.
*/
bool readHeader (const std::string &file_name, pcl::PCLPointCloud2 &cloud,
Eigen::Vector4f &origin, Eigen::Quaternionf &orientation,
int &file_version, int &data_type, unsigned int &data_idx,
const int offset);
Logger log_; /**< Logging object. */
std::string inputFile_; /**< Path to the textured mesh as an obj-file. */
@ -198,6 +215,8 @@ private:
cv::Mat depth_; /**< The depth of the ortho photo as an OpenCV matrix, CV_32F. */
bool multiMaterial_; /**< True if the mesh has multiple materials. **/
std::vector<pcl::MTLReader> companions_; /**< Materials (used by loadOBJFile). **/
};
/*!

Wyświetl plik

@ -3,7 +3,7 @@ import context
# parse arguments
processopts = ['resize', 'opensfm', 'cmvs', 'pmvs',
'odm_meshing', 'odm_texturing', 'odm_georeferencing',
'odm_meshing', 'mvs_texturing', 'odm_georeferencing',
'odm_orthophoto']
@ -199,6 +199,46 @@ def config():
'times slightly but helps reduce memory usage. '
'Default: %(default)s'))
parser.add_argument('--mvs_texturing-dataTerm',
metavar='<string>',
default='gmi',
help=('Data term: [area, gmi]. Default: %(default)s'))
parser.add_argument('--mvs_texturing-outlierRemovalType',
metavar='<string>',
default='none',
help=('Type of photometric outlier removal method: '
'[none, gauss_damping, gauss_clamping]. Default: '
'%(default)s'))
parser.add_argument('--mvs_texturing-skipGeometricVisibilityTest',
metavar='<string>',
default="false",
help=('Skip geometric visibility test. Default: %(default)s'))
parser.add_argument('--mvs_texturing-skipGlobalSeamLeveling',
metavar='<string>',
default="false",
help=('Skip geometric visibility test. Default: %(default)s'))
parser.add_argument('--mvs_texturing-skipLocalSeamLeveling',
metavar='<string>',
default="false",
help=('Skip local seam blending. Default: %(default)s'))
parser.add_argument('--mvs_texturing-skipHoleFilling',
metavar='<string>',
default="false",
help=('Skip filling of holes in the mesh. Default: %(default)s'))
parser.add_argument('--mvs_texturing-keepUnseenFaces',
metavar='<string>',
default="false",
help=('Keep faces in the mesh that are not seen in any camera. '
'Default: %(default)s'))
# Old odm_texturing arguments
parser.add_argument('--odm_texturing-textureResolution',
metavar='<positive integer>',
default=4096,
@ -213,6 +253,8 @@ def config():
help=('The resolution to rescale the images performing '
'the texturing. Default: %(default)s'))
# End of old odm_texturing arguments
parser.add_argument('--odm_georeferencing-gcpFile',
metavar='<path string>',
default='gcp_list.txt',

Wyświetl plik

@ -23,6 +23,9 @@ 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 mvstex path
mvstex_path = os.path.join(superbuild_path, "install/bin/texrecon")
# define txt2las path
txt2las_path = os.path.join(superbuild_path, 'src/las-tools/bin')
pdal_path = os.path.join(superbuild_path, 'build/pdal/bin')

Wyświetl plik

@ -13,7 +13,8 @@ tasks_dict = {'1': 'resize',
'3': 'cmvs',
'4': 'pmvs',
'5': 'odm_meshing',
'6': 'odm_texturing',
# '6': 'odm_texturing',
'6': 'mvs_texturing',
'7': 'odm_georeferencing',
'8': 'odm_orthophoto',
'9': 'zip_results'}
@ -68,7 +69,7 @@ class ODMTaskManager(object):
command = None
inputs = {}
elif task_name == 'odm_texturing':
elif task_name == 'mvs_texturing':
# setup this task
command = None
inputs = {}

Wyświetl plik

@ -369,11 +369,12 @@ class ODM_Tree(object):
self.odm_mesh = io.join_paths(self.odm_meshing, 'odm_mesh.ply')
self.odm_meshing_log = io.join_paths(self.odm_meshing, 'odm_meshing_log.txt')
# odm_texturing
# texturing
self.odm_textured_model_obj = io.join_paths(
self.odm_texturing, 'odm_textured_model.obj')
self.odm_textured_model_mtl = io.join_paths(
self.odm_texturing, 'odm_textured_model.mtl')
# Log is only used by old odm_texturing
self.odm_texuring_log = io.join_paths(
self.odm_texturing, 'odm_texturing_log.txt')

Wyświetl plik

@ -0,0 +1,90 @@
FROM ubuntu:14.04
MAINTAINER Alex Hagiopol <alex.hagiopol@icloud.com>
# Env variables
ENV DEBIAN_FRONTEND noninteractive
#Install dependencies
#Required Requisites
RUN apt-get update \
&& apt-get install -y -qq \
build-essential \
cmake \
git \
python-pip \
libgdal-dev \
gdal-bin \
libgeotiff-dev \
pkg-config
#CMake 3.1 for MVS-Texturing
RUN sudo apt-get install -y software-properties-common python-software-properties
RUN sudo add-apt-repository -y ppa:george-edison55/cmake-3.x
RUN sudo apt-get update -y
RUN sudo apt-get install -y --only-upgrade cmake
#Installing OpenCV Dependencies
RUN sudo apt-get install -y -qq libgtk2.0-dev \
libavcodec-dev \
libavformat-dev \
libswscale-dev \
python-dev \
python-numpy \
libtbb2 \
libtbb-dev \
libjpeg-dev \
libpng-dev \
libtiff-dev \
libjasper-dev \
libflann-dev \
libproj-dev \
libxext-dev \
liblapack-dev \
libeigen3-dev \
libvtk5-dev
#Removing libdc1394-22-dev due to python opencv issue
RUN sudo apt-get remove libdc1394-22-dev
#Installing OpenSfM Dependencies
RUN sudo apt-get install -y -qq python-networkx \
libgoogle-glog-dev \
libsuitesparse-dev \
libboost-filesystem-dev \
libboost-iostreams-dev \
libboost-regex-dev \
libboost-python-dev \
libboost-date-time-dev \
libboost-thread-dev
RUN sudo pip install -U PyYAML \
exifread \
gpxpy \
xmltodict \
catkin-pkg
#Installing Ecto Dependencies
RUN sudo apt-get install -y -qq python-empy \
python-nose \
python-pyside
#"Installing OpenDroneMap Dependencies"
RUN sudo apt-get install -y python-pyexiv2 \
python-scipy \
jhead \
liblas-bin -y -qq
RUN sudo apt-get install -y python-empy \
python-nose \
python-pyside \
python-pyexiv2 \
python-scipy \
jhead \
liblas-bin \
python-matplotlib \
libatlas-base-dev \
libatlas3gf-base
ENV PYTHONPATH="$PYTHONPATH:/code/SuperBuild/install/lib/python2.7/dist-packages"
ENV PYTHONPATH="$PYTHONPATH:/code/SuperBuild/src/opensfm"
ENV LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/code/SuperBuild/install/lib"

12
run.py
Wyświetl plik

@ -6,6 +6,7 @@ from opendm import system
import sys
import ecto
import os
from scripts.odm_app import ODMApp
@ -26,6 +27,17 @@ if __name__ == '__main__':
if args.project_path is None:
usage()
#If user asks to rerun everything, delete all of the existing progress directories.
if args.rerun_all:
os.system("rm -rf "
+ args.project_path + "images_resize/ "
+ args.project_path + "odm_georeferencing/ "
+ args.project_path + "odm_meshing/ "
+ args.project_path + "odm_orthophoto/ "
+ args.project_path + "odm_texturing/ "
+ args.project_path + "opensfm/ "
+ args.project_path + "pmvs/")
# create an instance of my App BlackBox
# internally configure all tasks
app = ODMApp(args=args)

111
scripts/mvstex.py 100644
Wyświetl plik

@ -0,0 +1,111 @@
import ecto
from opendm import log
from opendm import io
from opendm import system
from opendm import context
import pmvs2nvmcams
class ODMMvsTexCell(ecto.Cell):
def declare_params(self, params):
params.declare("data_term", 'Data term: [area, gmi] default: gmi', "gmi")
params.declare("outlier_rem_type", 'Type of photometric outlier removal method: [none, gauss_damping, gauss_clamping]. default: none', "none")
params.declare("skip_vis_test", 'Skip geometric visibility test based on ray intersection.', "false")
params.declare("skip_glob_seam_leveling", 'Skip global seam leveling.', "false")
params.declare("skip_loc_seam_leveling", 'Skip local seam leveling (Poisson editing).', "false")
params.declare("skip_hole_fill", 'Skip hole filling.', "false")
params.declare("keep_unseen_faces", 'Keep unseen faces.', "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 MVS Texturing Cell')
# get inputs
args = self.inputs.args
tree = self.inputs.tree
# define paths and create working directories
system.mkdir_p(tree.odm_texturing)
# check if we rerun cell or not
rerun_cell = (args.rerun is not None and
args.rerun == 'mvs_texturing') or \
(args.rerun_all) or \
(args.rerun_from is not None and
'mvs_texturing' in args.rerun_from)
if not io.file_exists(tree.odm_textured_model_obj) or rerun_cell:
log.ODM_DEBUG('Writing MVS Textured file in: %s'
% tree.odm_textured_model_obj)
# Format arguments to fit Mvs-Texturing app
skipGeometricVisibilityTest = ""
skipGlobalSeamLeveling = ""
skipLocalSeamLeveling = ""
skipHoleFilling = ""
keepUnseenFaces = ""
if (self.params.skip_vis_test.lower() == "true"):
skipGeometricVisibilityTest = "--skip_geometric_visibility_test"
if (self.params.skip_glob_seam_leveling.lower() == "true"):
skipGlobalSeamLeveling = "--skip_global_seam_leveling"
if (self.params.skip_loc_seam_leveling.lower() == "true"):
skipLocalSeamLeveling = "--skip_local_seam_leveling"
if (self.params.skip_hole_fill.lower() == "true"):
skipHoleFilling = "--skip_hole_filling"
if (self.params.keep_unseen_faces.lower() == "true"):
keepUnseenFaces = "--keep_unseen_faces"
# mvstex definitions
kwargs = {
'bin': context.mvstex_path,
'out_dir': io.join_paths(tree.odm_texturing, "odm_textured_model"),
'pmvs_folder': tree.pmvs_rec_path,
'nvm_file': io.join_paths(tree.pmvs_rec_path, "nvmCams.nvm"),
'model': tree.odm_mesh,
'dataTerm': self.params.data_term,
'outlierRemovalType': self.params.outlier_rem_type,
'skipGeometricVisibilityTest': skipGeometricVisibilityTest,
'skipGlobalSeamLeveling': skipGlobalSeamLeveling,
'skipLocalSeamLeveling': skipLocalSeamLeveling,
'skipHoleFilling': skipHoleFilling,
'keepUnseenFaces': keepUnseenFaces
}
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))
# run texturing binary
system.run('{bin} {nvm_file} {model} {out_dir} '
'-d {dataTerm} -o {outlierRemovalType} '
'{skipGeometricVisibilityTest} '
'{skipGlobalSeamLeveling} '
'{skipLocalSeamLeveling} '
'{skipHoleFilling} '
'{keepUnseenFaces}'.format(**kwargs))
else:
log.ODM_WARNING('Found a valid ODM Texture file in: %s'
% tree.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

Wyświetl plik

@ -13,7 +13,8 @@ from opensfm import ODMOpenSfMCell
from pmvs import ODMPmvsCell
from cmvs import ODMCmvsCell
from odm_meshing import ODMeshingCell
from odm_texturing import ODMTexturingCell
#from odm_texturing import ODMTexturingCell
from mvstex import ODMMvsTexCell
from odm_georeferencing import ODMGeoreferencingCell
from odm_orthophoto import ODMOrthoPhotoCell
@ -57,9 +58,16 @@ class ODMApp(ecto.BlackBox):
oct_tree=p.args.odm_meshing_octreeDepth,
samples=p.args.odm_meshing_samplesPerNode,
solver=p.args.odm_meshing_solverDivide),
'texturing': ODMTexturingCell(resize=p.args.resize_to,
resolution=p.args.odm_texturing_textureResolution,
size=p.args.odm_texturing_textureWithSize),
'texturing': ODMMvsTexCell(data_term=p.args.mvs_texturing_dataTerm,
outlier_rem_type=p.args.mvs_texturing_outlierRemovalType,
skip_vis_test=p.args.mvs_texturing_skipGeometricVisibilityTest,
skip_glob_seam_leveling=p.args.mvs_texturing_skipGlobalSeamLeveling,
skip_loc_seam_leveling=p.args.mvs_texturing_skipLocalSeamLeveling,
skip_hole_fill=p.args.mvs_texturing_skipHoleFilling,
keep_unseen_faces=p.args.mvs_texturing_keepUnseenFaces),
# Old odm_texturing
# 'texturing': ODMTexturingCell(resize=p.args['resize_to'],
# resolution=p.args['odm_texturing_textureResolution'],
'georeferencing': ODMGeoreferencingCell(img_size=p.args.resize_to,
gcp_file=p.args.odm_georeferencing_gcpFile,
use_gcp=p.args.odm_georeferencing_useGcp),

Wyświetl plik

@ -0,0 +1,144 @@
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")

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 193 KiB