diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 000000000..e82fb5df7
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,17 @@
+Dockerfile
+tests/test_data
+SuperBuild/build
+SuperBuild/download
+SuperBuild/install
+SuperBuild/src
+build
+opensfm
+pmvs
+odm_orthophoto
+odm_texturing
+odm_meshing
+odm_georeferencing
+images_resize
+.git
+
+
diff --git a/.gitignore b/.gitignore
index e69de29bb..460fe7037 100644
--- a/.gitignore
+++ b/.gitignore
@@ -0,0 +1,22 @@
+*~
+bin/
+include/
+lib/
+logs/
+share/
+src/
+download/
+
+SuperBuild/build/
+SuperBuild/install/
+build/
+
+cmvs.tar.gz
+parallel.tar.bz2
+LAStools.zip
+pcl.tar.gz
+ceres-solver.tar.gz
+*.pyc
+opencv.zip
+settings.yaml
+docker.settings.yaml
\ No newline at end of file
diff --git a/README b/.gitmodules
similarity index 100%
rename from README
rename to .gitmodules
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 000000000..a8a441d8c
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,18 @@
+cmake_minimum_required(VERSION 2.8)
+
+project(OpenDroneMap C CXX)
+
+# TODO(edgar): add option in order to point to CMAKE_PREFIX_PATH
+# if we want to build SuperBuild in an external directory.
+# It is assumed that SuperBuild have been compiled.
+
+# Set third party libs location
+set(CMAKE_PREFIX_PATH "${CMAKE_CURRENT_SOURCE_DIR}/SuperBuild/install")
+
+# move binaries to the same bin directory
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
+
+option(ODM_BUILD_SLAM "Build SLAM module" OFF)
+
+# Add ODM sub-modules
+add_subdirectory(modules)
diff --git a/CNAME b/CNAME
new file mode 100644
index 000000000..ed563e1e0
--- /dev/null
+++ b/CNAME
@@ -0,0 +1 @@
+opendronemap.org
\ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 000000000..b47d7ceec
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+# Contributing to OpenDroneMap
+
+:+1::tada: First off, thanks for taking the time to contribute! :tada::+1:
+
+### Code of Conduct
+
+This project adheres to the Contributor Covenant [code of conduct](code_of_conduct.md).
+By participating, you are expected to uphold this code.
+Please report unacceptable behavior to the [Project Maintainer](mailto:svm@clevelandmetroparks.com).
+
+## How can I contribute?
+
+### Reporting bugs
+
+Bugs are tracked as Github issues. Please create an issue in the repository and tag it with the Bug tag.
+
+Explain the problem and include additional details to help maintainers reproduce the problem:
+
+* **Use a clear and descriptive title** for the issue to identify the problem.
+* **Describe the exact steps which reproduce the problem** in as many details as possible. For example, start by explaining how you run ODM (Docker, Vagrant, etc), e.g. which command exactly you used in the terminal. When listing steps, **don't just say what you did, but explain how you did it**.
+* **Provide specific examples to demonstrate the steps**. Include links to files or GitHub projects, or copy/pasteable snippets, which you use in those examples. If you're providing snippets in the issue, use [Markdown code blocks](https://help.github.com/articles/markdown-basics/#multiple-lines).
+* **Describe the behavior you observed after following the steps** and point out what exactly is the problem with that behavior.
+* **Explain which behavior you expected to see instead and why.**
+* **Include screenshots and animated GIFs** which show you following the described steps and clearly demonstrate the problem. If you use the keyboard while following the steps, **record the GIF with the [Keybinding Resolver](https://github.com/atom/keybinding-resolver) shown**. You can use [this tool](http://www.cockos.com/licecap/) to record GIFs on macOS and Windows, and [this tool](https://github.com/colinkeenan/silentcast) or [this tool](https://github.com/GNOME/byzanz) on Linux.
+* **If the problem is related to performance**, please post your machine's specs (host and guest machine).
+* **If the problem wasn't triggered by a specific action**, describe what you were doing before the problem happened and share more information using the guidelines below.
+
+Include details about your configuration and environment:
+
+* **Which version of ODM are you using?** A stable release? a clone of master or dev?
+* **What's the name and version of the OS you're using**?
+* **Are you running ODM in a virtual machine?** If so, which VM software are you using and which operating systems and versions are used for the host and the guest?
+
+#### Template For Submitting Bug Reports
+
+ [Short description of problem here]
+
+ **Reproduction Steps:**
+
+ 1. [First Step]
+ 2. [Second Step]
+ 3. [Other Steps...]
+
+ **Expected behavior:**
+
+ [Describe expected behavior here]
+
+ **Observed behavior:**
+
+ [Describe observed behavior here]
+
+ **Screenshots and GIFs**
+
+ 
+
+ **ODM version:** [Enter Atom version here]
+ **OS and version:** [Enter OS name and version here]
+
+ **Additional information:**
+
+ * Problem started happening recently, didn't happen in an older version of ODM: [Yes/No]
+ * Problem can be reliably reproduced, doesn't happen randomly: [Yes/No]
+ * Problem happens with all datasets and projects, not only some datasets or projects: [Yes/No]
+
+### Pull Requests
+* Include screenshots and animated GIFs in your pull request whenever possible.
+* Follow the [PEP8 Python Style Guide](https://www.python.org/dev/peps/pep-0008/).
+* End files with a newline.
+* Avoid platform-dependent code:
+ * Use `require('fs-plus').getHomeDirectory()` to get the home directory.
+ * Use `path.join()` to concatenate filenames.
+ * Use `os.tmpdir()` rather than `/tmp` when you need to reference the
+ temporary directory.
+* Using a plain `return` when returning explicitly at the end of a function.
+ * Not `return null`, `return undefined`, `null`, or `undefined`
+
+
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 000000000..a480be8f1
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,68 @@
+FROM phusion/baseimage
+
+# Env variables
+ENV DEBIAN_FRONTEND noninteractive
+
+#Install dependencies
+RUN apt-get update -y
+RUN apt-get install software-properties-common -y
+#Required Requisites
+RUN add-apt-repository -y ppa:ubuntugis/ppa
+RUN add-apt-repository -y ppa:george-edison55/cmake-3.x
+RUN apt-get update -y
+
+# All packages (Will install much faster)
+RUN apt-get install --no-install-recommends -y git cmake python-pip build-essential software-properties-common python-software-properties libgdal-dev gdal-bin libgeotiff-dev \
+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-pyproj python-empy python-nose python-pyside python-pyexiv2 python-scipy \
+libexiv2-dev liblas-bin python-matplotlib libatlas-base-dev libgmp-dev libmpfr-dev swig2.0 python-wheel libboost-log-dev libjsoncpp-dev
+
+RUN apt-get remove libdc1394-22-dev
+RUN pip install --upgrade pip
+RUN pip install setuptools
+RUN pip install -U PyYAML exifread gpxpy xmltodict catkin-pkg appsettings https://github.com/OpenDroneMap/gippy/archive/v0.3.9.tar.gz loky
+
+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"
+
+# Prepare directories
+
+RUN mkdir /code
+WORKDIR /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 /modules/ /code/modules/
+COPY /opendm/ /code/opendm/
+COPY /patched_files/ /code/patched_files/
+COPY run.py /code/run.py
+COPY run.sh /code/run.sh
+COPY /scripts/ /code/scripts/
+COPY /SuperBuild/cmake/ /code/SuperBuild/cmake/
+COPY /SuperBuild/CMakeLists.txt /code/SuperBuild/CMakeLists.txt
+COPY docker.settings.yaml /code/settings.yaml
+COPY VERSION /code/VERSION
+
+
+#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)
+
+RUN apt-get -y remove libgl1-mesa-dri git cmake python-pip build-essential
+RUN apt-get install -y libvtk5-dev
+
+# Cleanup APT
+RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
+
+# Clean Superbuild
+
+RUN rm -rf /code/SuperBuild/download
+RUN rm -rf /code/SuperBuild/src/opencv/samples /code/SuperBuild/src/pcl/test /code/SuperBuild/src/pcl/doc /code/SuperBuild/src/pdal/test /code/SuperBuild/src/pdal/doc
+
+# Entry point
+ENTRYPOINT ["python", "/code/run.py", "code"]
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 000000000..9cecc1d46
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ {one line to give the program's name and a brief idea of what it does.}
+ Copyright (C) {year} {name of author}
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ {project} Copyright (C) {year} {fullname}
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
diff --git a/README.md b/README.md
new file mode 100644
index 000000000..4812ffa03
--- /dev/null
+++ b/README.md
@@ -0,0 +1,211 @@
+# OpenDroneMap
+
+
+
+## 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.
+
+
+
+In a word, OpenDroneMap is a toolchain for processing raw civilian UAS imagery to other useful products. What kind of products?
+
+1. Point Clouds
+2. Digital Surface Models
+3. Textured Digital Surface Models
+4. Orthorectified Imagery
+5. Classified Point Clouds (coming soon)
+6. Digital Elevation Models
+7. etc.
+
+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.
+
+## QUICKSTART
+
+### Docker (All platforms)
+
+The easiest way to run ODM is through Docker. 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 through "Create a Docker group". The Docker image workflow
+has equivalent procedures for Mac OS X and Windows found at [docs.docker.com](docs.docker.com). Then run the following command which will build a pre-built image and run on images found in `$(pwd)/images` (you can change this if you need to, see the [wiki](https://github.com/OpenDroneMap/OpenDroneMap/wiki/Docker) for more detailed instructions.
+
+```
+docker run -it --rm -v $(pwd)/images:/code/images -v $(pwd)/odm_orthophoto:/code/odm_orthophoto -v $(pwd)/odm_texturing:/code/odm_texturing opendronemap/opendronemap
+```
+
+### Native Install (Ubuntu 16.04)
+
+** Please note that we need help getting ODM updated to work for 16.10+. Look at #659 or drop into the [gitter][https://gitter.im/OpenDroneMap/OpenDroneMap) for more info.
+
+
+**[Download the latest release here](https://github.com/OpenDroneMap/OpenDroneMap/releases)**
+Current version: 0.3.1 (this software is in beta)
+
+1. Extract and enter the OpenDroneMap directory
+2. Run `bash configure.sh install`
+4. Edit the `settings.yaml` file in your favorite text editor. Set the `project-path` value to an empty directory (you will place sub-directories containing individual projects inside). You can add many options to this file, [see here](https://github.com/OpenDroneMap/OpenDroneMap/wiki/Run-Time-Parameters)
+3. Download a sample dataset from [here](https://github.com/OpenDroneMap/odm_data_aukerman/archive/master.zip) (about 550MB) and extract it as a subdirectory in your project directory.
+4. Run `./run.sh odm_data_aukerman`
+5. Enter dataset directory to view results:
+ - orthophoto: odm_orthophoto/odm_orthophoto.tif
+ - textured mesh model: odm_texturing/odm_textured_model_geo.obj
+ - point cloud (georeferenced): odm_georeferencing/odm_georeferenced_model.ply
+
+See below for more detailed installation instructions.
+
+## Diving Deeper
+
+### Installation
+
+Extract and enter the downloaded OpenDroneMap directory and compile all of the code by executing a single configuration script:
+
+ bash configure.sh install
+
+When updating to a newer version of ODM, it is recommended that you run
+
+ bash configure.sh reinstall
+
+to ensure all the dependent packages and modules get updated.
+
+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
+
+### Environment Variables
+
+There are some environmental variables that need to be set. Open the ~/.bashrc file on your machine and add the following 3 lines at the end. The file can be opened with ```gedit ~/.bashrc``` if you are using an Ubuntu desktop environment. Be sure to replace the "/your/path/" with the correct path to the location where you extracted 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
+
+Note that using `run.sh` sets these temporarily in the shell.
+
+### Run OpenDroneMap
+
+First you need a set of images, taken from a drone or otherwise. Example data can be obtained from https://github.com/OpenDroneMap/odm_data
+
+Next, you need to edit the `settings.yaml` file. The only setting you must edit is the `project-path` key. Set this to an empty directory within projects will be saved. There are many options for tuning your project. See the [wiki](https://github.com/OpenDroneMap/OpenDroneMap/wiki/Run-Time-Parameters) or run `python run.py -h`
+
+
+Then run:
+
+ python run.py -i /path/to/images project-name
+
+The images will be copied over to the project path so you only need to specify the `-i /path/` once. You can also override any variable from settings.yaml here using the command line arguments. If you want to rerun the whole thing, run
+
+ python run.py --rerun-all project-name
+
+or
+
+ 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'
+
+### View Results
+
+When the process finishes, the results will be organized as follows:
+
+ |-- images/
+ |-- img-1234.jpg
+ |-- ...
+ |-- images_resize/
+ |-- img-1234.jpg
+ |-- ...
+ |-- opensfm/
+ |-- see mapillary/opensfm repository for more info
+ |-- depthmaps/
+ |-- merged.ply # Dense Point cloud (not georeferenced)
+ |-- odm_meshing/
+ |-- odm_mesh.ply # A 3D mesh
+ |-- odm_meshing_log.txt # Output of the meshing task. May point out errors.
+ |-- odm_texturing/
+ |-- odm_textured_model.obj # Textured mesh
+ |-- odm_textured_model_geo.obj # Georeferenced textured mesh
+ |-- texture_N.jpg # Associated textured images used by the model
+ |-- odm_georeferencing/
+ |-- odm_georeferenced_model.ply # A georeferenced dense point cloud
+ |-- odm_georeferenced_model.ply.laz # LAZ format point cloud
+ |-- odm_georeferenced_model.csv # XYZ format point cloud
+ |-- odm_georeferencing_log.txt # Georeferencing log
+ |-- odm_georeferencing_transform.txt# Transform used for georeferencing
+ |-- odm_georeferencing_utm_log.txt # Log for the extract_utm portion
+ |-- odm_orthophoto/
+ |-- odm_orthophoto.png # Orthophoto image (no coordinates)
+ |-- odm_orthophoto.tif # Orthophoto GeoTiff
+ |-- odm_orthophoto_log.txt # Log file
+ |-- gdal_translate_log.txt # Log for georeferencing the png file
+
+Any file ending in .obj or .ply can be opened and viewed in [MeshLab](http://meshlab.sourceforge.net/) or similar software. That includes `opensfm/depthmaps/merged.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:
+
+
+
+You can also view the orthophoto GeoTIFF in [QGIS](http://www.qgis.org/) or other mapping software:
+
+
+
+## Build and Run Using Docker
+
+(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))
+
+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 through "Create a Docker group". Once Docker is installed, the fastest way to use OpenDroneMap is to run a pre-built image by typing:
+
+ docker run -it --rm -v $(pwd)/images:/code/images -v $(pwd)/odm_orthophoto:/code/odm_orthophoto -v $(pwd)/odm_texturing:/code/odm_texturing opendronemap/opendronemap
+
+If you want to build your own Docker image from sources, type:
+
+ docker build -t my_odm_image .
+ docker run -it --rm -v $(pwd)/images:/code/images -v $(pwd)/odm_orthophoto:/code/odm_orthophoto -v $(pwd)/odm_texturing:/code/odm_texturing my_odm_image
+
+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.
+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 --rm -v $(pwd)/images:/code/images -v $(pwd)/odm_georeferencing:/code/odm_georeferencing -v $(pwd)/odm_orthophoto:/code/odm_orthophoto my_odm_image
+
+If you want to get all intermediate outputs, run the following command:
+
+ docker run -it --rm -v $(pwd)/images:/code/images -v $(pwd)/odm_georeferencing:/code/odm_georeferencing -v $(pwd)/odm_meshing:/code/odm_meshing -v $(pwd)/odm_orthophoto:/code/odm_orthophoto -v $(pwd)/odm_texturing:/code/odm_texturing -v $(pwd)/opensfm:/code/opensfm -v $(pwd)/pmvs:/code/pmvs opendronemap/opendronemap
+
+To pass in custom parameters to the run.py script, simply pass it as arguments to the `docker run` command. For example:
+
+ docker run -it --rm -v $(pwd)/images:/code/images v $(pwd)/odm_orthophoto:/code/odm_orthophoto -v $(pwd)/odm_texturing:/code/odm_texturing opendronemap/opendronemap --resize-to 1800 --force-ccd 6.16
+
+If you want to pass in custom parameters using the settings.yaml file, you can pass it as a -v volume binding:
+
+ docker run -it --rm -v $(pwd)/images:/code/images v $(pwd)/odm_orthophoto:/code/odm_orthophoto -v $(pwd)/odm_texturing:/code/odm_texturing -v $(pwd)/settings.yaml:/code/settings.yaml opendronemap/opendronemap
+
+
+## User Interface
+
+A web interface and API to OpenDroneMap is currently under active development in the [WebODM](https://github.com/OpenDroneMap/WebODM) repository.
+
+## Video Support
+
+Currently we have an experimental feature that uses ORB_SLAM to render a textured mesh from video. It is only supported on Ubuntu 14.04 on machines with X11 support. See the [wiki](https://github.com/OpenDroneMap/OpenDroneMap/wiki/Reconstruction-from-Video)for details on installation and use.
+
+## Examples
+
+Coming soon...
+
+## Documentation:
+
+For documentation, please take a look at our [wiki](https://github.com/OpenDroneMap/OpenDroneMap/wiki).Check here first if you are having problems. If you still need help, look through the issue queue or create one. There's also a general help chat [here](https://gitter.im/OpenDroneMap/generalhelp).
+
+## Developers
+
+Help improve our software!
+
+[](https://gitter.im/OpenDroneMap/OpenDroneMap?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+
+1. Try to keep commits clean and simple
+2. Submit a pull request with detailed changes and test results
+
+
diff --git a/SuperBuild/CMakeLists.txt b/SuperBuild/CMakeLists.txt
new file mode 100644
index 000000000..453c3fb47
--- /dev/null
+++ b/SuperBuild/CMakeLists.txt
@@ -0,0 +1,134 @@
+cmake_minimum_required(VERSION 3.1)
+
+project(ODM-SuperBuild)
+
+# Setup SuperBuild root location
+set(SB_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+
+# Path to additional CMake modules
+set(CMAKE_MODULE_PATH ${SB_ROOT_DIR}/cmake)
+
+include(ExternalProject)
+include(ExternalProject-Setup)
+
+option(ODM_BUILD_SLAM "Build SLAM module" OFF)
+
+
+################################
+# Setup SuperBuild directories #
+################################
+
+# Setup location where source tar-balls are downloaded
+set(SB_DOWNLOAD_DIR "${SB_ROOT_DIR}/download"
+ CACHE PATH "Location where source tar-balls are (to be) downloaded.")
+mark_as_advanced(SB_DOWNLOAD_DIR)
+
+message(STATUS "SuperBuild files will be downloaded to: ${SB_DOWNLOAD_DIR}")
+
+
+# Setup location where source tar-balls are located
+set(SB_SOURCE_DIR "${SB_ROOT_DIR}/src"
+ CACHE PATH "Location where source tar-balls are (will be).")
+mark_as_advanced(SB_SOURCE_DIR)
+
+message(STATUS "SuperBuild source files will be extracted to: ${SB_SOURCE_DIR}")
+
+
+# Setup location where source tar-balls are located
+set(SB_INSTALL_DIR "${SB_ROOT_DIR}/install"
+ CACHE PATH "Location where source tar-balls are (will be) installed.")
+mark_as_advanced(SB_SOURCE_DIR)
+
+message(STATUS "SuperBuild source files will be installed to: ${SB_INSTALL_DIR}")
+
+
+# Setup location where binary files are located
+set(SB_BINARY_DIR "${SB_ROOT_DIR}/build"
+ CACHE PATH "Location where files are (will be) located.")
+mark_as_advanced(SB_BINARY_DIR)
+
+message(STATUS "SuperBuild binary files will be located to: ${SB_BINARY_DIR}")
+
+
+#########################################
+# Download and install third party libs #
+#########################################
+
+# ---------------------------------------------------------------------------------------------
+# Open Source Computer Vision (OpenCV)
+#
+set(ODM_OpenCV_Version 2.4.11)
+option(ODM_BUILD_OpenCV "Force to build OpenCV library" OFF)
+
+SETUP_EXTERNAL_PROJECT(OpenCV ${ODM_OpenCV_Version} ${ODM_BUILD_OpenCV})
+
+
+# ---------------------------------------------------------------------------------------------
+# Point Cloud Library (PCL)
+#
+set(ODM_PCL_Version 1.7.2)
+option(ODM_BUILD_PCL "Force to build PCL library" OFF)
+
+SETUP_EXTERNAL_PROJECT(PCL ${ODM_PCL_Version} ${ODM_BUILD_PCL})
+
+
+# ---------------------------------------------------------------------------------------------
+# Google Flags library (GFlags)
+#
+set(ODM_GFlags_Version 2.1.2)
+option(ODM_BUILD_GFlags "Force to build GFlags library" OFF)
+
+SETUP_EXTERNAL_PROJECT(GFlags ${ODM_GFlags_Version} ${ODM_BUILD_GFlags})
+
+
+# ---------------------------------------------------------------------------------------------
+# Ceres Solver
+#
+set(ODM_Ceres_Version 1.10.0)
+option(ODM_BUILD_Ceres "Force to build Ceres library" OFF)
+
+SETUP_EXTERNAL_PROJECT(Ceres ${ODM_Ceres_Version} ${ODM_BUILD_Ceres})
+
+
+# ---------------------------------------------------------------------------------------------
+# CGAL
+#
+set(ODM_CGAL_Version 4.9)
+option(ODM_BUILD_CGAL "Force to build CGAL library" OFF)
+
+SETUP_EXTERNAL_PROJECT(CGAL ${ODM_CGAL_Version} ${ODM_BUILD_CGAL})
+
+# ---------------------------------------------------------------------------------------------
+# Hexer
+#
+SETUP_EXTERNAL_PROJECT(Hexer 1.4 ON)
+
+# ---------------------------------------------------------------------------------------------
+# Open Geometric Vision (OpenGV)
+# Open Structure from Motion (OpenSfM)
+# Clustering Views for Multi-view Stereo (CMVS)
+# Catkin
+# Ecto
+#
+
+set(custom_libs OpenGV
+ OpenSfM
+ CMVS
+ Catkin
+ Ecto
+ PDAL
+ MvsTexturing
+ Lidar2dems
+)
+
+# Dependencies of the SLAM module
+if(ODM_BUILD_SLAM)
+ list(APPEND custom_libs
+ Pangolin
+ ORB_SLAM2)
+endif()
+
+foreach(lib ${custom_libs})
+ SETUP_EXTERNAL_PROJECT_CUSTOM(${lib})
+endforeach()
+
diff --git a/SuperBuild/cmake/External-CGAL.cmake b/SuperBuild/cmake/External-CGAL.cmake
new file mode 100644
index 000000000..51e09c4b9
--- /dev/null
+++ b/SuperBuild/cmake/External-CGAL.cmake
@@ -0,0 +1,26 @@
+set(_proj_name cgal)
+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/CGAL/cgal/releases/download/releases%2FCGAL-4.9/CGAL-4.9.zip
+ URL_MD5 31c08d762a72fda785df194c89b833df
+ #--Update/Patch step----------
+ UPDATE_COMMAND ""
+ #--Configure step-------------
+ SOURCE_DIR ${SB_SOURCE_DIR}/${_proj_name}
+ CMAKE_ARGS
+ -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
+)
diff --git a/SuperBuild/cmake/External-CMVS.cmake b/SuperBuild/cmake/External-CMVS.cmake
new file mode 100644
index 000000000..a58beb5fd
--- /dev/null
+++ b/SuperBuild/cmake/External-CMVS.cmake
@@ -0,0 +1,28 @@
+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 /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
+)
+
diff --git a/SuperBuild/cmake/External-Catkin.cmake b/SuperBuild/cmake/External-Catkin.cmake
new file mode 100644
index 000000000..5a0914c17
--- /dev/null
+++ b/SuperBuild/cmake/External-Catkin.cmake
@@ -0,0 +1,27 @@
+set(_proj_name catkin)
+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}
+ URL https://github.com/ros/catkin/archive/0.6.16.zip
+ URL_MD5 F5D45AE68709CE6E3346FB8C019416F8
+ #--Update/Patch step----------
+ UPDATE_COMMAND ""
+ #--Configure step-------------
+ SOURCE_DIR ${SB_SOURCE_DIR}/${_proj_name}
+ CMAKE_ARGS
+ -DCATKIN_ENABLE_TESTING=OFF
+ -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
+)
diff --git a/SuperBuild/cmake/External-Ceres.cmake b/SuperBuild/cmake/External-Ceres.cmake
new file mode 100644
index 000000000..4b3eaf109
--- /dev/null
+++ b/SuperBuild/cmake/External-Ceres.cmake
@@ -0,0 +1,31 @@
+set(_proj_name ceres)
+set(_SB_BINARY_DIR "${SB_BINARY_DIR}/${_proj_name}")
+
+ExternalProject_Add(${_proj_name}
+ DEPENDS gflags
+ PREFIX ${_SB_BINARY_DIR}
+ TMP_DIR ${_SB_BINARY_DIR}/tmp
+ STAMP_DIR ${_SB_BINARY_DIR}/stamp
+ #--Download step--------------
+ DOWNLOAD_DIR ${SB_DOWNLOAD_DIR}
+ URL http://ceres-solver.org/ceres-solver-1.10.0.tar.gz
+ URL_MD5 dbf9f452bd46e052925b835efea9ab16
+ #--Update/Patch step----------
+ UPDATE_COMMAND ""
+ #--Configure step-------------
+ SOURCE_DIR ${SB_SOURCE_DIR}/${_proj_name}
+ CMAKE_ARGS
+ -DCMAKE_C_FLAGS=-fPIC
+ -DCMAKE_CXX_FLAGS=-fPIC
+ -DBUILD_EXAMPLES=OFF
+ -DBUILD_TESTING=OFF
+ -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
+)
\ No newline at end of file
diff --git a/SuperBuild/cmake/External-Ecto.cmake b/SuperBuild/cmake/External-Ecto.cmake
new file mode 100644
index 000000000..e031cb82c
--- /dev/null
+++ b/SuperBuild/cmake/External-Ecto.cmake
@@ -0,0 +1,30 @@
+set(_proj_name ecto)
+set(_SB_BINARY_DIR "${SB_BINARY_DIR}/${_proj_name}")
+
+ExternalProject_Add(${_proj_name}
+ DEPENDS catkin
+ 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/plasmodic/ecto/archive/c6178ed0102a66cebf503a4213c27b0f60cfca69.zip
+ URL_MD5 A5C4757B656D536D3E3CC1DC240EC158
+ #--Update/Patch step----------
+ UPDATE_COMMAND ""
+ #--Configure step-------------
+ SOURCE_DIR ${SB_SOURCE_DIR}/${_proj_name}
+ CMAKE_ARGS
+ -DBUILD_DOC=OFF
+ -DBUILD_SAMPLES=OFF
+ -DCATKIN_ENABLE_TESTING=OFF
+ -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
+)
diff --git a/SuperBuild/cmake/External-GFlags.cmake b/SuperBuild/cmake/External-GFlags.cmake
new file mode 100644
index 000000000..2c9b26792
--- /dev/null
+++ b/SuperBuild/cmake/External-GFlags.cmake
@@ -0,0 +1,27 @@
+set(_proj_name gflags)
+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}
+ URL https://github.com/gflags/gflags/archive/v2.1.2.zip
+ URL_MD5 5cb0a1b38740ed596edb7f86cd5b3bd8
+ #--Update/Patch step----------
+ UPDATE_COMMAND ""
+ #--Configure step-------------
+ SOURCE_DIR ${SB_SOURCE_DIR}/${_proj_name}
+ CMAKE_ARGS
+ -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
+)
diff --git a/SuperBuild/cmake/External-Hexer.cmake b/SuperBuild/cmake/External-Hexer.cmake
new file mode 100644
index 000000000..64de1ae21
--- /dev/null
+++ b/SuperBuild/cmake/External-Hexer.cmake
@@ -0,0 +1,27 @@
+set(_proj_name hexer)
+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/hobu/hexer/archive/2898b96b1105991e151696391b9111610276258f.tar.gz
+ URL_MD5 e8f2788332ad212cf78efa81a82e95dd
+ #--Update/Patch step----------
+ UPDATE_COMMAND ""
+ #--Configure step-------------
+ SOURCE_DIR ${SB_SOURCE_DIR}/${_proj_name}
+ CMAKE_ARGS
+ -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
+)
diff --git a/SuperBuild/cmake/External-Lidar2dems.cmake b/SuperBuild/cmake/External-Lidar2dems.cmake
new file mode 100644
index 000000000..4772a2462
--- /dev/null
+++ b/SuperBuild/cmake/External-Lidar2dems.cmake
@@ -0,0 +1,24 @@
+set(_proj_name lidar2dems)
+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/OpenDroneMap/lidar2dems/archive/master.zip
+ #--Update/Patch step----------
+ UPDATE_COMMAND ""
+ #--Configure step-------------
+ SOURCE_DIR ${SB_SOURCE_DIR}/${_proj_name}
+ CONFIGURE_COMMAND ""
+ #--Build step-----------------
+ BUILD_COMMAND ""
+ #--Install step---------------
+ INSTALL_COMMAND "${SB_SOURCE_DIR}/${_proj_name}/install.sh" "${SB_INSTALL_DIR}"
+ #--Output logging-------------
+ LOG_DOWNLOAD OFF
+ LOG_CONFIGURE OFF
+ LOG_BUILD OFF
+)
diff --git a/SuperBuild/cmake/External-MvsTexturing.cmake b/SuperBuild/cmake/External-MvsTexturing.cmake
new file mode 100644
index 000000000..d637f682b
--- /dev/null
+++ b/SuperBuild/cmake/External-MvsTexturing.cmake
@@ -0,0 +1,29 @@
+set(_proj_name mvstexturing)
+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/OpenDroneMap/mvs-texturing/archive/4f885aff1d92fb20a7d72d320be5b935397c81c9.zip
+ URL_MD5 cbcccceba4693c6c882eb4aa618a2227
+ #--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
+)
diff --git a/SuperBuild/cmake/External-ORB_SLAM2.cmake b/SuperBuild/cmake/External-ORB_SLAM2.cmake
new file mode 100644
index 000000000..9e7047844
--- /dev/null
+++ b/SuperBuild/cmake/External-ORB_SLAM2.cmake
@@ -0,0 +1,78 @@
+set(_proj_name orb_slam2)
+set(_SB_BINARY_DIR "${SB_BINARY_DIR}/${_proj_name}")
+
+ExternalProject_Add(${_proj_name}
+ DEPENDS opencv pangolin
+ 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/paulinus/ORB_SLAM2/archive/7c11f186a53a75560cd17352d327b0bc127a82de.zip
+ #--Update/Patch step----------
+ UPDATE_COMMAND ""
+ #--Configure step-------------
+ SOURCE_DIR ${SB_SOURCE_DIR}/${_proj_name}
+ CMAKE_ARGS
+ -DCMAKE_INSTALL_PREFIX:PATH=${SB_INSTALL_DIR}
+ #--Build step-----------------
+ BINARY_DIR ${_SB_BINARY_DIR}
+ #--Install step---------------
+ INSTALL_COMMAND ""
+ #--Output logging-------------
+ LOG_DOWNLOAD OFF
+ LOG_CONFIGURE OFF
+ LOG_BUILD OFF
+)
+
+# DBoW2
+set(DBoW2_BINARY_DIR "${SB_BINARY_DIR}/DBoW2")
+file(MAKE_DIRECTORY "${DBoW2_BINARY_DIR}")
+
+ExternalProject_Add_Step(${_proj_name} build_DBoW2
+ COMMAND make -j2
+ DEPENDEES configure_DBoW2
+ DEPENDERS configure
+ WORKING_DIRECTORY ${DBoW2_BINARY_DIR}
+ ALWAYS 1
+)
+
+ExternalProject_Add_Step(${_proj_name} configure_DBoW2
+ COMMAND ${CMAKE_COMMAND} /Thirdparty/DBoW2
+ -DOpenCV_DIR=${SB_INSTALL_DIR}/share/OpenCV
+ -DCMAKE_BUILD_TYPE=Release
+ DEPENDEES download
+ DEPENDERS build_DBoW2
+ WORKING_DIRECTORY ${DBoW2_BINARY_DIR}
+ ALWAYS 1
+)
+
+# g2o
+set(g2o_BINARY_DIR "${SB_BINARY_DIR}/g2o")
+file(MAKE_DIRECTORY "${g2o_BINARY_DIR}")
+
+ExternalProject_Add_Step(${_proj_name} build_g2o
+ COMMAND make -j2
+ DEPENDEES configure_g2o
+ DEPENDERS configure
+ WORKING_DIRECTORY ${g2o_BINARY_DIR}
+ ALWAYS 1
+)
+
+ExternalProject_Add_Step(${_proj_name} configure_g2o
+ COMMAND ${CMAKE_COMMAND} /Thirdparty/g2o
+ -DCMAKE_BUILD_TYPE=Release
+ DEPENDEES download
+ DEPENDERS build_g2o
+ WORKING_DIRECTORY ${g2o_BINARY_DIR}
+ ALWAYS 1
+)
+
+# Uncompress Vocabulary
+ExternalProject_Add_Step(${_proj_name} uncompress_vocabulary
+ COMMAND tar -xf ORBvoc.txt.tar.gz
+ DEPENDEES download
+ DEPENDERS configure
+ WORKING_DIRECTORY /Vocabulary
+ ALWAYS 1
+)
diff --git a/SuperBuild/cmake/External-OpenCV.cmake b/SuperBuild/cmake/External-OpenCV.cmake
new file mode 100644
index 000000000..232059c9e
--- /dev/null
+++ b/SuperBuild/cmake/External-OpenCV.cmake
@@ -0,0 +1,60 @@
+set(_proj_name opencv)
+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}
+ URL https://github.com/Itseez/opencv/archive/2.4.11.zip
+ URL_MD5 b517e83489c709eee1d8be76b16976a7
+ #--Update/Patch step----------
+ UPDATE_COMMAND ""
+ #--Configure step-------------
+ SOURCE_DIR ${SB_SOURCE_DIR}/${_proj_name}
+ CMAKE_ARGS
+ -DBUILD_opencv_core=ON
+ -DBUILD_opencv_imgproc=ON
+ -DBUILD_opencv_highgui=ON
+ -DBUILD_opencv_video=ON
+ -DBUILD_opencv_ml=ON
+ -DBUILD_opencv_features2d=ON
+ -DBUILD_opencv_calib3d=ON
+ -DBUILD_opencv_contrib=ON
+ -DBUILD_opencv_flann=ON
+ -DBUILD_opencv_objdetect=ON
+ -DBUILD_opencv_photo=ON
+ -DBUILD_opencv_legacy=ON
+ -DBUILD_opencv_python=ON
+ -DWITH_FFMPEG=${ODM_BUILD_SLAM}
+ -DWITH_CUDA=OFF
+ -DWITH_GTK=${ODM_BUILD_SLAM}
+ -DWITH_VTK=OFF
+ -DWITH_EIGEN=OFF
+ -DWITH_OPENNI=OFF
+ -DBUILD_EXAMPLES=OFF
+ -DBUILD_TESTS=OFF
+ -DBUILD_PERF_TESTS=OFF
+ -DBUILD_DOCS=OFF
+ -DBUILD_opencv_apps=OFF
+ -DBUILD_opencv_gpu=OFF
+ -DBUILD_opencv_videostab=OFF
+ -DBUILD_opencv_nonfree=OFF
+ -DBUILD_opencv_stitching=OFF
+ -DBUILD_opencv_world=OFF
+ -DBUILD_opencv_superres=OFF
+ -DBUILD_opencv_java=OFF
+ -DBUILD_opencv_ocl=OFF
+ -DBUILD_opencv_ts=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
+)
diff --git a/SuperBuild/cmake/External-OpenGV.cmake b/SuperBuild/cmake/External-OpenGV.cmake
new file mode 100644
index 000000000..cd1ac76de
--- /dev/null
+++ b/SuperBuild/cmake/External-OpenGV.cmake
@@ -0,0 +1,29 @@
+set(_proj_name opengv)
+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}
+ URL https://github.com/paulinus/opengv/archive/7436794df04d85433a966395088e38b107e69fc2.zip
+ URL_MD5 9B303C3AB9F210B242941E851572D2C8
+ #--Update/Patch step----------
+ UPDATE_COMMAND ""
+ #--Configure step-------------
+ SOURCE_DIR ${SB_SOURCE_DIR}/${_proj_name}
+ CMAKE_ARGS
+ -DBUILD_TESTS=OFF
+ -DBUILD_PYTHON=ON
+ -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
+)
+
diff --git a/SuperBuild/cmake/External-OpenSfM.cmake b/SuperBuild/cmake/External-OpenSfM.cmake
new file mode 100644
index 000000000..9fa30f422
--- /dev/null
+++ b/SuperBuild/cmake/External-OpenSfM.cmake
@@ -0,0 +1,31 @@
+set(_proj_name opensfm)
+set(_SB_BINARY_DIR "${SB_BINARY_DIR}/${_proj_name}")
+
+ExternalProject_Add(${_proj_name}
+ DEPENDS ceres opencv opengv
+ 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/mapillary/OpenSfM/archive/93be3a1bfe46482345ddd57bc1f3a62f63169b86.zip
+ URL_MD5 2b310420a5c7c2297294a39183fb8b1a
+ #--Update/Patch step----------
+ UPDATE_COMMAND ""
+ #--Configure step-------------
+ SOURCE_DIR ${SB_SOURCE_DIR}/${_proj_name}
+ CONFIGURE_COMMAND cmake /${_proj_name}/src
+ -DCERES_ROOT_DIR=${SB_INSTALL_DIR}
+ -DOpenCV_DIR=${SB_INSTALL_DIR}/share/OpenCV
+ -DOPENSFM_BUILD_TESTS=off
+
+ #--Build step-----------------
+ BINARY_DIR ${_SB_BINARY_DIR}
+ #--Install step---------------
+ INSTALL_COMMAND ""
+ #--Output logging-------------
+ LOG_DOWNLOAD OFF
+ LOG_CONFIGURE OFF
+ LOG_BUILD OFF
+)
+
diff --git a/SuperBuild/cmake/External-PCL.cmake b/SuperBuild/cmake/External-PCL.cmake
new file mode 100644
index 000000000..50d7c1df6
--- /dev/null
+++ b/SuperBuild/cmake/External-PCL.cmake
@@ -0,0 +1,52 @@
+set(_proj_name pcl)
+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}
+ URL https://github.com/PointCloudLibrary/pcl/archive/pcl-1.8.0.tar.gz
+ URL_MD5 8c1308be2c13106e237e4a4204a32cca
+ #--Update/Patch step----------
+ UPDATE_COMMAND ""
+ #--Configure step-------------
+ SOURCE_DIR ${SB_SOURCE_DIR}/${_proj_name}
+ CMAKE_ARGS
+ -DBUILD_features=OFF
+ -DBUILD_filters=OFF
+ -DBUILD_geometry=OFF
+ -DBUILD_keypoints=OFF
+ -DBUILD_outofcore=OFF
+ -DBUILD_people=OFF
+ -DBUILD_recognition=OFF
+ -DBUILD_registration=OFF
+ -DBUILD_sample_consensus=OFF
+ -DBUILD_segmentation=OFF
+ -DBUILD_features=OFF
+ -DBUILD_surface_on_nurbs=OFF
+ -DBUILD_tools=OFF
+ -DBUILD_tracking=OFF
+ -DBUILD_visualization=OFF
+ -DWITH_QT=OFF
+ -DBUILD_OPENNI=OFF
+ -DBUILD_OPENNI2=OFF
+ -DWITH_OPENNI=OFF
+ -DWITH_OPENNI2=OFF
+ -DWITH_FZAPI=OFF
+ -DWITH_LIBUSB=OFF
+ -DWITH_PCAP=OFF
+ -DWITH_PXCAPI=OFF
+ -DCMAKE_BUILD_TYPE=Release
+ -DPCL_VERBOSITY_LEVEL=Error
+ -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
+)
\ No newline at end of file
diff --git a/SuperBuild/cmake/External-PDAL.cmake b/SuperBuild/cmake/External-PDAL.cmake
new file mode 100644
index 000000000..d1fb938d3
--- /dev/null
+++ b/SuperBuild/cmake/External-PDAL.cmake
@@ -0,0 +1,47 @@
+set(_proj_name pdal)
+set(_SB_BINARY_DIR "${SB_BINARY_DIR}/${_proj_name}")
+
+ExternalProject_Add(${_proj_name}
+ DEPENDS hexer
+ 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/PDAL/PDAL/archive/e881b581e3b91a928105d67db44c567f3b6d1afe.tar.gz
+ URL_MD5 cadbadf1c83d69d6525cfffd41473323
+ #--Update/Patch step----------
+ UPDATE_COMMAND ""
+ #--Configure step-------------
+ SOURCE_DIR ${SB_SOURCE_DIR}/${_proj_name}
+ CMAKE_ARGS
+ -BUILD_PGPOINTCLOUD_TESTS=OFF
+ -BUILD_PLUGIN_PCL=ON
+ -BUILD_PLUGIN_PGPOINTCLOUD=ON
+ -DBUILD_PLUGIN_CPD=OFF
+ -DBUILD_PLUGIN_GREYHOUND=OFF
+ -DBUILD_PLUGIN_HEXBIN=ON
+ -DBUILD_PLUGIN_ICEBRIDGE=OFF
+ -DBUILD_PLUGIN_MRSID=OFF
+ -DBUILD_PLUGIN_NITF=OFF
+ -DBUILD_PLUGIN_OCI=OFF
+ -DBUILD_PLUGIN_P2G=OFF
+ -DBUILD_PLUGIN_SQLITE=OFF
+ -DBUILD_PLUGIN_RIVLIB=OFF
+ -DBUILD_PLUGIN_PYTHON=OFF
+ -DENABLE_CTEST=OFF
+ -DWITH_APPS=ON
+ -DWITH_LAZPERF=OFF
+ -DWITH_GEOTIFF=ON
+ -DWITH_LASZIP=ON
+ -DWITH_TESTS=OFF
+ -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
+)
diff --git a/SuperBuild/cmake/External-Pangolin.cmake b/SuperBuild/cmake/External-Pangolin.cmake
new file mode 100644
index 000000000..f328c89b4
--- /dev/null
+++ b/SuperBuild/cmake/External-Pangolin.cmake
@@ -0,0 +1,29 @@
+set(_proj_name pangolin)
+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}
+ URL https://github.com/paulinus/Pangolin/archive/b7c66570b336e012bf3124e2a7411d417a1d35f7.zip
+ URL_MD5 9b7938d1045d26b27a637b663e647aef
+ #--Update/Patch step----------
+ UPDATE_COMMAND ""
+ #--Configure step-------------
+ SOURCE_DIR ${SB_SOURCE_DIR}/${_proj_name}
+ CMAKE_ARGS
+ -DCPP11_NO_BOOST=1
+ -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
+)
+
diff --git a/SuperBuild/cmake/ExternalProject-Setup.cmake b/SuperBuild/cmake/ExternalProject-Setup.cmake
new file mode 100644
index 000000000..eea0b5339
--- /dev/null
+++ b/SuperBuild/cmake/ExternalProject-Setup.cmake
@@ -0,0 +1,27 @@
+set(ADD_INTERNAL_LIB_MSG "--- Adding internal version")
+set(FORCE_BUILD_LIB_MSG "force build ${ADD_INTERNAL_LIB_MSG}")
+
+macro(SETUP_EXTERNAL_PROJECT name version force_build)
+
+ if(NOT ${force_build})
+
+ find_package(${name} ${version} EXACT QUIET)
+
+ if(${${name}_FOUND})
+ message(STATUS "${name} ${${name}_VERSION} found")
+ set(${name}_DIR ${${name}_DIR})
+ else()
+ message(STATUS "${name} ${version} not found ${ADD_INTERNAL_LIB_MSG}")
+ include(External-${name})
+ endif()
+ else()
+ message(STATUS "${name} ${version} ${FORCE_BUILD_LIB_MSG}")
+ include(External-${name})
+ endif()
+
+endmacro()
+
+macro(SETUP_EXTERNAL_PROJECT_CUSTOM name)
+ message(STATUS "${name} ${FORCE_BUILD_LIB_MSG}")
+ include(External-${name})
+endmacro()
\ No newline at end of file
diff --git a/VERSION b/VERSION
new file mode 100644
index 000000000..9e11b32fc
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+0.3.1
diff --git a/ccd_defs.pl b/ccd_defs.pl
deleted file mode 100644
index edb5508e8..000000000
--- a/ccd_defs.pl
+++ /dev/null
@@ -1,277 +0,0 @@
-#!/usr/bin/perl
-
-%ccdWidths = (
- "Asahi Optical Co.,Ltd. PENTAX Optio330RS" => 7.176, # 1/1.8"
- "Canon Canon DIGITAL IXUS 400" => 7.176, # 1/1.8"
- "Canon Canon DIGITAL IXUS 40" => 5.76, # 1/2.5"
- "Canon Canon DIGITAL IXUS 430" => 7.176, # 1/1.8"
- "Canon Canon DIGITAL IXUS 500" => 7.176, # 1/1.8"
- "Canon Canon DIGITAL IXUS 50" => 5.76, # 1/2.5"
- "Canon Canon DIGITAL IXUS 55" => 5.76, # 1/2.5"
- "Canon Canon DIGITAL IXUS 60" => 5.76, # 1/2.5"
- "Canon Canon DIGITAL IXUS 65" => 5.76, # 1/2.5"
- "Canon Canon DIGITAL IXUS 700" => 7.176, # 1/1.8"
- "Canon Canon DIGITAL IXUS 750" => 7.176, # 1/1.8"
- "Canon Canon DIGITAL IXUS 800 IS" => 5.76, # 1/2.5"
- "Canon Canon DIGITAL IXUS II" => 5.27, # 1/2.7"
- "Canon Canon DIGITAL IXUS 430" => 6.18, # 1/2.3"
- "Canon Canon EOS 10D" => 22.7,
- "Canon Canon EOS-1D Mark II" => 28.7,
- "Canon Canon EOS-1Ds Mark II" => 35.95,
- "Canon Canon EOS 20D" => 22.5,
- "Canon Canon EOS 20D" => 22.5,
- "Canon Canon EOS 300D DIGITAL" => 22.66,
- "Canon Canon EOS 30D" => 22.5,
- "Canon Canon EOS 350D DIGITAL" => 22.2,
- "Canon Canon EOS 400D DIGITAL" => 22.2,
- "Canon Canon EOS 40D" => 22.2,
- "Canon Canon EOS 5D" => 35.8,
- "Canon Canon EOS DIGITAL REBEL" => 22.66,
- "Canon Canon EOS DIGITAL REBEL XT" => 22.2,
- "Canon Canon EOS DIGITAL REBEL XTi" => 22.2,
- "Canon Canon EOS Kiss Digital" => 22.66,
- "Canon Canon IXY DIGITAL 600" => 7.176, # 1/1.8"
- "Canon Canon PowerShot A10" => 5.23, # 1/1.8"
- "Canon Canon PowerShot A20" => 7.176, # 1/1.8"
- "Canon Canon PowerShot A400" => 4.54, # 1/3.2"
- "Canon Canon PowerShot A40" => 5.27, # 1/2.7"
- "Canon Canon PowerShot A510" => 5.76, # 1/2.5"
- "Canon Canon PowerShot A520" => 5.76, # 1/2.5"
- "Canon Canon PowerShot A530" => 5.76, # 1/2.5"
- "Canon Canon PowerShot A60" => 5.27, # 1/2.7"
- "Canon Canon PowerShot A620" => 7.176, # 1/1.8"
- "Canon Canon PowerShot A630" => 7.176, # 1/1.8"
- "Canon Canon PowerShot A640" => 7.176, # 1/1.8"
- "Canon Canon PowerShot A700" => 5.76, # 1/2.5"
- "Canon Canon PowerShot A70" => 5.27, # 1/2.7"
- "Canon Canon PowerShot A710 IS" => 5.76, # 1/2.5"
- "Canon Canon PowerShot A75" => 5.27, # 1/2.7"
- "Canon Canon PowerShot A80" => 7.176, # 1/1.8"
- "Canon Canon PowerShot A85" => 5.27, # 1/2.7"
- "Canon Canon PowerShot A95" => 7.176, # 1/1.8"
- "Canon Canon PowerShot G1" => 7.176, # 1/1.8"
- "Canon Canon PowerShot G2" => 7.176, # 1/1.8"
- "Canon Canon PowerShot G3" => 7.176, # 1/1.8"
- "Canon Canon PowerShot G5" => 7.176, # 1/1.8"
- "Canon Canon PowerShot G6" => 7.176, # 1/1.8"
- "Canon Canon PowerShot G7" => 7.176, # 1/1.8"
- "Canon Canon PowerShot G9" => 7.600, # 1/1.7"
- "Canon Canon PowerShot Pro1" => 8.8, # 2/3"
- "Canon Canon PowerShot S110" => 5.27, # 1/2.7"
- "Canon Canon PowerShot S1 IS" => 5.27, # 1/2.7"
- "Canon Canon PowerShot S200" => 5.27, # 1/2.7"
- "Canon Canon PowerShot S2 IS" => 5.76, # 1/2.5"
- "Canon Canon PowerShot S30" => 7.176, # 1/1.8"
- "Canon Canon PowerShot S3 IS" => 5.76, # 1/2.5"
- "Canon Canon PowerShot S400" => 7.176, # 1/1.8"
- "Canon Canon PowerShot S40" => 7.176, # 1/1.8"
- "Canon Canon PowerShot S410" => 7.176, # 1/1.8"
- "Canon Canon PowerShot S45" => 7.176, # 1/1.8"
- "Canon Canon PowerShot S500" => 7.176, # 1/1.8"
- "Canon Canon PowerShot S50" => 7.176, # 1/1.8"
- "Canon Canon PowerShot S60" => 7.176, # 1/1.8"
- "Canon Canon PowerShot S70" => 7.176, # 1/1.8"
- "Canon Canon PowerShot S80" => 7.176, # 1/1.8"
- "Canon Canon PowerShot SD1000" => 5.75, # 1/2.5"
- "Canon Canon PowerShot SD100" => 5.27, # 1/2.7"
- "Canon Canon PowerShot SD10" => 5.75, # 1/2.5"
- "Canon Canon PowerShot SD110" => 5.27, # 1/2.7"
- "Canon Canon PowerShot SD200" => 5.76, # 1/2.5"
- "Canon Canon PowerShot SD300" => 5.76, # 1/2.5"
- "Canon Canon PowerShot SD400" => 5.76, # 1/2.5"
- "Canon Canon PowerShot SD450" => 5.76, # 1/2.5"
- "Canon Canon PowerShot SD500" => 7.176, # 1/1.8"
- "Canon Canon PowerShot SD550" => 7.176, # 1/1.8"
- "Canon Canon PowerShot SD600" => 5.76, # 1/2.5"
- "Canon Canon PowerShot SD630" => 5.76, # 1/2.5"
- "Canon Canon PowerShot SD700 IS" => 5.76, # 1/2.5"
- "Canon Canon PowerShot SD750" => 5.75, # 1/2.5"
- "Canon Canon PowerShot SD800 IS" => 5.76, # 1/2.5"
- "Canon EOS 300D DIGITAL" => 22.66,
- "Canon EOS DIGITAL REBEL" => 22.66,
- "Canon PowerShot A510" => 5.76, # 1/2.5" ???
- "Canon PowerShot S30" => 7.176, # 1/1.8"
- "CASIO COMPUTER CO.,LTD. EX-S500" => 5.76, # 1/2.5"
- "CASIO COMPUTER CO.,LTD. EX-Z1000" => 7.716, # 1/1.8"
- "CASIO COMPUTER CO.,LTD EX-Z30" => 5.76, # 1/2.5 "
- "CASIO COMPUTER CO.,LTD. EX-Z600" => 5.76, # 1/2.5"
- "CASIO COMPUTER CO.,LTD. EX-Z60" => 7.176, # 1/1.8"
- "CASIO COMPUTER CO.,LTD EX-Z750" => 7.176, # 1/1.8"
- "CASIO COMPUTER CO.,LTD. EX-Z850" => 7.176,
- "EASTMAN KODAK COMPANY KODAK CX7330 ZOOM DIGITAL CAMERA" => 5.27, # 1/2.7"
- "EASTMAN KODAK COMPANY KODAK CX7530 ZOOM DIGITAL CAMERA" => 5.76, # 1/2.5"
- "EASTMAN KODAK COMPANY KODAK DX3900 ZOOM DIGITAL CAMERA" => 7.176, # 1/1.8"
- "EASTMAN KODAK COMPANY KODAK DX4900 ZOOM DIGITAL CAMERA" => 7.176, # 1/1.8"
- "EASTMAN KODAK COMPANY KODAK DX6340 ZOOM DIGITAL CAMERA" => 5.27, # 1/2.7"
- "EASTMAN KODAK COMPANY KODAK DX6490 ZOOM DIGITAL CAMERA" => 5.76, # 1/2.5"
- "EASTMAN KODAK COMPANY KODAK DX7630 ZOOM DIGITAL CAMERA" => 7.176, # 1/1.8"
- "EASTMAN KODAK COMPANY KODAK Z650 ZOOM DIGITAL CAMERA" => 5.76, # 1/2.5"
- "EASTMAN KODAK COMPANY KODAK Z700 ZOOM DIGITAL CAMERA" => 5.76, # 1/2.5"
- "EASTMAN KODAK COMPANY KODAK Z740 ZOOM DIGITAL CAMERA" => 5.76, # 1/2.5"
- "EASTMAN KODAK COMPANY KODAK Z740 ZOOM DIGITAL CAMERA" => 5.76, # 1/2.5" ?
- "FUJIFILM FinePix2600Zoom" => 5.27, # 1/2.7"
- "FUJIFILM FinePix40i" => 7.600, # 1/1.7"
- "FUJIFILM FinePix A310" => 5.27, # 1/2.7"
- "FUJIFILM FinePix A330" => 5.27, # 1/2.7"
- "FUJIFILM FinePix A600" => 7.600, # 1/1.7"
- "FUJIFILM FinePix E500" => 5.76, # 1/2.5"
- "FUJIFILM FinePix E510" => 5.76, # 1/2.5"
- "FUJIFILM FinePix E550" => 7.600, # 1/1.7"
- "FUJIFILM FinePix E900" => 7.78, # 1/1.6"
- "FUJIFILM FinePix F10" => 7.600, # 1/1.7"
- "FUJIFILM FinePix F30" => 7.600, # 1/1.7"
- "FUJIFILM FinePix F450" => 5.76, # 1/2.5"
- "FUJIFILM FinePix F601 ZOOM" => 7.600, # 1/1.7"
- "FUJIFILM FinePix S3Pro" => 23.0,
- "FUJIFILM FinePix S5000" => 5.27, # 1/2.7"
- "FUJIFILM FinePix S5200" => 5.76, # 1/2.5"
- "FUJIFILM FinePix S5500" => 5.27, # 1/2.7"
- "FUJIFILM FinePix S6500fd" => 7.600, # 1/1.7"
- "FUJIFILM FinePix S7000" => 7.600, # 1/1.7"
- "FUJIFILM FinePix Z2" => 5.76, # 1/2.5"
- "Hewlett-Packard hp 635 Digital Camera" => 4.54, # 1/3.2"
- "Hewlett-Packard hp PhotoSmart 43x series" => 5.27, # 1/2.7"
- "Hewlett-Packard HP PhotoSmart 618 (V1.1)" => 5.27, # 1/2.7"
- "Hewlett-Packard HP PhotoSmart C945 (V01.61)" => 7.176, # 1/1.8"
- "Hewlett-Packard HP PhotoSmart R707 (V01.00)" => 7.176, # 1/1.8"
- "KONICA MILOLTA DYNAX 5D" => 23.5,
- "Konica Minolta Camera, Inc. DiMAGE A2" => 8.80, # 2/3"
- "KONICA MINOLTA CAMERA, Inc. DiMAGE G400" => 5.76, # 1/2.5"
- "Konica Minolta Camera, Inc. DiMAGE Z2" => 5.76, # 1/2.5"
- "KONICA MINOLTA DiMAGE A200" => 8.80, # 2/3"
- "KONICA MINOLTA DiMAGE X1" => 7.176, # 1/1.8"
- "KONICA MINOLTA DYNAX 5D" => 23.5,
- "Minolta Co., Ltd. DiMAGE F100" => 7.176, # 1/2.7"
- "Minolta Co., Ltd. DiMAGE Xi" => 5.27, # 1/2.7"
- "Minolta Co., Ltd. DiMAGE Xt" => 5.27, # 1/2.7"
- "Minolta Co., Ltd. DiMAGE Z1" => 5.27, # 1/2.7"
- "NIKON COOLPIX L3" => 5.76, # 1/2.5"
- "NIKON COOLPIX P2" => 7.176, # 1/1.8"
- "NIKON COOLPIX S4" => 5.76, # 1/2.5"
- "NIKON COOLPIX S7c" => 5.76, # 1/2.5"
- "NIKON CORPORATION NIKON D100" => 23.7,
- "NIKON CORPORATION NIKON D1" => 23.7,
- "NIKON CORPORATION NIKON D1H" => 23.7,
- "NIKON CORPORATION NIKON D200" => 23.6,
- "NIKON CORPORATION NIKON D2H" => 23.3,
- "NIKON CORPORATION NIKON D2X" => 23.7,
- "NIKON CORPORATION NIKON D40" => 23.7,
- "NIKON CORPORATION NIKON D50" => 23.7,
- "NIKON CORPORATION NIKON D60" => 23.6,
- "NIKON CORPORATION NIKON D70" => 23.7,
- "NIKON CORPORATION NIKON D70s" => 23.7,
- "NIKON CORPORATION NIKON D80" => 23.6,
- "NIKON CORPORATION NIKON D700" => 36.0,
- "NIKON E2500" => 5.27, # 1/2.7"
- "NIKON E2500" => 5.27, # 1/2.7"
- "NIKON E3100" => 5.27, # 1/2.7"
- "NIKON E3200" => 5.27,
- "NIKON E3700" => 5.27, # 1/2.7"
- "NIKON E4200" => 7.176, # 1/1.8"
- "NIKON E4300" => 7.18,
- "NIKON E4500" => 7.176, # 1/1.8"
- "NIKON E4600" => 5.76, # 1/2.5"
- "NIKON E5000" => 8.80, # 2/3"
- "NIKON E5200" => 7.176, # 1/1.8"
- "NIKON E5400" => 7.176, # 1/1.8"
- "NIKON E5600" => 5.76, # 1/2.5"
- "NIKON E5700" => 8.80, # 2/3"
- "NIKON E5900" => 7.176, # 1/1.8"
- "NIKON E7600" => 7.176, # 1/1.8"
- "NIKON E775" => 5.27, # 1/2.7"
- "NIKON E7900" => 7.176, # 1/1.8"
- "NIKON E7900" => 7.176, # 1/1.8"
- "NIKON E8800" => 8.80, # 2/3"
- "NIKON E990" => 7.176, # 1/1.8"
- "NIKON E995" => 7.176, # 1/1.8"
- "NIKON S1" => 5.76, # 1/2.5"
- "Nokia N80" => 5.27, # 1/2.7"
- "Nokia N80" => 5.27, # 1/2.7"
- "Nokia N93" => 4.536, # 1/3.1"
- "Nokia N95" => 5.7, # 1/2.7"
- "OLYMPUS CORPORATION C-5000Z" => 7.176, # 1/1.8"
- "OLYMPUS CORPORATION C5060WZ" => 7.176, # 1/1.8"
- "OLYMPUS CORPORATION C750UZ" => 5.27, # 1/2.7"
- "OLYMPUS CORPORATION C765UZ" => 5.76, # 1//2.5"
- "OLYMPUS CORPORATION C8080WZ" => 8.80, # 2/3"
- "OLYMPUS CORPORATION X250,D560Z,C350Z" => 5.76, # 1/2.5"
- "OLYMPUS CORPORATION X-3,C-60Z" => 7.176, # 1.8"
- "OLYMPUS CORPORATION X400,D580Z,C460Z" => 5.27, # 1/2.7"
- "OLYMPUS IMAGING CORP. E-500" => 17.3, # 4/3?
- "OLYMPUS IMAGING CORP. E-510" => 17.3,
- "OLYMPUS IMAGING CORP. FE115,X715" => 5.76, # 1/2.5"
- "OLYMPUS IMAGING CORP. SP310" => 7.176, # 1/1.8"
- "OLYMPUS IMAGING CORP. SP510UZ" => 5.75, # 1/2.5"
- "OLYMPUS IMAGING CORP. SP550UZ" => 5.76, # 1/2.5"
- "OLYMPUS IMAGING CORP. uD600,S600" => 5.75, # 1/2.5"
- "OLYMPUS_IMAGING_CORP. X450,D535Z,C370Z" => 5.27, # 1/2.7"
- "OLYMPUS IMAGING CORP. X550,D545Z,C480Z" => 5.76, # 1/2.5"
- "OLYMPUS OPTICAL CO.,LTD C2040Z" => 6.40, # 1/2"
- "OLYMPUS OPTICAL CO.,LTD C211Z" => 5.27, # 1/2.7"
- "OLYMPUS OPTICAL CO.,LTD C2Z,D520Z,C220Z" => 4.54, # 1/3.2"
- "OLYMPUS OPTICAL CO.,LTD C3000Z" => 7.176, # 1/1.8"
- "OLYMPUS OPTICAL CO.,LTD C300Z,D550Z" => 5.4,
- "OLYMPUS OPTICAL CO.,LTD C4100Z,C4000Z" => 7.176, # 1/1.8"
- "OLYMPUS OPTICAL CO.,LTD C750UZ" => 5.27, # 1/2.7"
- "OLYMPUS OPTICAL CO.,LTD X-2,C-50Z" => 7.176, # 1/1.8"
- "OLYMPUS SP550UZ" => 5.76, # 1/2.5"
- "OLYMPUS X100,D540Z,C310Z" => 5.27, # 1/2.7"
- "Panasonic DMC-FX01" => 5.76, # 1/2.5"
- "Panasonic DMC-FX07" => 5.75, # 1/2.5"
- "Panasonic DMC-FX9" => 5.76, # 1/2.5"
- "Panasonic DMC-FZ20" => 5.760, # 1/2.5"
- "Panasonic DMC-FZ2" => 4.54, # 1/3.2"
- "Panasonic DMC-FZ30" => 7.176, # 1/1.8"
- "Panasonic DMC-FZ50" => 7.176, # 1/1.8"
- "Panasonic DMC-FZ5" => 5.760, # 1/2.5"
- "Panasonic DMC-FZ7" => 5.76, # 1/2.5"
- "Panasonic DMC-LC1" => 8.80, # 2/3"
- "Panasonic DMC-LC33" => 5.760, # 1/2.5"
- "Panasonic DMC-LX1" => 8.50, # 1/6.5"
- "Panasonic DMC-LZ2" => 5.76, # 1/2.5"
- "Panasonic DMC-TZ1" => 5.75, # 1/2.5"
- "Panasonic DMC-TZ3" => 5.68, # 1/2.35"
- "Panasonic DMC-TZ5" => 6.12, # 1/2.33"
- "PENTAX Corporation PENTAX *ist DL" => 23.5,
- "PENTAX Corporation PENTAX *ist DS2" => 23.5,
- "PENTAX Corporation PENTAX *ist DS" => 23.5,
- "PENTAX Corporation PENTAX K100D" => 23.5,
- "PENTAX Corporation PENTAX Optio 450" => 7.176, # 1/1.8"
- "PENTAX Corporation PENTAX Optio 550" => 7.176, # 1/1.8"
- "PENTAX Corporation PENTAX Optio E10" => 5.76, # 1/2.5"
- "PENTAX Corporation PENTAX Optio S40" => 5.76, # 1/2.5"
- "PENTAX Corporation PENTAX Optio S4" => 5.76, # 1/2.5"
- "PENTAX Corporation PENTAX Optio S50" => 5.76, # 1/2.5"
- "PENTAX Corporation PENTAX Optio S5i" => 5.76, # 1/2.5"
- "PENTAX Corporation PENTAX Optio S5z" => 5.76, # 1/2.5"
- "PENTAX Corporation PENTAX Optio SV" => 5.76, # 1/2.5"
- "PENTAX Corporation PENTAX Optio WP" => 5.75, # 1/2.5"
- "RICOH CaplioG3 modelM" => 5.27, # 1/2.7"
- "RICOH Caplio GX" => 7.176, # 1/1.8"
- "RICOH Caplio R30" => 5.75, # 1/2.5"
- "Samsung Digimax 301" => 5.27, # 1/2.7"
- "Samsung Techwin " => 5.76, # 1/2.5"
- "SAMSUNG TECHWIN Pro 815" => 8.80, # 2/3"
- "SONY DSC-F828" => 8.80, # 2/3"
- "SONY DSC-N12" => 7.176, # 1/1.8"
- "SONY DSC-P100" => 7.176, # 1/1.8"
- "SONY DSC-P10" => 7.176, # 1/1.8"
- "SONY DSC-P12" => 7.176, # 1/1.8"
- "SONY DSC-P150" => 7.176, # 1/1.8"
- "SONY DSC-P200" => 7.176, # 1/1.8");
- "SONY DSC-P52" => 5.27, # 1/2.7"
- "SONY DSC-P72" => 5.27, # 1/2.7"
- "SONY DSC-P73" => 5.27,
- "SONY DSC-P8" => 5.27, # 1/2.7"
- "SONY DSC-R1" => 21.5,
- "SONY DSC-S40" => 5.27, # 1/2.7"
- "SONY DSC-S600" => 5.760, # 1/2.5"
- "SONY DSC-T9" => 7.18,
- "SONY DSC-V1" => 7.176, # 1/1.8"
- "SONY DSC-W1" => 7.176, # 1/1.8"
- "SONY DSC-W30" => 5.760, # 1/2.5"
- "SONY DSC-W50" => 5.75, # 1/2.5"
- "SONY DSC-W5" => 7.176, # 1/1.8"
- "SONY DSC-W7" => 7.176, # 1/1.8"
- "SONY DSC-W80" => 5.75, # 1/2.5"
-);
diff --git a/ccd_defs.rb b/ccd_defs.rb
deleted file mode 100644
index 3e7f1486b..000000000
--- a/ccd_defs.rb
+++ /dev/null
@@ -1,278 +0,0 @@
-#!/usr/bin/ruby
-
-$ccd_widths = {
- :"Asahi Optical Co.,Ltd. PENTAX Optio330RS" => 7.176, # 1/1.8"
- :"Canon Canon DIGITAL IXUS 400" => 7.176, # 1/1.8"
- :"Canon Canon DIGITAL IXUS 40" => 5.76, # 1/2.5"
- :"Canon Canon DIGITAL IXUS 430" => 7.176, # 1/1.8"
- :"Canon Canon DIGITAL IXUS 500" => 7.176, # 1/1.8"
- :"Canon Canon DIGITAL IXUS 50" => 5.76, # 1/2.5"
- :"Canon Canon DIGITAL IXUS 55" => 5.76, # 1/2.5"
- :"Canon Canon DIGITAL IXUS 60" => 5.76, # 1/2.5"
- :"Canon Canon DIGITAL IXUS 65" => 5.76, # 1/2.5"
- :"Canon Canon DIGITAL IXUS 700" => 7.176, # 1/1.8"
- :"Canon Canon DIGITAL IXUS 750" => 7.176, # 1/1.8"
- :"Canon Canon DIGITAL IXUS 800 IS" => 5.76, # 1/2.5"
- :"Canon Canon DIGITAL IXUS II" => 5.27, # 1/2.7"
- :"Canon Canon DIGITAL IXUS 430" => 6.18, # 1/2.3"
- :"Canon Canon EOS 10D" => 22.7,
- :"Canon Canon EOS-1D Mark II" => 28.7,
- :"Canon Canon EOS-1Ds Mark II" => 35.95,
- :"Canon Canon EOS 20D" => 22.5,
- :"Canon Canon EOS 20D" => 22.5,
- :"Canon Canon EOS 300D DIGITAL" => 22.66,
- :"Canon Canon EOS 30D" => 22.5,
- :"Canon Canon EOS 350D DIGITAL" => 22.2,
- :"Canon Canon EOS 400D DIGITAL" => 22.2,
- :"Canon Canon EOS 40D" => 22.2,
- :"Canon Canon EOS 5D" => 35.8,
- :"Canon Canon EOS DIGITAL REBEL" => 22.66,
- :"Canon Canon EOS DIGITAL REBEL XT" => 22.2,
- :"Canon Canon EOS DIGITAL REBEL XTi" => 22.2,
- :"Canon Canon EOS Kiss Digital" => 22.66,
- :"Canon Canon IXY DIGITAL 600" => 7.176, # 1/1.8"
- :"Canon Canon PowerShot A10" => 5.23, # 1/1.8"
- :"Canon Canon PowerShot A20" => 7.176, # 1/1.8"
- :"Canon Canon PowerShot A400" => 4.54, # 1/3.2"
- :"Canon Canon PowerShot A40" => 5.27, # 1/2.7"
- :"Canon Canon PowerShot A510" => 5.76, # 1/2.5"
- :"Canon Canon PowerShot A520" => 5.76, # 1/2.5"
- :"Canon Canon PowerShot A530" => 5.76, # 1/2.5"
- :"Canon Canon PowerShot A60" => 5.27, # 1/2.7"
- :"Canon Canon PowerShot A620" => 7.176, # 1/1.8"
- :"Canon Canon PowerShot A630" => 7.176, # 1/1.8"
- :"Canon Canon PowerShot A640" => 7.176, # 1/1.8"
- :"Canon Canon PowerShot A700" => 5.76, # 1/2.5"
- :"Canon Canon PowerShot A70" => 5.27, # 1/2.7"
- :"Canon Canon PowerShot A710 IS" => 5.76, # 1/2.5"
- :"Canon Canon PowerShot A75" => 5.27, # 1/2.7"
- :"Canon Canon PowerShot A80" => 7.176, # 1/1.8"
- :"Canon Canon PowerShot A85" => 5.27, # 1/2.7"
- :"Canon Canon PowerShot A95" => 7.176, # 1/1.8"
- :"Canon Canon PowerShot G1" => 7.176, # 1/1.8"
- :"Canon Canon PowerShot G2" => 7.176, # 1/1.8"
- :"Canon Canon PowerShot G3" => 7.176, # 1/1.8"
- :"Canon Canon PowerShot G5" => 7.176, # 1/1.8"
- :"Canon Canon PowerShot G6" => 7.176, # 1/1.8"
- :"Canon Canon PowerShot G7" => 7.176, # 1/1.8"
- :"Canon Canon PowerShot G9" => 7.600, # 1/1.7"
- :"Canon Canon PowerShot Pro1" => 8.8, # 2/3"
- :"Canon Canon PowerShot S110" => 5.27, # 1/2.7"
- :"Canon Canon PowerShot S1 IS" => 5.27, # 1/2.7"
- :"Canon Canon PowerShot S200" => 5.27, # 1/2.7"
- :"Canon Canon PowerShot S2 IS" => 5.76, # 1/2.5"
- :"Canon Canon PowerShot S30" => 7.176, # 1/1.8"
- :"Canon Canon PowerShot S3 IS" => 5.76, # 1/2.5"
- :"Canon Canon PowerShot S400" => 7.176, # 1/1.8"
- :"Canon Canon PowerShot S40" => 7.176, # 1/1.8"
- :"Canon Canon PowerShot S410" => 7.176, # 1/1.8"
- :"Canon Canon PowerShot S45" => 7.176, # 1/1.8"
- :"Canon Canon PowerShot S500" => 7.176, # 1/1.8"
- :"Canon Canon PowerShot S50" => 7.176, # 1/1.8"
- :"Canon Canon PowerShot S60" => 7.176, # 1/1.8"
- :"Canon Canon PowerShot S70" => 7.176, # 1/1.8"
- :"Canon Canon PowerShot S80" => 7.176, # 1/1.8"
- :"Canon Canon PowerShot SD1000" => 5.75, # 1/2.5"
- :"Canon Canon PowerShot SD100" => 5.27, # 1/2.7"
- :"Canon Canon PowerShot SD10" => 5.75, # 1/2.5"
- :"Canon Canon PowerShot SD110" => 5.27, # 1/2.7"
- :"Canon Canon PowerShot SD200" => 5.76, # 1/2.5"
- :"Canon Canon PowerShot SD300" => 5.76, # 1/2.5"
- :"Canon Canon PowerShot SD400" => 5.76, # 1/2.5"
- :"Canon Canon PowerShot SD450" => 5.76, # 1/2.5"
- :"Canon Canon PowerShot SD500" => 7.176, # 1/1.8"
- :"Canon Canon PowerShot SD550" => 7.176, # 1/1.8"
- :"Canon Canon PowerShot SD600" => 5.76, # 1/2.5"
- :"Canon Canon PowerShot SD630" => 5.76, # 1/2.5"
- :"Canon Canon PowerShot SD700 IS" => 5.76, # 1/2.5"
- :"Canon Canon PowerShot SD750" => 5.75, # 1/2.5"
- :"Canon Canon PowerShot SD800 IS" => 5.76, # 1/2.5"
- :"Canon EOS 300D DIGITAL" => 22.66,
- :"Canon EOS DIGITAL REBEL" => 22.66,
- :"Canon PowerShot A510" => 5.76, # 1/2.5" ???
- :"Canon PowerShot S30" => 7.176, # 1/1.8"
- :"CASIO COMPUTER CO.,LTD. EX-S500" => 5.76, # 1/2.5"
- :"CASIO COMPUTER CO.,LTD. EX-Z1000" => 7.716, # 1/1.8"
- :"CASIO COMPUTER CO.,LTD EX-Z30" => 5.76, # 1/2.5 "
- :"CASIO COMPUTER CO.,LTD. EX-Z600" => 5.76, # 1/2.5"
- :"CASIO COMPUTER CO.,LTD. EX-Z60" => 7.176, # 1/1.8"
- :"CASIO COMPUTER CO.,LTD EX-Z750" => 7.176, # 1/1.8"
- :"CASIO COMPUTER CO.,LTD. EX-Z850" => 7.176,
- :"EASTMAN KODAK COMPANY KODAK CX7330 ZOOM DIGITAL CAMERA" => 5.27, # 1/2.7"
- :"EASTMAN KODAK COMPANY KODAK CX7530 ZOOM DIGITAL CAMERA" => 5.76, # 1/2.5"
- :"EASTMAN KODAK COMPANY KODAK DX3900 ZOOM DIGITAL CAMERA" => 7.176, # 1/1.8"
- :"EASTMAN KODAK COMPANY KODAK DX4900 ZOOM DIGITAL CAMERA" => 7.176, # 1/1.8"
- :"EASTMAN KODAK COMPANY KODAK DX6340 ZOOM DIGITAL CAMERA" => 5.27, # 1/2.7"
- :"EASTMAN KODAK COMPANY KODAK DX6490 ZOOM DIGITAL CAMERA" => 5.76, # 1/2.5"
- :"EASTMAN KODAK COMPANY KODAK DX7630 ZOOM DIGITAL CAMERA" => 7.176, # 1/1.8"
- :"EASTMAN KODAK COMPANY KODAK Z650 ZOOM DIGITAL CAMERA" => 5.76, # 1/2.5"
- :"EASTMAN KODAK COMPANY KODAK Z700 ZOOM DIGITAL CAMERA" => 5.76, # 1/2.5"
- :"EASTMAN KODAK COMPANY KODAK Z740 ZOOM DIGITAL CAMERA" => 5.76, # 1/2.5"
- :"EASTMAN KODAK COMPANY KODAK Z740 ZOOM DIGITAL CAMERA" => 5.76, # 1/2.5" ?
- :"FUJIFILM FinePix2600Zoom" => 5.27, # 1/2.7"
- :"FUJIFILM FinePix40i" => 7.600, # 1/1.7"
- :"FUJIFILM FinePix A310" => 5.27, # 1/2.7"
- :"FUJIFILM FinePix A330" => 5.27, # 1/2.7"
- :"FUJIFILM FinePix A600" => 7.600, # 1/1.7"
- :"FUJIFILM FinePix E500" => 5.76, # 1/2.5"
- :"FUJIFILM FinePix E510" => 5.76, # 1/2.5"
- :"FUJIFILM FinePix E550" => 7.600, # 1/1.7"
- :"FUJIFILM FinePix E900" => 7.78, # 1/1.6"
- :"FUJIFILM FinePix F10" => 7.600, # 1/1.7"
- :"FUJIFILM FinePix F30" => 7.600, # 1/1.7"
- :"FUJIFILM FinePix F450" => 5.76, # 1/2.5"
- :"FUJIFILM FinePix F601 ZOOM" => 7.600, # 1/1.7"
- :"FUJIFILM FinePix S3Pro" => 23.0,
- :"FUJIFILM FinePix S5000" => 5.27, # 1/2.7"
- :"FUJIFILM FinePix S5200" => 5.76, # 1/2.5"
- :"FUJIFILM FinePix S5500" => 5.27, # 1/2.7"
- :"FUJIFILM FinePix S6500fd" => 7.600, # 1/1.7"
- :"FUJIFILM FinePix S7000" => 7.600, # 1/1.7"
- :"FUJIFILM FinePix Z2" => 5.76, # 1/2.5"
- :"Hewlett-Packard hp 635 Digital Camera" => 4.54, # 1/3.2"
- :"Hewlett-Packard hp PhotoSmart 43x series" => 5.27, # 1/2.7"
- :"Hewlett-Packard HP PhotoSmart 618 (V1.1)" => 5.27, # 1/2.7"
- :"Hewlett-Packard HP PhotoSmart C945 (V01.61)" => 7.176, # 1/1.8"
- :"Hewlett-Packard HP PhotoSmart R707 (V01.00)" => 7.176, # 1/1.8"
- :"KONICA MILOLTA DYNAX 5D" => 23.5,
- :"Konica Minolta Camera, Inc. DiMAGE A2" => 8.80, # 2/3"
- :"KONICA MINOLTA CAMERA, Inc. DiMAGE G400" => 5.76, # 1/2.5"
- :"Konica Minolta Camera, Inc. DiMAGE Z2" => 5.76, # 1/2.5"
- :"KONICA MINOLTA DiMAGE A200" => 8.80, # 2/3"
- :"KONICA MINOLTA DiMAGE X1" => 7.176, # 1/1.8"
- :"KONICA MINOLTA DYNAX 5D" => 23.5,
- :"Minolta Co., Ltd. DiMAGE F100" => 7.176, # 1/2.7"
- :"Minolta Co., Ltd. DiMAGE Xi" => 5.27, # 1/2.7"
- :"Minolta Co., Ltd. DiMAGE Xt" => 5.27, # 1/2.7"
- :"Minolta Co., Ltd. DiMAGE Z1" => 5.27, # 1/2.7"
- :"NIKON COOLPIX L3" => 5.76, # 1/2.5"
- :"NIKON COOLPIX P2" => 7.176, # 1/1.8"
- :"NIKON COOLPIX S4" => 5.76, # 1/2.5"
- :"NIKON COOLPIX S7c" => 5.76, # 1/2.5"
- :"NIKON CORPORATION NIKON D100" => 23.7,
- :"NIKON CORPORATION NIKON D1" => 23.7,
- :"NIKON CORPORATION NIKON D1H" => 23.7,
- :"NIKON CORPORATION NIKON D200" => 23.6,
- :"NIKON CORPORATION NIKON D2H" => 23.3,
- :"NIKON CORPORATION NIKON D2X" => 23.7,
- :"NIKON CORPORATION NIKON D40" => 23.7,
- :"NIKON CORPORATION NIKON D50" => 23.7,
- :"NIKON CORPORATION NIKON D60" => 23.6,
- :"NIKON CORPORATION NIKON D70" => 23.7,
- :"NIKON CORPORATION NIKON D70s" => 23.7,
- :"NIKON CORPORATION NIKON D80" => 23.6,
- :"NIKON CORPORATION NIKON D700" => 36.0,
- :"NIKON E2500" => 5.27, # 1/2.7"
- :"NIKON E2500" => 5.27, # 1/2.7"
- :"NIKON E3100" => 5.27, # 1/2.7"
- :"NIKON E3200" => 5.27,
- :"NIKON E3700" => 5.27, # 1/2.7"
- :"NIKON E4200" => 7.176, # 1/1.8"
- :"NIKON E4300" => 7.18,
- :"NIKON E4500" => 7.176, # 1/1.8"
- :"NIKON E4600" => 5.76, # 1/2.5"
- :"NIKON E5000" => 8.80, # 2/3"
- :"NIKON E5200" => 7.176, # 1/1.8"
- :"NIKON E5400" => 7.176, # 1/1.8"
- :"NIKON E5600" => 5.76, # 1/2.5"
- :"NIKON E5700" => 8.80, # 2/3"
- :"NIKON E5900" => 7.176, # 1/1.8"
- :"NIKON E7600" => 7.176, # 1/1.8"
- :"NIKON E775" => 5.27, # 1/2.7"
- :"NIKON E7900" => 7.176, # 1/1.8"
- :"NIKON E7900" => 7.176, # 1/1.8"
- :"NIKON E8800" => 8.80, # 2/3"
- :"NIKON E990" => 7.176, # 1/1.8"
- :"NIKON E995" => 7.176, # 1/1.8"
- :"NIKON S1" => 5.76, # 1/2.5"
- :"Nokia N80" => 5.27, # 1/2.7"
- :"Nokia N80" => 5.27, # 1/2.7"
- :"Nokia N93" => 4.536, # 1/3.1"
- :"Nokia N95" => 5.7, # 1/2.7"
- :"OLYMPUS CORPORATION C-5000Z" => 7.176, # 1/1.8"
- :"OLYMPUS CORPORATION C5060WZ" => 7.176, # 1/1.8"
- :"OLYMPUS CORPORATION C750UZ" => 5.27, # 1/2.7"
- :"OLYMPUS CORPORATION C765UZ" => 5.76, # 1//2.5"
- :"OLYMPUS CORPORATION C8080WZ" => 8.80, # 2/3"
- :"OLYMPUS CORPORATION X250,D560Z,C350Z" => 5.76, # 1/2.5"
- :"OLYMPUS CORPORATION X-3,C-60Z" => 7.176, # 1.8"
- :"OLYMPUS CORPORATION X400,D580Z,C460Z" => 5.27, # 1/2.7"
- :"OLYMPUS IMAGING CORP. E-500" => 17.3, # 4/3?
- :"OLYMPUS IMAGING CORP. E-510" => 17.3,
- :"OLYMPUS IMAGING CORP. FE115,X715" => 5.76, # 1/2.5"
- :"OLYMPUS IMAGING CORP. SP310" => 7.176, # 1/1.8"
- :"OLYMPUS IMAGING CORP. SP510UZ" => 5.75, # 1/2.5"
- :"OLYMPUS IMAGING CORP. SP550UZ" => 5.76, # 1/2.5"
- :"OLYMPUS IMAGING CORP. uD600,S600" => 5.75, # 1/2.5"
- :"OLYMPUS_IMAGING_CORP. X450,D535Z,C370Z" => 5.27, # 1/2.7"
- :"OLYMPUS IMAGING CORP. X550,D545Z,C480Z" => 5.76, # 1/2.5"
- :"OLYMPUS OPTICAL CO.,LTD C2040Z" => 6.40, # 1/2"
- :"OLYMPUS OPTICAL CO.,LTD C211Z" => 5.27, # 1/2.7"
- :"OLYMPUS OPTICAL CO.,LTD C2Z,D520Z,C220Z" => 4.54, # 1/3.2"
- :"OLYMPUS OPTICAL CO.,LTD C3000Z" => 7.176, # 1/1.8"
- :"OLYMPUS OPTICAL CO.,LTD C300Z,D550Z" => 5.4,
- :"OLYMPUS OPTICAL CO.,LTD C4100Z,C4000Z" => 7.176, # 1/1.8"
- :"OLYMPUS OPTICAL CO.,LTD C750UZ" => 5.27, # 1/2.7"
- :"OLYMPUS OPTICAL CO.,LTD X-2,C-50Z" => 7.176, # 1/1.8"
- :"OLYMPUS SP550UZ" => 5.76, # 1/2.5"
- :"OLYMPUS X100,D540Z,C310Z" => 5.27, # 1/2.7"
- :"Panasonic DMC-FX01" => 5.76, # 1/2.5"
- :"Panasonic DMC-FX07" => 5.75, # 1/2.5"
- :"Panasonic DMC-FX9" => 5.76, # 1/2.5"
- :"Panasonic DMC-FS6" => 5.76, # 1/2.5"
- :"Panasonic DMC-FZ20" => 5.760, # 1/2.5"
- :"Panasonic DMC-FZ2" => 4.54, # 1/3.2"
- :"Panasonic DMC-FZ30" => 7.176, # 1/1.8"
- :"Panasonic DMC-FZ50" => 7.176, # 1/1.8"
- :"Panasonic DMC-FZ5" => 5.760, # 1/2.5"
- :"Panasonic DMC-FZ7" => 5.76, # 1/2.5"
- :"Panasonic DMC-LC1" => 8.80, # 2/3"
- :"Panasonic DMC-LC33" => 5.760, # 1/2.5"
- :"Panasonic DMC-LX1" => 8.50, # 1/6.5"
- :"Panasonic DMC-LZ2" => 5.76, # 1/2.5"
- :"Panasonic DMC-TZ1" => 5.75, # 1/2.5"
- :"Panasonic DMC-TZ3" => 5.68, # 1/2.35"
- :"Panasonic DMC-TZ5" => 6.12, # 1/2.33"
- :"PENTAX Corporation PENTAX *ist DL" => 23.5,
- :"PENTAX Corporation PENTAX *ist DS2" => 23.5,
- :"PENTAX Corporation PENTAX *ist DS" => 23.5,
- :"PENTAX Corporation PENTAX K100D" => 23.5,
- :"PENTAX Corporation PENTAX Optio 450" => 7.176, # 1/1.8"
- :"PENTAX Corporation PENTAX Optio 550" => 7.176, # 1/1.8"
- :"PENTAX Corporation PENTAX Optio E10" => 5.76, # 1/2.5"
- :"PENTAX Corporation PENTAX Optio S40" => 5.76, # 1/2.5"
- :"PENTAX Corporation PENTAX Optio S4" => 5.76, # 1/2.5"
- :"PENTAX Corporation PENTAX Optio S50" => 5.76, # 1/2.5"
- :"PENTAX Corporation PENTAX Optio S5i" => 5.76, # 1/2.5"
- :"PENTAX Corporation PENTAX Optio S5z" => 5.76, # 1/2.5"
- :"PENTAX Corporation PENTAX Optio SV" => 5.76, # 1/2.5"
- :"PENTAX Corporation PENTAX Optio WP" => 5.75, # 1/2.5"
- :"RICOH CaplioG3 modelM" => 5.27, # 1/2.7"
- :"RICOH Caplio GX" => 7.176, # 1/1.8"
- :"RICOH Caplio R30" => 5.75, # 1/2.5"
- :"Samsung Digimax 301" => 5.27, # 1/2.7"
- :"Samsung Techwin " => 5.76, # 1/2.5"
- :"SAMSUNG TECHWIN Pro 815" => 8.80, # 2/3"
- :"SONY DSC-F828" => 8.80, # 2/3"
- :"SONY DSC-N12" => 7.176, # 1/1.8"
- :"SONY DSC-P100" => 7.176, # 1/1.8"
- :"SONY DSC-P10" => 7.176, # 1/1.8"
- :"SONY DSC-P12" => 7.176, # 1/1.8"
- :"SONY DSC-P150" => 7.176, # 1/1.8"
- :"SONY DSC-P200" => 7.176, # 1/1.8");
- :"SONY DSC-P52" => 5.27, # 1/2.7"
- :"SONY DSC-P72" => 5.27, # 1/2.7"
- :"SONY DSC-P73" => 5.27,
- :"SONY DSC-P8" => 5.27, # 1/2.7"
- :"SONY DSC-R1" => 21.5,
- :"SONY DSC-S40" => 5.27, # 1/2.7"
- :"SONY DSC-S600" => 5.760, # 1/2.5"
- :"SONY DSC-T9" => 7.18,
- :"SONY DSC-V1" => 7.176, # 1/1.8"
- :"SONY DSC-W1" => 7.176, # 1/1.8"
- :"SONY DSC-W30" => 5.760, # 1/2.5"
- :"SONY DSC-W50" => 5.75, # 1/2.5"
- :"SONY DSC-W5" => 7.176, # 1/1.8"
- :"SONY DSC-W7" => 7.176, # 1/1.8"
- :"SONY DSC-W80" => 5.75, # 1/2.5"
-}
diff --git a/ccd_defs_check.py b/ccd_defs_check.py
new file mode 100644
index 000000000..efacfee6b
--- /dev/null
+++ b/ccd_defs_check.py
@@ -0,0 +1,25 @@
+#!/usr/bin/python
+import sys
+import os
+import json
+
+BIN_PATH_ABS = os.path.abspath(os.path.dirname(os.path.abspath(__file__)))
+
+def get_ccd_widths():
+ """Return the CCD Width of the camera listed in the JSON defs file."""
+ with open(BIN_PATH_ABS + '/data/ccd_defs.json') as jsonFile:
+ return json.load(jsonFile)
+
+try:
+ ccd_defs = get_ccd_widths()
+ print "CCD_DEFS compiles OK"
+ print "Definitions in file: {0}".format(len(ccd_defs))
+ exit_code=0
+except IOError as e:
+ print "I/O error with CCD_DEFS file: {0}".format(e.strerror)
+ exit_code=255
+except:
+ print "Error with CCD_DEFS file: {0}".format(sys.exc_info()[1])
+ exit_code=255
+
+sys.exit(exit_code)
diff --git a/code_of_conduct.md b/code_of_conduct.md
new file mode 100644
index 000000000..9dd416e9b
--- /dev/null
+++ b/code_of_conduct.md
@@ -0,0 +1,74 @@
+# Contributor Covenant Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, gender identity and expression, level of experience,
+nationality, personal appearance, race, religion, or sexual identity and
+orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+* Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery and unwelcome sexual attention or
+advances
+* Trolling, insulting/derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or electronic
+ address, without explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or
+reject comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any contributor for other behaviors that they deem inappropriate,
+threatening, offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an appointed
+representative at an online or offline event. Representation of a project may be
+further defined and clarified by project maintainers.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by contacting the project team at `svm at clevelandmetroparks dot com`. All
+complaints will be reviewed and investigated and will result in a response that
+is deemed necessary and appropriate to the circumstances. The project team is
+obligated to maintain confidentiality with regard to the reporter of an incident.
+Further details of specific enforcement policies may be posted separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in good
+faith may face temporary or permanent repercussions as determined by other
+members of the project's leadership.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
+available at [http://contributor-covenant.org/version/1/4][version]
+
+[homepage]: http://contributor-covenant.org
+[version]: http://contributor-covenant.org/version/1/4/
diff --git a/configure.sh b/configure.sh
new file mode 100755
index 000000000..e9ddb6785
--- /dev/null
+++ b/configure.sh
@@ -0,0 +1,153 @@
+#!/bin/bash
+
+install() {
+ ## Set up library paths
+
+ export PYTHONPATH=$RUNPATH/SuperBuild/install/lib/python2.7/dist-packages:$RUNPATH/SuperBuild/src/opensfm:$PYTHONPATH
+ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$RUNPATH/SuperBuild/install/lib
+
+ if [[ $2 =~ ^[0-9]+$ ]] ; then
+ processes=$2
+ else
+ processes=$(nproc)
+ fi
+
+ ## Before installing
+ echo "Updating the system"
+ sudo apt-get update
+
+ sudo add-apt-repository -y ppa:ubuntugis/ppa
+ sudo apt-get update
+
+ echo "Installing Required Requisites"
+ sudo apt-get install -y -qq build-essential \
+ git \
+ cmake \
+ python-pip \
+ libgdal-dev \
+ gdal-bin \
+ libgeotiff-dev \
+ pkg-config \
+ libjsoncpp-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 \
+ 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 \
+ libvtk6-dev
+
+ echo "Removing libdc1394-22-dev due to python opencv issue"
+ sudo apt-get remove libdc1394-22-dev
+
+ ## Installing OpenSfM Requisites
+ echo "Installing OpenSfM Dependencies"
+ 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 \
+ python-pyproj
+
+ sudo pip install -U PyYAML \
+ exifread \
+ gpxpy \
+ xmltodict \
+ appsettings \
+ loky
+
+ echo "Installing CGAL dependencies"
+ sudo apt-get install -y -qq libgmp-dev libmpfr-dev
+
+ echo "Installing Ecto Dependencies"
+ sudo pip install -U catkin-pkg
+ sudo apt-get install -y -qq python-empy \
+ python-nose \
+ python-pyside
+
+ echo "Installing OpenDroneMap Dependencies"
+ sudo apt-get install -y -qq python-pyexiv2 \
+ python-scipy \
+ libexiv2-dev \
+ liblas-bin
+
+ echo "Installing lidar2dems Dependencies"
+ sudo apt-get install -y -qq swig2.0 \
+ python-wheel \
+ libboost-log-dev
+
+ sudo pip install -U https://github.com/OpenDroneMap/gippy/archive/v0.3.9.tar.gz
+
+ echo "Compiling SuperBuild"
+ cd ${RUNPATH}/SuperBuild
+ mkdir -p build && cd build
+ cmake .. && make -j$processes
+
+ echo "Compiling build"
+ cd ${RUNPATH}
+ mkdir -p build && cd build
+ cmake .. && make -j$processes
+
+ echo "Configuration Finished"
+}
+
+uninstall() {
+ echo "Removing SuperBuild and build directories"
+ cd ${RUNPATH}/SuperBuild
+ rm -rfv build src download install
+ cd ../
+ rm -rfv build
+}
+
+reinstall() {
+ echo "Reinstalling ODM modules"
+ uninstall
+ install
+}
+
+usage() {
+ echo "Usage:"
+ echo "bash configure.sh [nproc]"
+ echo "Subcommands:"
+ echo " install"
+ echo " Installs all dependencies and modules for running OpenDroneMap"
+ echo " reinstall"
+ echo " Removes SuperBuild and build modules, then re-installs them. Note this does not update OpenDroneMap to the latest version. "
+ echo " uninstall"
+ echo " Removes SuperBuild and build modules. Does not uninstall dependencies"
+ echo " help"
+ echo " Displays this message"
+ echo "[nproc] is an optional argument that can set the number of processes for the make -j tag. By default it uses $(nproc)"
+}
+
+if [[ $1 =~ ^(install|reinstall|uninstall|usage)$ ]]; then
+ RUNPATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+ "$1"
+else
+ echo "Invalid instructions." >&2
+ usage
+ exit 1
+fi
diff --git a/contrib/blender/README.md b/contrib/blender/README.md
new file mode 100644
index 000000000..74b93008f
--- /dev/null
+++ b/contrib/blender/README.md
@@ -0,0 +1,41 @@
+# Blender scripts
+# odm_photo
+Renders photos from ODM generated texture models.
+Currently can produce 360 panoramic photos and 360 3D panoramic (VR) photos.
+NB: the default resolution for 360 photos is 6000x3000 (maximum supported by Facebook).
+
+## Requirements
+* Blender
+* ExifTool (must be on your PATH)
+
+## Usage
+To generate a 360 panoramic photo:
+
+ blender -b photo_360.blend --python odm_photo.py --
+
+Output is `/odm_photo/odm_photo_360.jpg`.
+
+To generate a 360 3D panoramic photo:
+
+ blender -b photo_vr.blend --python odm_photo.py --
+
+Output is `/odm_photo/odm_photo_vr_L.jpg` and `/odm_photo/odm_photo_vr_R.jpg`.
+
+**NB: argument order matters!**
+
+# odm_video
+Renders videos from ODM generated texture models.
+Currently can produce 360 panoramic videos.
+NB: the default resolution is 4096x2048 (maximum supported by Facebook).
+
+## Requirements
+* Blender
+* Python 2.7 (must be on your PATH)
+* Spatial Media Metadata Injector (https://github.com/google/spatial-media/tree/master/spatialmedia) (place in `spatialmedia` subdirectory)
+
+## Usage
+To generate a 360 panoramic photo:
+
+ blender -b photo_360.blend --python odm_video.py --
+
+Output is `/odm_video/odm_video_360.mp4`.
diff --git a/contrib/blender/common.py b/contrib/blender/common.py
new file mode 100644
index 000000000..e37749828
--- /dev/null
+++ b/contrib/blender/common.py
@@ -0,0 +1,45 @@
+import bpy
+import materials_utils
+
+def loadMesh(file):
+
+ bpy.utils.register_module('materials_utils')
+
+ bpy.ops.import_scene.obj(filepath=file,
+ axis_forward='Y',
+ axis_up='Z')
+
+ bpy.ops.xps_tools.convert_to_cycles_all()
+
+ model = bpy.data.objects[-1]
+ minX = float('inf')
+ maxX = float('-inf')
+ minY = float('inf')
+ maxY = float('-inf')
+ minZ = float('inf')
+ maxZ = float('-inf')
+ for coord in model.bound_box:
+ x = coord[0]
+ y = coord[1]
+ z = coord[2]
+ minX = min(x, minX)
+ maxX = max(x, maxX)
+ minY = min(y, minY)
+ maxY = max(y, maxY)
+ minZ = min(z, minZ)
+ maxZ = max(z, maxZ)
+
+ model.location[2] += (maxZ - minZ)/2
+
+ surfaceShaderType = 'ShaderNodeEmission'
+ surfaceShaderName = 'Emission'
+
+ for m in bpy.data.materials:
+ nt = m.node_tree
+ nt.nodes.remove(nt.nodes['Color Mult'])
+ nt.nodes.remove(nt.nodes['Diffuse BSDF'])
+ nt.nodes.new(surfaceShaderType)
+ nt.links.new(nt.nodes['Material Output'].inputs[0],
+ nt.nodes[surfaceShaderName].outputs[0])
+ nt.links.new(nt.nodes[surfaceShaderName].inputs[0],
+ nt.nodes['Diffuse Texture'].outputs[0])
diff --git a/contrib/blender/odm_photo.py b/contrib/blender/odm_photo.py
new file mode 100644
index 000000000..b63cdcf37
--- /dev/null
+++ b/contrib/blender/odm_photo.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+
+# Renders a photo.
+# ExifTool must be on your PATH.
+# To generate a 360 panoramic photo:
+# blender -b photo_360.blend --python odm_photo.py --
+# To generate a 360 3D panoramic photo:
+# blender -b photo_vr.blend --python odm_photo.py --
+# NB: argument order matters!
+
+import sys
+import bpy
+import subprocess
+from common import loadMesh
+
+
+def main():
+
+ if len(sys.argv) < 5 or sys.argv[-2] != '--':
+ sys.exit('Please provide the ODM project path.')
+
+ projectHome = sys.argv[-1]
+
+ loadMesh(projectHome +
+ '/odm_texturing/odm_textured_model_geo.obj')
+
+ blendName = bpy.path.display_name_from_filepath(bpy.data.filepath)
+ fileName = projectHome + '/odm_photo/odm_' + blendName
+ render = bpy.data.scenes['Scene'].render
+ render.filepath = fileName
+ bpy.ops.render.render(write_still=True)
+
+ width = render.resolution_x
+ height = render.resolution_y
+ if(render.use_multiview):
+ writeExif(fileName+render.views[0].file_suffix+'.jpg', width, height)
+ writeExif(fileName+render.views[1].file_suffix+'.jpg', width, height)
+ else:
+ writeExif(fileName+'.jpg', width, height)
+
+
+def writeExif(fileName, width, height):
+ w = str(width)
+ h = str(height)
+
+ subprocess.run(['exiftool',
+ '-overwrite_original',
+ '-CroppedAreaImageWidthPixels=' + w,
+ '-CroppedAreaImageHeightPixels=' + h,
+ '-FullPanoWidthPixels=' + w,
+ '-FullPanoHeightPixels=' + h,
+ '-CroppedAreaLeftPixels=0',
+ '-CroppedAreaTopPixels=0',
+ '-ProjectionType=equirectangular',
+ '-UsePanoramaViewer=True',
+ '-PoseHeadingDegrees=0',
+ '-LargestValidInteriorRectLeft=0',
+ '-LargestValidInteriorRectTop=0',
+ '-LargestValidInteriorRectWidth=' + w,
+ '-LargestValidInteriorRectHeight=' + h,
+ fileName])
+
+
+if __name__ == '__main__':
+ main()
diff --git a/contrib/blender/odm_video.py b/contrib/blender/odm_video.py
new file mode 100644
index 000000000..6faf8b15f
--- /dev/null
+++ b/contrib/blender/odm_video.py
@@ -0,0 +1,113 @@
+#!/usr/bin/env python
+
+# Renders a video.
+# To generate a 360 panoramic video:
+# blender -b photo_360.blend --python odm_video.py --
+
+import sys
+import subprocess
+import os
+import bpy
+from common import loadMesh
+
+
+def main():
+
+ if len(sys.argv) < 7 or sys.argv[-4] != '--':
+ sys.exit('Please provide the ODM project path, camera waypoints (xyz format), and number of frames.')
+
+ projectHome = sys.argv[-3]
+ waypointFile = sys.argv[-2]
+ numFrames = int(sys.argv[-1])
+
+ loadMesh(projectHome +
+ '/odm_texturing/odm_textured_model_geo.obj')
+
+ waypoints = loadWaypoints(waypointFile)
+ numWaypoints = len(waypoints)
+
+ scene = bpy.data.scenes['Scene']
+
+ # create path thru waypoints
+ curve = bpy.data.curves.new(name='CameraPath', type='CURVE')
+ curve.dimensions = '3D'
+ curve.twist_mode = 'Z_UP'
+ nurbs = curve.splines.new('NURBS')
+ nurbs.points.add(numWaypoints-1)
+ weight = 1
+ for i in range(numWaypoints):
+ nurbs.points[i].co[0] = waypoints[i][0]
+ nurbs.points[i].co[1] = waypoints[i][1]
+ nurbs.points[i].co[2] = waypoints[i][2]
+ nurbs.points[i].co[3] = weight
+ nurbs.use_endpoint_u = True
+ path = bpy.data.objects.new(name='CameraPath', object_data=curve)
+ scene.objects.link(path)
+
+ camera = bpy.data.objects['Camera']
+ camera.location[0] = 0
+ camera.location[1] = 0
+ camera.location[2] = 0
+ followPath = camera.constraints.new(type='FOLLOW_PATH')
+ followPath.name = 'CameraFollowPath'
+ followPath.target = path
+ followPath.use_curve_follow = True
+ animateContext = bpy.context.copy()
+ animateContext['constraint'] = followPath
+ bpy.ops.constraint.followpath_path_animate(animateContext,
+ constraint='CameraFollowPath',
+ frame_start=0,
+ length=numFrames)
+
+ blendName = bpy.path.display_name_from_filepath(bpy.data.filepath)
+ fileName = projectHome + '/odm_video/odm_' + blendName.replace('photo', 'video')
+ scene.frame_start = 0
+ scene.frame_end = numFrames
+ render = scene.render
+ render.filepath = fileName + '.mp4'
+ render.image_settings.file_format = 'FFMPEG'
+ if(render.use_multiview):
+ render.image_settings.stereo_3d_format.display_mode = 'TOPBOTTOM'
+ render.image_settings.views_format = 'STEREO_3D'
+ render.views[0].file_suffix = ''
+ format3d = 'top-bottom'
+ else:
+ width = render.resolution_x
+ height = render.resolution_y
+ format3d = 'none'
+ render.resolution_x = 4096
+ render.resolution_y = 2048
+
+ render.ffmpeg.audio_codec = 'AAC'
+ render.ffmpeg.codec = 'H264'
+ render.ffmpeg.format = 'MPEG4'
+ render.ffmpeg.video_bitrate = 45000
+ bpy.ops.render.render(animation=True)
+
+ writeMetadata(fileName+'.mp4', format3d)
+
+
+def loadWaypoints(filename):
+ waypoints = []
+ with open(filename) as f:
+ for line in f:
+ xyz = line.split()
+ waypoints.append((float(xyz[0]), float(xyz[1]), float(xyz[2])))
+ return waypoints
+
+
+def writeMetadata(filename, format3d):
+ subprocess.run(['python',
+ 'spatialmedia',
+ '-i',
+ '--stereo='+format3d,
+ filename,
+ filename+'.injected'])
+ # check metadata injector was succesful
+ if os.path.exists(filename+'.injected'):
+ os.remove(filename)
+ os.rename(filename+'.injected', filename)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/contrib/blender/photo_360.blend b/contrib/blender/photo_360.blend
new file mode 100644
index 000000000..6e2769479
Binary files /dev/null and b/contrib/blender/photo_360.blend differ
diff --git a/contrib/blender/photo_vr.blend b/contrib/blender/photo_vr.blend
new file mode 100644
index 000000000..00f8e7ff4
Binary files /dev/null and b/contrib/blender/photo_vr.blend differ
diff --git a/contrib/grass/README.md b/contrib/grass/README.md
new file mode 100644
index 000000000..9700f8adf
--- /dev/null
+++ b/contrib/grass/README.md
@@ -0,0 +1,16 @@
+# GRASS scripts
+# odm_grass
+Generates contour and textured relief maps.
+
+## Requirements
+* Compile and install GRASS 7 version or higher, https://grasswiki.osgeo.org/wiki/Compile_and_Install
+* Environment variables:
+ * PYTHONHOME set to the location of Python
+ * PYTHONPATH set to the location of GRASS Python libs
+ * PATH includes GRASS bin and lib directories
+ * GISBASE set to the location of GRASS
+
+## Usage
+ python odm_grass.py
+
+Output is `/odm_georeferencing/odm_contour.shp` and `/odm_orthophoto/odm_relief.tif`.
diff --git a/contrib/grass/odm_grass.py b/contrib/grass/odm_grass.py
new file mode 100644
index 000000000..78bb61137
--- /dev/null
+++ b/contrib/grass/odm_grass.py
@@ -0,0 +1,149 @@
+#!/usr/bin/env python
+
+# To run, set the following env variables:
+# PYTHONHOME location of Python
+# PYTHONPATH location of GRASS Python libs
+# PATH include GRASS bin and lib
+# GISBASE location of GRASS
+
+import os
+import sys
+import grass.script as gscript
+import grass.script.core
+import grass.script.setup
+
+rsurfName = 'odm_rsurf'
+contourName = 'odm_contour'
+orthophotoName = 'odm_orthophoto'
+reliefName = 'odm_relief'
+shadedReliefName = reliefName + '_shaded'
+
+overwrite = True
+
+
+def main():
+ if len(sys.argv) < 2:
+ sys.exit('Please provide the ODM project path.')
+
+ projectHome = sys.argv[1]
+
+ gisdb = projectHome+'/grassdata'
+ location = 'odm'
+ gisrc = gscript.setup.init(os.environ['GISBASE'], gisdb, location)
+
+ # get srs and initial extents
+ with open(projectHome+'/odm_georeferencing/coords.txt') as f:
+ srs = f.readline().split()
+ mean = f.readline().split()
+ meanX = float(mean[0])
+ meanY = float(mean[1])
+ minX = float('inf')
+ maxX = float('-inf')
+ minY = float('inf')
+ maxY = float('-inf')
+ for line in f:
+ xy = line.split()
+ x = float(xy[0])
+ y = float(xy[1])
+ minX = min(x, minX)
+ maxX = max(x, maxX)
+ minY = min(y, minY)
+ maxY = max(y, maxY)
+
+ datum = srs[0]
+ proj = srs[1]
+ zone = srs[2]
+ gscript.core.create_location(gisdb, location, datum=datum,
+ proj4='+proj='+proj+' +zone='+zone,
+ overwrite=overwrite)
+
+ n = meanY + maxY
+ s = meanY + minY
+ e = meanX + maxX
+ w = meanX + minX
+ gscript.run_command('g.region', flags='s', n=n, s=s, e=e, w=w, res=0.01,
+ res3=0.01, overwrite=overwrite)
+
+ contour(projectHome)
+ relief(projectHome)
+
+ os.remove(gisrc)
+
+
+def contour(projectHome):
+ """
+ Creates a contour map based on the ODM project DEM model.
+ """
+ print 'Creating contour map'
+
+ step = 0.25
+
+ gscript.run_command('r.in.gdal', flags='o',
+ input=projectHome+'/odm_georeferencing/odm_georeferencing_model_dem.tif',
+ output=rsurfName, memory=2047,
+ overwrite=overwrite)
+
+ gscript.run_command('r.contour', input=rsurfName, output=contourName,
+ step=step, overwrite=overwrite)
+
+ gscript.run_command('v.out.ogr', input=contourName,
+ output=projectHome +
+ '/odm_georeferencing/odm_contour.shp',
+ overwrite=overwrite)
+
+
+def relief(projectHome):
+ """
+ Creates a textured relief map in GeoTIFF format.
+ NB: this is an RGBA raster and so is readable by image software.
+ """
+ print 'Creating relief map'
+
+ gscript.run_command('r.in.gdal', flags='o',
+ input=projectHome+'/odm_orthophoto/odm_orthophoto.tif',
+ output=orthophotoName, memory=2047,
+ overwrite=overwrite)
+
+ gscript.run_command('r.composite', red=orthophotoName+'.red',
+ green=orthophotoName+'.green',
+ blue=orthophotoName+'.blue',
+ output=orthophotoName+'.rgb',
+ overwrite=overwrite)
+
+ gscript.run_command('r.relief', input=rsurfName, output=reliefName,
+ overwrite=overwrite)
+
+ gscript.run_command('r.shade', shade=reliefName,
+ color=orthophotoName+'.rgb', output=shadedReliefName,
+ overwrite=overwrite)
+
+ calc = ';'.join([
+ '$shadedRelief.red = ' +
+ 'if(isnull($orthophoto.red), 0, r#$shadedRelief)',
+ '$shadedRelief.green = ' +
+ 'if(isnull($orthophoto.green), 0, g#$shadedRelief)',
+ '$shadedRelief.blue = ' +
+ 'if(isnull($orthophoto.blue), 0, b#$shadedRelief)',
+ '$shadedRelief.alpha = ' +
+ 'if(isnull($orthophoto.alpha), 0, 255)'
+ ])
+ gscript.mapcalc(calc, shadedRelief=shadedReliefName,
+ orthophoto=orthophotoName, overwrite=overwrite)
+
+ gscript.run_command('i.group', group=shadedReliefName+'.group',
+ input=shadedReliefName+'.red,' +
+ shadedReliefName+'.green,' +
+ shadedReliefName+'.blue,' +
+ shadedReliefName+'.alpha')
+
+ gscript.run_command('r.out.gdal', flags='cm',
+ input=shadedReliefName+'.group',
+ output=projectHome+'/odm_orthophoto/odm_relief.tif',
+ format='GTiff', type='Byte',
+ createopt='TILED=yes,COMPRESS=DEFLATE,PREDICTOR=2,' +
+ 'BLOCKXSIZE=512,BLOCKYSIZE=512',
+ nodata=0, overwrite=overwrite)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/contrib/ndvi/README.md b/contrib/ndvi/README.md
new file mode 100644
index 000000000..2b5df267c
--- /dev/null
+++ b/contrib/ndvi/README.md
@@ -0,0 +1,31 @@
+# NDVI
+
+This script produces a NDVI raster from a CIR orthophoto (odm_orthophoto.tif in your project)
+
+## Requirements
+* python_gdal package from apt
+* numpy python package (included in ODM build)
+
+## Usage
+```
+ndvi.py [-h] [--overwrite] N N
+
+positional arguments:
+ The CIR orthophoto. Must be a GeoTiff.
+ N NIR band number
+ N Vis band number
+ The output file. Also must be in GeoTiff format
+
+optional arguments:
+ -h, --help show this help message and exit
+ --overwrite, -o Will overwrite output file if it exists.
+```
+
+**Argument order matters! NIR first, then VIS**
+
+## Examples:
+Use the [Seneca](https://github.com/OpenDroneMap/odm_data_seneca) dataset for a good working CIR. The band order for that set is NIR-G-B, so you will want to use bands 1 and 2 for this script. After running ODM, the command goes as follows:
+
+`python ndvi.py /path/to/odm_orthophoto.tif 1 2 /path/to/ndvi.tif`
+
+The output in QGIS (with a spectral pseudocolor): 
\ No newline at end of file
diff --git a/contrib/ndvi/ndvi.py b/contrib/ndvi/ndvi.py
new file mode 100644
index 000000000..ab457f2df
--- /dev/null
+++ b/contrib/ndvi/ndvi.py
@@ -0,0 +1,82 @@
+# A script to calculate the NDVI from a color-infrared orthophoto.
+# requires python-gdal
+
+import numpy
+import argparse
+import os.path
+try:
+ from osgeo import gdal
+ from osgeo import osr
+except ImportError:
+ raise ImportError("You need to install python-gdal. run `apt-get install python-gdal`")
+ exit()
+
+
+def parse_args():
+ p = argparse.ArgumentParser("A script that calculates the NDVI of a CIR orthophoto")
+
+ p.add_argument("orthophoto", metavar="",
+ type=argparse.FileType('r'),
+ help="The CIR orthophoto. Must be a GeoTiff.")
+ p.add_argument("nir", metavar="N", type=int,
+ help="NIR band number")
+ p.add_argument("vis", metavar="N", type=int,
+ help="Vis band number")
+ p.add_argument("out", metavar="",
+ type=argparse.FileType('w'),
+ help="The output file. Also must be in GeoTiff format")
+ p.add_argument("--overwrite", "-o",
+ action='http://github.com/store_true',
+ default=False,
+ help="Will overwrite output file if it exists. ")
+ return p.parse_args()
+
+
+def calc_ndvi(nir, vis):
+ """
+ Calculates the NDVI of an orthophoto using nir and vis bands.
+ :param nir: An array containing the nir band
+ :param vis: An array containing the vis band
+ :return: An array that will be exported as a tif
+ """
+
+ # Take the orthophoto and do nir - vis / nir + vis
+ # for each cell, calculate ndvi (masking out where divide by 0)
+ ndvi = numpy.empty(nir.shape, dtype=float)
+ mask = numpy.not_equal((nirb + visb), 0.0)
+ return numpy.choose(mask, (-1.0, numpy.true_divide(numpy.subtract(nirb, visb), numpy.add(nirb, visb))))
+
+
+if __name__ == "__main__":
+
+ rootdir = os.path.dirname(os.path.abspath(__file__))
+
+ # Parse args
+ args = parse_args()
+
+ if not args.overwrite and os.path.isfile(os.path.join(rootdir, args.out.name)):
+ print("File exists, rename or use -o to overwrite.")
+ exit()
+
+ # import raster
+ raster = gdal.Open(args.orthophoto.name)
+ orthophoto = raster.ReadAsArray()
+ # parse out bands
+ nirb = orthophoto[args.nir - 1].astype(float)
+ visb = orthophoto[args.vis - 1].astype(float)
+
+ outfile = args.out
+
+ # Do ndvi calc
+ ndvi = calc_ndvi(nirb, visb)
+
+ # export raster
+ out_driver = gdal.GetDriverByName('GTiff')\
+ .Create(outfile.name, int(ndvi.shape[1]), int(ndvi.shape[0]), 1, gdal.GDT_Float32)
+ outband = out_driver.GetRasterBand(1)
+ outband.WriteArray(ndvi)
+ outcrs = osr.SpatialReference()
+ outcrs.ImportFromWkt(raster.GetProjectionRef())
+ out_driver.SetProjection(outcrs.ExportToWkt())
+ out_driver.SetGeoTransform(raster.GetGeoTransform())
+ outband.FlushCache()
diff --git a/contrib/visveg/readme.md b/contrib/visveg/readme.md
new file mode 100644
index 000000000..1d883be43
--- /dev/null
+++ b/contrib/visveg/readme.md
@@ -0,0 +1,31 @@
+# Visible Vegetation Indexes
+
+This script produces a Vegetation Index raster from a RGB orthophoto (odm_orthophoto.tif in your project)
+
+## Requirements
+* rasterio (pip install rasterio)
+* numpy python package (included in ODM build)
+
+## Usage
+```
+vegind.py index
+
+positional arguments:
+ The RGB orthophoto. Must be a GeoTiff.
+ index Index identifier. Allowed values: ngrdi, tgi, vari
+```
+Output will be generated with index suffix in the same directory as input.
+
+## Examples
+
+`python vegind.py /path/to/odm_orthophoto.tif tgi`
+
+Orthophoto photo of Koniaków grass field and forest in QGIS: 
+The Triangular Greenness Index output in QGIS (with a spectral pseudocolor): 
+Visible Atmospheric Resistant Index: 
+Normalized green-red difference index: 
+
+## Bibliography
+
+1. Hunt, E. Raymond, et al. "A Visible Band Index for Remote Sensing Leaf Chlorophyll Content At the Canopy Scale." ITC journal 21(2013): 103-112. doi: 10.1016/j.jag.2012.07.020
+(https://doi.org/10.1016/j.jag.2012.07.020)
diff --git a/contrib/visveg/vegind.py b/contrib/visveg/vegind.py
new file mode 100644
index 000000000..625546572
--- /dev/null
+++ b/contrib/visveg/vegind.py
@@ -0,0 +1,95 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+import rasterio, os, sys
+import numpy as np
+
+class bcolors:
+ OKBLUE = '\033[94m'
+ OKGREEN = '\033[92m'
+ WARNING = '\033[93m'
+ FAIL = '\033[91m'
+ ENDC = '\033[0m'
+ BOLD = '\033[1m'
+ UNDERLINE = '\033[4m'
+
+try:
+ file = sys.argv[1]
+ typ = sys.argv[2]
+ (fileRoot, fileExt) = os.path.splitext(file)
+ outFileName = fileRoot + "_" + typ + fileExt
+ if typ not in ['vari', 'tgi', 'ngrdi']:
+ raise IndexError
+except (TypeError, IndexError, NameError):
+ print bcolors.FAIL + 'Arguments messed up. Check arguments order and index name' + bcolors.ENDC
+ print 'Usage: ./vegind.py orto index'
+ print ' orto - filepath to RGB orthophoto'
+ print ' index - Vegetation Index'
+ print bcolors.OKGREEN + 'Available indexes: vari, ngrdi, tgi' + bcolors.ENDC
+ sys.exit()
+
+
+def calcNgrdi(red, green):
+ """
+ Normalized green red difference index
+ Tucker,C.J.,1979.
+ Red and photographic infrared linear combinations for monitoring vegetation.
+ Remote Sensing of Environment 8, 127–150
+ :param red: red visible channel
+ :param green: green visible channel
+ :return: ngrdi index array
+ """
+ mask = np.not_equal(np.add(red,green), 0.0)
+ return np.choose(mask, (-9999.0, np.true_divide(
+ np.subtract(green,red),
+ np.add(red,green))))
+
+def calcVari(red,green,blue):
+ """
+ Calculates Visible Atmospheric Resistant Index
+ Gitelson, A.A., Kaufman, Y.J., Stark, R., Rundquist, D., 2002.
+ Novel algorithms for remote estimation of vegetation fraction.
+ Remote Sensing of Environment 80, 76–87.
+ :param red: red visible channel
+ :param green: green visible channel
+ :param blue: blue visible channel
+ :return: vari index array, that will be saved to tiff
+ """
+ mask = np.not_equal(np.subtract(np.add(green,red),blue), 0.0)
+ return np.choose(mask, (-9999.0, np.true_divide(np.subtract(green,red),np.subtract(np.add(green,red),blue))))
+
+def calcTgi(red,green,blue):
+ """
+ Calculates Triangular Greenness Index
+ Hunt, E. Raymond Jr.; Doraiswamy, Paul C.; McMurtrey, James E.; Daughtry, Craig S.T.; Perry, Eileen M.; and Akhmedov, Bakhyt,
+ A visible band index for remote sensing leaf chlorophyll content at the canopy scale (2013).
+ Publications from USDA-ARS / UNL Faculty. Paper 1156.
+ http://digitalcommons.unl.edu/usdaarsfacpub/1156
+ :param red: red channel
+ :param green: green channel
+ :param blue: blue channel
+ :return: tgi index array, that will be saved to tiff
+ """
+ mask = np.not_equal(green-red+blue-255.0, 0.0)
+ return np.choose(mask, (-9999.0, np.subtract(green, np.multiply(0.39,red), np.multiply(0.61, blue))))
+
+try:
+ with rasterio.Env():
+ ds = rasterio.open(file)
+ profile = ds.profile
+ profile.update(dtype=rasterio.float32, count=1, nodata=-9999)
+ red = np.float32(ds.read(1))
+ green = np.float32(ds.read(2))
+ blue = np.float32(ds.read(3))
+ np.seterr(divide='ignore', invalid='ignore')
+ if typ == 'ngrdi':
+ indeks = calcNgrdi(red,green)
+ elif typ == 'vari':
+ indeks = calcVari(red, green, blue)
+ elif typ == 'tgi':
+ indeks = calcTgi(red, green, blue)
+
+ with rasterio.open(outFileName, 'w', **profile) as dst:
+ dst.write(indeks.astype(rasterio.float32), 1)
+except rasterio.errors.RasterioIOError:
+ print bcolors.FAIL + 'Orthophoto file not found or access denied' + bcolors.ENDC
+ sys.exit()
diff --git a/convert_vlsift_to_lowesift.pl b/convert_vlsift_to_lowesift.pl
deleted file mode 100644
index dc72a1f4c..000000000
--- a/convert_vlsift_to_lowesift.pl
+++ /dev/null
@@ -1,112 +0,0 @@
-#!/usr/local/bin/perl
-
-$filename_base = $ARGV[0];
-
-$write_binary = 1;
-
-$filename_src = $filename_base.".key.sift";
-$filename_dest_bin = $filename_base.".key.bin";
-$filename_dest_key = $filename_base.".key";
-$filename_image = $filename_base.".pgm";
-
-open (DEST_BIN, ">$filename_dest_bin");
-open (DEST_KEY, ">$filename_dest_key");
-
-open (SRC, "$filename_src");
-
-$linecount = 0;
-$linecount += tr/\n/\n/ while sysread(SRC, $_, 2 ** 16);
-
-printf ("%d", $linecount);
-
-if($write_binary){
- seek(SRC, 0, 0);
-
- print DEST_BIN pack("L", $linecount);
-
- while ($record = ) {
- @parts = split(/ /, $record);
-
- if(@parts[3] > 3.141){
- @parts[3] -= 6.282;
- }
-
- @parts[3] *= -1;
-
- @tmp = @parts[0];
- @parts[0] = @parts[1];
- @parts[1] = @tmp;
-
- for ($count = 4; $count < 132; $count += 8) {
- @tmp = @parts[$count+7];
- @parts[$count+7] = @parts[$count+1];
- @parts[$count+1] = @tmp;
-
- @tmp = @parts[$count+6];
- @parts[$count+6] = @parts[$count+2];
- @parts[$count+2] = @tmp;
-
- @tmp = @parts[$count+3];
- @parts[$count+3] = @parts[$count+5];
- @parts[$count+5] = @tmp;
- }
-
- print DEST_BIN pack("f4 C128", @parts);
- }
-}
-
- seek(SRC, 0, 0);
-
- print DEST_KEY $linecount, " 128\n";
-
- while ($record = ) {
- @parts = split(/ /, $record);
-
- $counter = 0;
-
- if(@parts[3] > 3.141){
- @parts[3] -= 6.282;
- }
-
- @parts[3] *= -1;
-
- printf (DEST_KEY "%.3f %.3f %.3f %.3f", @parts[1], @parts[0], @parts[2], @parts[3]);
-
- shift(@parts);
- shift(@parts);
- shift(@parts);
- shift(@parts);
-
- for ($count = 0; $count < 128; $count += 8) {
- @tmp = @parts[$count+7];
- @parts[$count+7] = @parts[$count+1];
- @parts[$count+1] = @tmp;
-
- @tmp = @parts[$count+6];
- @parts[$count+6] = @parts[$count+2];
- @parts[$count+2] = @tmp;
-
- @tmp = @parts[$count+3];
- @parts[$count+3] = @parts[$count+5];
- @parts[$count+5] = @tmp;
- }
-
- foreach (@parts) {
- if((($counter) % 20) == 0) {
- print DEST_KEY "\n ";
- } else {
- if($counter != 0){
- print DEST_KEY " ";
- }
- }
-
- print DEST_KEY $_;
-
- $counter++;
- }
- }
-
-
-close(DEST_BIN);
-close(DEST_KEY);
-close(SRC);
\ No newline at end of file
diff --git a/core2.Dockerfile b/core2.Dockerfile
new file mode 100644
index 000000000..e300fbce3
--- /dev/null
+++ b/core2.Dockerfile
@@ -0,0 +1,69 @@
+FROM phusion/baseimage
+
+# Env variables
+ENV DEBIAN_FRONTEND noninteractive
+
+#Install dependencies
+#Required Requisites
+RUN add-apt-repository -y ppa:ubuntugis/ppa
+RUN add-apt-repository -y ppa:george-edison55/cmake-3.x
+RUN apt-get update -y
+
+# All packages (Will install much faster)
+RUN apt-get install --no-install-recommends -y git cmake python-pip build-essential software-properties-common python-software-properties libgdal-dev gdal-bin libgeotiff-dev \
+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-pyproj python-empy python-nose python-pyside python-pyexiv2 python-scipy \
+libexiv2-dev liblas-bin python-matplotlib libatlas-base-dev libgmp-dev libmpfr-dev swig2.0 python-wheel libboost-log-dev libjsoncpp-dev
+
+RUN apt-get remove libdc1394-22-dev
+RUN pip install --upgrade pip
+RUN pip install setuptools
+RUN pip install -U PyYAML exifread gpxpy xmltodict catkin-pkg appsettings https://github.com/OpenDroneMap/gippy/archive/v0.3.9.tar.gz loky
+
+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"
+
+# Prepare directories
+
+RUN mkdir /code
+WORKDIR /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 /modules/ /code/modules/
+COPY /opendm/ /code/opendm/
+COPY /patched_files/ /code/patched_files/
+COPY run.py /code/run.py
+COPY run.sh /code/run.sh
+COPY /scripts/ /code/scripts/
+COPY /SuperBuild/cmake/ /code/SuperBuild/cmake/
+COPY /SuperBuild/CMakeLists.txt /code/SuperBuild/CMakeLists.txt
+COPY docker.settings.yaml /code/settings.yaml
+COPY VERSION /code/VERSION
+
+# Replace g++ and gcc with our own scripts
+COPY /docker/ /code/docker/
+RUN mv -v /usr/bin/gcc /usr/bin/gcc_real && mv -v /usr/bin/g++ /usr/bin/g++_real && cp -v /code/docker/gcc /usr/bin/gcc && cp -v /code/docker/g++ /usr/bin/g++
+
+#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)
+
+RUN apt-get -y remove libgl1-mesa-dri git cmake python-pip build-essential
+RUN apt-get install -y libvtk5-dev
+
+# Cleanup APT
+RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
+
+# Clean Superbuild
+
+RUN rm -rf /code/SuperBuild/download
+RUN rm -rf /code/SuperBuild/src/opencv/samples /code/SuperBuild/src/pcl/test /code/SuperBuild/src/pcl/doc /code/SuperBuild/src/pdal/test /code/SuperBuild/src/pdal/doc
+
+# Entry point
+ENTRYPOINT ["python", "/code/run.py", "code"]
+
diff --git a/docker.settings.yaml b/docker.settings.yaml
new file mode 100644
index 000000000..2a2e4092a
--- /dev/null
+++ b/docker.settings.yaml
@@ -0,0 +1,62 @@
+---
+# A list of global configuration variables
+# Uncomment lines as needed to edit default settings.
+# Note this only works for settings with default values. Some commands like --rerun
+# or --force-ccd n will have to be set in the command line (if you need to)
+
+# This line is really important to set up properly
+project_path: '/' #DO NOT CHANGE THIS OR DOCKER WILL NOT WORK. It should be '/'
+
+# The rest of the settings will default to the values set unless you uncomment and change them
+#resize_to: 2048
+#start_with: 'resize'
+#end_with: 'odm_orthophoto'
+#rerun_all: False
+#zip_results: False
+#verbose: False
+#time: False
+#use_fixed_camera_params: False
+#use_hybrid_bundle_adjustment: False
+#opensfm_processes: 4 # by default this is set to $(nproc)
+#min_num_features: 4000
+#matcher_threshold: 2.0
+#matcher_ratio: 0.6
+#matcher_neighbors: 8
+#matcher_distance: 0
+#use_pmvs: False # The cmvs/pmvs settings only matter if 'Enabled' is set to True
+#cmvs_maximages: 500
+#pmvs_level: 1
+#pmvs_csize: 2
+#pmvs_threshold: 0.7
+#pmvs_wsize: 7
+#pmvs_min_images: 3
+#pmvs_num_cores: 4 # by default this is set to $(nproc)
+#mesh_size: 100000
+#mesh_octree_depth: 9
+#mesh_samples: 1.0
+#mesh_solver_divide: 9
+#texturing_data_term: 'gmi'
+#texturing_outlier_removal_type: 'gauss_clamping'
+#texturing_skip_visibility_test: False
+#texturing_skip_global_seam_leveling: False
+#texturing_skip_local_seam_leveling: False
+#texturing_skip_hole_filling: False
+#texturing_keep_unseen_faces: False
+#texturing_tone_mapping: 'none'
+#gcp: !!null # YAML tag for None
+#use_exif: False # Set to True if you have a GCP file (it auto-detects) and want to use EXIF
+#dtm: False # Use this tag to build a DTM (Digital Terrain Model
+#dsm: False # Use this tag to build a DSM (Digital Surface Model
+#dem-gapfill-steps: 4
+#dem-resolution: 0.1
+#dem-maxangle:20
+#dem-maxsd: 2.5
+#dem-approximate: False
+#dem-decimation: 1
+#dem-terrain-type: ComplexForest
+#orthophoto_resolution: 20.0 # Pixels/meter
+#orthophoto_target_srs: !!null # Currently does nothing
+#orthophoto_no_tiled: False
+#orthophoto_compression: DEFLATE # Options are [JPEG, LZW, PACKBITS, DEFLATE, LZMA, NONE] Don't change unless you know what you are doing
+#orthophoto_bigtiff: IF_SAFER # Options are [YES, NO, IF_NEEDED, IF_SAFER]
+#build_overviews: FALSE
diff --git a/docker/README b/docker/README
new file mode 100644
index 000000000..f96e85d88
--- /dev/null
+++ b/docker/README
@@ -0,0 +1,3 @@
+The g++ and gcc scripts in this directory are used to replace the real g++ and gcc programs so that compilation across all projects (including dependencies) uses the -march=core2 flag, which allows us to build a docker image compatible with most Intel based CPUs.
+
+Without the -march=core2 flag, a docker image will contain binaries that are optimized for the machine that built the image, and will not run on older machines.
diff --git a/docker/g++ b/docker/g++
new file mode 100755
index 000000000..0206851b3
--- /dev/null
+++ b/docker/g++
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+args=""
+
+for i in "$@"
+do
+ if [[ $i != -march* ]]; then
+ args="$args $i"
+ fi
+done
+
+/usr/bin/g++_real -march=core2 $args
diff --git a/docker/gcc b/docker/gcc
new file mode 100755
index 000000000..d72824c66
--- /dev/null
+++ b/docker/gcc
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+args=""
+
+for i in "$@"
+do
+ if [[ $i != -march* ]]; then
+ args="$args $i"
+ fi
+done
+
+/usr/bin/gcc_real -march=core2 $args
diff --git a/hooks/pre-commit b/hooks/pre-commit
new file mode 100644
index 000000000..0a85afe45
--- /dev/null
+++ b/hooks/pre-commit
@@ -0,0 +1,23 @@
+#!/bin/sh
+#
+# An example hook script to verify what is about to be committed.
+# Called by "git commit" with no arguments. The hook should
+# exit with non-zero status after issuing an appropriate message if
+# it wants to stop the commit.
+#
+# To enable this hook, rename this file to "pre-commit".
+
+exec 1>&2
+
+echo "RUNNING PRE-COMMIT"
+EXIT_CODE=0
+# Get list of files about to be committed
+if git diff --cached --name-only --diff-filter=ACM | grep 'ccd_defs.json'; then
+ echo "We changed ccd_defs.json"
+ GIT_ROOT=$(git rev-parse --show-toplevel)
+ python $GIT_ROOT/ccd_defs_check.py
+ EXIT_CODE=$(echo $?)
+fi
+
+# non-zero exit fails the commit
+exit $EXIT_CODE
diff --git a/img/bellus_map.png b/img/bellus_map.png
new file mode 100644
index 000000000..305acb70d
Binary files /dev/null and b/img/bellus_map.png differ
diff --git a/img/mvs-text-orthphoto.png b/img/mvs-text-orthphoto.png
new file mode 100644
index 000000000..db8d210f5
Binary files /dev/null and b/img/mvs-text-orthphoto.png differ
diff --git a/img/odm_image.png b/img/odm_image.png
new file mode 100644
index 000000000..04817f567
Binary files /dev/null and b/img/odm_image.png differ
diff --git a/img/odm_orthophoto_test.png b/img/odm_orthophoto_test.png
new file mode 100644
index 000000000..113f8182f
Binary files /dev/null and b/img/odm_orthophoto_test.png differ
diff --git a/img/sm_seneca_orthophoto.png b/img/sm_seneca_orthophoto.png
new file mode 100644
index 000000000..2d1bc1543
Binary files /dev/null and b/img/sm_seneca_orthophoto.png differ
diff --git a/img/sm_tol_odm_orthophoto.png b/img/sm_tol_odm_orthophoto.png
new file mode 100644
index 000000000..fd7c40614
Binary files /dev/null and b/img/sm_tol_odm_orthophoto.png differ
diff --git a/img/tol_ptcloud.png b/img/tol_ptcloud.png
new file mode 100644
index 000000000..911fe9179
Binary files /dev/null and b/img/tol_ptcloud.png differ
diff --git a/img/tol_text.png b/img/tol_text.png
new file mode 100644
index 000000000..715b57485
Binary files /dev/null and b/img/tol_text.png differ
diff --git a/install-centos.sh b/install-centos.sh
deleted file mode 100644
index cd7e1167c..000000000
--- a/install-centos.sh
+++ /dev/null
@@ -1,342 +0,0 @@
-#!/bin/bash/bin/bash
-
-set -o nounset
-set -o errexit
-
-echo
-echo " created by Daniel Schwarz/daniel.schwarz@topoi.org"
-echo " released under Creative Commons/CC-BY"
-echo " Attribution"
-echo
-echo " if the script doesn't finish properly"
-echo " (i.e. it doesn't print \"script finished\" at the end)"
-echo " please email me the content of the logs folder"
-echo
-echo
-echo " - script started - `date`"
-
- ## dest base path
- TOOLS_PATH="$PWD"
-
- ## paths for the tools
- TOOLS_BIN_PATH="$TOOLS_PATH/bin"
- TOOLS_INC_PATH="$TOOLS_PATH/include"
- TOOLS_LIB_PATH="$TOOLS_PATH/lib"
- TOOLS_SRC_PATH="$TOOLS_PATH/src"
- TOOLS_LOG_PATH="$TOOLS_PATH/logs"
- TOOLS_PATCHED_PATH="$TOOLS_PATH/patched_files"
-
-## get sys vars
-ARCH=`uname -m`
-CORES=`grep -c processor /proc/cpuinfo`
-
- ## loacal dest paths
-if [ "$ARCH" = "i686" ]; then
- LIB_PATH="/lib"
-fi
-
-if [ "$ARCH" = "x86_64" ]; then
- LIB_PATH="/lib64"
-fi
-INC_PATH="/usr/local/include"
-
- ## source paths
- BUNDLER_PATH="$TOOLS_SRC_PATH/bundler"
- CMVS_PATH="$TOOLS_SRC_PATH/cmvs"
- PMVS_PATH="$TOOLS_SRC_PATH/pmvs"
- CLAPACK_PATH="$TOOLS_SRC_PATH/clapack"
- VLFEAT_PATH="$TOOLS_SRC_PATH/vlfeat"
- PARALLEL_PATH="$TOOLS_SRC_PATH/parallel"
- PSR_PATH="$TOOLS_SRC_PATH/PoissonRecon"
- GRACLUS_PATH="$TOOLS_SRC_PATH/graclus"
-
- ## executables
- EXTRACT_FOCAL="$TOOLS_BIN_PATH/extract_focal.pl"
- MATCHKEYS="$TOOLS_BIN_PATH/KeyMatch"
- MATCHKEYSFULL="$TOOLS_BIN_PATH/KeyMatchFull"
- BUNDLER="$TOOLS_BIN_PATH/bundler"
- BUNDLE2PVMS="$TOOLS_BIN_PATH/Bundle2PMVS"
- CMVS="$TOOLS_BIN_PATH/cmvs"
- PMVS="$TOOLS_BIN_PATH/pmvs2"
- GENOPTION="$TOOLS_BIN_PATH/genOption"
- VLSIFT="$TOOLS_BIN_PATH/vlsift"
- PARALLEL="$TOOLS_BIN_PATH/parallel"
- PSR="$TOOLS_BIN_PATH/PoissonRecon"
- VLSIFT_TO_LOWESIFT="$TOOLS_BIN_PATH/convert_vlsift_to_lowesift.pl"
-
-## prevents different (localized) output
-LC_ALL=C
-
-## removing old stuff
-sudo rm -Rf "$TOOLS_BIN_PATH"
-sudo rm -Rf "$TOOLS_INC_PATH"
-sudo rm -Rf "$TOOLS_LIB_PATH"
-sudo rm -Rf "$TOOLS_SRC_PATH"
-sudo rm -Rf "$TOOLS_LOG_PATH"
-
-## create needed directories
-mkdir -p "$TOOLS_BIN_PATH"
-mkdir -p "$TOOLS_INC_PATH"
-mkdir -p "$TOOLS_LIB_PATH"
-mkdir -p "$TOOLS_SRC_PATH"
-mkdir -p "$TOOLS_LOG_PATH"
-
-## output sys info
-echo "System info:" > "$TOOLS_LOG_PATH/sysinfo.txt"
-uname -a > "$TOOLS_LOG_PATH/sysinfo.txt"
-
-## install packages
-echo
-echo " > installing required packages"
-
-echo " - updating"
-sudo yum update -y > "$TOOLS_LOG_PATH/apt-get_get.log" 2>&1
-
-echo " - installing"
-yum install -y \
- cmake gcc gcc-c++ compat-gcc-32 compat-gcc-32-c++ gcc-gfortran perl ruby rubygems git \
- curl wget \
- unzip \
- ImageMagick jhead \
- libjpeg-devel boost-devel gsl-devel libX11-devel libXext-devel lapack-devel blas-devel \
- zlib-devel \
- opencv-devel \
- > "$TOOLS_LOG_PATH/apt-get_install.log" 2>&1
-
-sudo gem install parallel > /dev/null 2>&1
-
-echo " < done - `date`"
-
-## downloading sources
-echo
-echo " > getting the sources"
-
-## getting all archives if not already present; save them to .tmp and rename them after download
-while read target source
-do
- if [ ! -f "$target" ] ; then
- echo " - getting $source"
-
- curl --progress-bar --insecure --location -o "$target.tmp" "$source"
- mv "$target.tmp" "$target"
- echo " - finished $target"
- echo
- else
- echo " - already downloaded $source"
- fi
-done < "$TOOLS_LOG_PATH/extract_$i.log" 2>&1 &
-done
-for i in *.tgz *.tar.gz ; do
- tar xzf "$i" > "$TOOLS_LOG_PATH/extract_$i.log" 2>&1 &
-done
-for i in *.zip ; do
- unzip "$i" > "$TOOLS_LOG_PATH/extract_$i.log" 2>&1 &
-done
-
-wait
-
-mv -f graclus1.2 "$GRACLUS_PATH"
-mv -f clapack-3.2.1-CMAKE "$CLAPACK_PATH"
-mv -f vlfeat-0.9.13 "$VLFEAT_PATH"
-mv -f bundler-v0.4-source "$BUNDLER_PATH"
-mv -f parallel-20100922 "$PARALLEL_PATH"
-mv -f PoissonRecon "$PSR_PATH"
-mv -f cmvs "$CMVS_PATH"
-
-echo " < done - `date`"
-
-
-## copying patches
-echo
-echo " - copying patches"
-echo
-
-for file in `find $TOOLS_PATCHED_PATH -type f -print` ; do
- cp $file $TOOLS_PATH/${file/$TOOLS_PATCHED_PATH/.}
-done
-
-echo " < done - `date`"
-
-
-# building
-echo
-echo " - building"
-echo
-
-sudo chown -R `id -u`:`id -g` *
-sudo chmod -R 777 *
-
-
-echo " > graclus"
- cd "$GRACLUS_PATH"
-
- if [ "$ARCH" = "i686" ]; then
- sed -i "$GRACLUS_PATH/Makefile.in" -e "11c\COPTIONS = -DNUMBITS=32"
- fi
-
- if [ "$ARCH" = "x86_64" ]; then
- sed -i "$GRACLUS_PATH/Makefile.in" -e "11c\COPTIONS = -DNUMBITS=64"
- fi
-
- echo " - cleaning graclus"
- make clean > "$TOOLS_LOG_PATH/graclus_1_clean.log" 2>&1
-
- echo " - building graclus"
- make -j > "$TOOLS_LOG_PATH/graclus_2_build.log" 2>&1
-
- mkdir "$TOOLS_INC_PATH/metisLib"
- cp -f "$GRACLUS_PATH/metisLib/"*.h "$TOOLS_INC_PATH/metisLib/"
-
- cp -f lib* "$TOOLS_LIB_PATH/"
-echo " < done - `date`"
-echo
-
-echo " > poisson surface reconstruction "
- cd "$PSR_PATH"
-
- sed -i "$PSR_PATH/Makefile" -e "21c\BIN = ./"
-
- echo " - building poisson surface reconstruction"
- make -j > "$TOOLS_LOG_PATH/poisson_1_build.log" 2>&1
-
- cp -f "$PSR_PATH/PoissonRecon" "$TOOLS_BIN_PATH/PoissonRecon"
-
-echo " < done - `date`"
-echo
-
-
-echo " > parallel"
- cd "$PARALLEL_PATH"
-
- echo " - configuring parallel"
- ./configure > "$TOOLS_LOG_PATH/parallel_1_build.log" 2>&1
-
- echo " - building paralel"
- make -j > "$TOOLS_LOG_PATH/parallel_2_build.log" 2>&1
-
- cp -f src/parallel "$TOOLS_BIN_PATH/"
-
-echo " < done - `date`"
-echo
-
-
-echo " > clapack"
- cd "$CLAPACK_PATH"
- cp make.inc.example make.inc
-
- set +e
- echo " - building clapack"
- make all -j > "$TOOLS_LOG_PATH/clapack_1_build.log" 2>&1
- set -e
-
- echo " - installing clapack"
- make lapack_install > "$TOOLS_LOG_PATH/clapack_2_install.log" 2>&1
-
- cp -Rf INCLUDE "$INC_PATH/clapack"
-
-echo " < done - `date`"
-echo
-
-
-echo " > vlfeat"
- cd "$VLFEAT_PATH"
-
- echo " - installing vlfeat"
-
- if [ "$ARCH" = "i686" ]; then
- cp -f "$VLFEAT_PATH/bin/glnx86/sift" "$TOOLS_BIN_PATH/vlsift"
- cp -f "$VLFEAT_PATH/bin/glnx86/libvl.so" "$TOOLS_LIB_PATH/"
- fi
-
- if [ "$ARCH" = "x86_64" ]; then
- cp -f "$VLFEAT_PATH/bin/glnxa64/sift" "$TOOLS_BIN_PATH/vlsift"
- cp -f "$VLFEAT_PATH/bin/glnxa64/libvl.so" "$TOOLS_LIB_PATH/"
- fi
-echo " < done - `date`"
-echo
-
-
-echo " > cmvs"
- cd "$CMVS_PATH/program/main"
-
- sed -i "$CMVS_PATH/program/main/genOption.cc" -e "5c\#include \n"
- sed -i "$CMVS_PATH/program/base/cmvs/bundle.cc" -e "3c\#include \n"
-
- sed -i "$CMVS_PATH/program/main/Makefile" -e "10c\#Your INCLUDE path (e.g., -I\/usr\/include)"
- sed -i "$CMVS_PATH/program/main/Makefile" -e "11c\YOUR_INCLUDE_PATH =-I$INC_PATH -I$TOOLS_INC_PATH"
- sed -i "$CMVS_PATH/program/main/Makefile" -e "13c\#Your metis directory (contains header files under graclus1.2/metisLib/)"
- sed -i "$CMVS_PATH/program/main/Makefile" -e "14c\YOUR_INCLUDE_METIS_PATH = -I$TOOLS_INC_PATH/metisLib/"
- sed -i "$CMVS_PATH/program/main/Makefile" -e "16c\#Your LDLIBRARY path (e.g., -L/usr/lib)"
- sed -i "$CMVS_PATH/program/main/Makefile" -e "17c\YOUR_LDLIB_PATH = -L$LIB_PATH -L$TOOLS_LIB_PATH"
-
- if [ "$ARCH" = "i686" ]; then
- sed -i "$CMVS_PATH/program/main/Makefile" -e "22c\CXXFLAGS_CMVS = -O2 -Wall -Wno-deprecated -DNUMBITS=32 \\\\"
- sed -i "$CMVS_PATH/program/main/Makefile" -e '24c\ -fopenmp -DNUMBITS=32 ${OPENMP_FLAG}'
- fi
-
- if [ "$ARCH" = "x86_64" ]; then
- sed -i "$CMVS_PATH/program/main/Makefile" -e "22c\CXXFLAGS_CMVS = -O2 -Wall -Wno-deprecated -DNUMBITS=64 \\\\"
- sed -i "$CMVS_PATH/program/main/Makefile" -e '24c\ -fopenmp -DNUMBITS=64 ${OPENMP_FLAG}'
- fi
-
- echo " - cleaning cmvs"
- make clean > "$TOOLS_LOG_PATH/cmvs_1_clean.log" 2>&1
-
- echo " - building cmvs"
- make -j > "$TOOLS_LOG_PATH/cmvs_2_build.log" 2>&1
-
- echo " - make depend cmvs"
- sudo make depend > "$TOOLS_LOG_PATH/cmvs_3_depend.log" 2>&1
-
- cp -f "$CMVS_PATH/program/main/cmvs" "$CMVS_PATH/program/main/pmvs2" "$CMVS_PATH/program/main/genOption" "$TOOLS_BIN_PATH/"
- cp -f "$CMVS_PATH/program/main/"*so* "$TOOLS_LIB_PATH/"
-echo " < done - `date`"
-echo
-
-
-echo " > bundler"
- cd "$BUNDLER_PATH"
-
- sed -i "$BUNDLER_PATH/src/BundlerApp.h" -e "620c\ BundlerApp();"
-
- echo " - cleaning bundler"
- make clean > "$TOOLS_LOG_PATH/bundler_1_clean.log" 2>&1
-
- echo " - building bundler"
- make -j > "$TOOLS_LOG_PATH/bundler_2_build.log" 2>&1
-
- cp -f "$BUNDLER_PATH/bin/Bundle2PMVS" "$BUNDLER_PATH/bin/Bundle2Vis" "$BUNDLER_PATH/bin/KeyMatchFull" "$BUNDLER_PATH/bin/KeyMatch" "$BUNDLER_PATH/bin/bundler" "$BUNDLER_PATH/bin/RadialUndistort" "$TOOLS_BIN_PATH/"
-
- cp -f "$BUNDLER_PATH/lib/libANN_char.so" "$TOOLS_LIB_PATH/"
-echo " < done - `date`"
-echo
-
-
-cd "$TOOLS_PATH"
-
-sudo install -o `id -u` -g `id -g` -m 644 -t "$LIB_PATH" lib/*.so
-sudo /sbin/ldconfig -v > "$TOOLS_LOG_PATH/ldconfig.log" 2>&1
-
-sudo chown -R `id -u`:`id -g` *
-sudo chmod -R 777 *
-
-echo " - script finished - `date`"
-
-exit
diff --git a/install.sh b/install.sh
deleted file mode 100755
index 35ddbed1c..000000000
--- a/install.sh
+++ /dev/null
@@ -1,336 +0,0 @@
-#!/bin/bash
-
-set -o nounset
-set -o errexit
-
-echo
-echo " created by Daniel Schwarz/daniel.schwarz@topoi.org"
-echo " released under Creative Commons/CC-BY"
-echo " Attribution"
-echo
-echo " if the script doesn't finish properly"
-echo " (i.e. it doesn't print \"script finished\" at the end)"
-echo " please email me the content of the logs folder"
-echo
-echo
-echo " - script started - `date`"
-
- ## dest base path
- TOOLS_PATH="$PWD"
-
- ## paths for the tools
- TOOLS_BIN_PATH="$TOOLS_PATH/bin"
- TOOLS_INC_PATH="$TOOLS_PATH/include"
- TOOLS_LIB_PATH="$TOOLS_PATH/lib"
- TOOLS_SRC_PATH="$TOOLS_PATH/src"
- TOOLS_LOG_PATH="$TOOLS_PATH/logs"
- TOOLS_PATCHED_PATH="$TOOLS_PATH/patched_files"
-
- ## loacal dest paths
- LIB_PATH="/usr/local/lib"
- INC_PATH="/usr/local/include"
-
- ## source paths
- BUNDLER_PATH="$TOOLS_SRC_PATH/bundler"
- CMVS_PATH="$TOOLS_SRC_PATH/cmvs"
- PMVS_PATH="$TOOLS_SRC_PATH/pmvs"
- CLAPACK_PATH="$TOOLS_SRC_PATH/clapack"
- VLFEAT_PATH="$TOOLS_SRC_PATH/vlfeat"
- PARALLEL_PATH="$TOOLS_SRC_PATH/parallel"
- PSR_PATH="$TOOLS_SRC_PATH/PoissonRecon"
- GRACLUS_PATH="$TOOLS_SRC_PATH/graclus"
-
- ## executables
- EXTRACT_FOCAL="$TOOLS_BIN_PATH/extract_focal.pl"
- MATCHKEYS="$TOOLS_BIN_PATH/KeyMatch"
- MATCHKEYSFULL="$TOOLS_BIN_PATH/KeyMatchFull"
- BUNDLER="$TOOLS_BIN_PATH/bundler"
- BUNDLE2PVMS="$TOOLS_BIN_PATH/Bundle2PMVS"
- CMVS="$TOOLS_BIN_PATH/cmvs"
- PMVS="$TOOLS_BIN_PATH/pmvs2"
- GENOPTION="$TOOLS_BIN_PATH/genOption"
- VLSIFT="$TOOLS_BIN_PATH/vlsift"
- PARALLEL="$TOOLS_BIN_PATH/parallel"
- PSR="$TOOLS_BIN_PATH/PoissonRecon"
- VLSIFT_TO_LOWESIFT="$TOOLS_BIN_PATH/convert_vlsift_to_lowesift.pl"
-
-## get sys vars
-ARCH=`uname -m`
-CORES=`grep -c processor /proc/cpuinfo`
-
-## prevents different (localized) output
-LC_ALL=C
-
-## removing old stuff
-sudo rm -Rf "$TOOLS_BIN_PATH"
-sudo rm -Rf "$TOOLS_INC_PATH"
-sudo rm -Rf "$TOOLS_LIB_PATH"
-sudo rm -Rf "$TOOLS_SRC_PATH"
-sudo rm -Rf "$TOOLS_LOG_PATH"
-
-## create needed directories
-mkdir -p "$TOOLS_BIN_PATH"
-mkdir -p "$TOOLS_INC_PATH"
-mkdir -p "$TOOLS_LIB_PATH"
-mkdir -p "$TOOLS_SRC_PATH"
-mkdir -p "$TOOLS_LOG_PATH"
-
-## output sys info
-echo "System info:" > "$TOOLS_LOG_PATH/sysinfo.txt"
-uname -a > "$TOOLS_LOG_PATH/sysinfo.txt"
-
-## install packages
-echo
-echo " > installing required packages"
-
-echo " - updating"
-sudo apt-get update --assume-yes > "$TOOLS_LOG_PATH/apt-get_get.log" 2>&1
-
-echo " - installing"
-sudo apt-get install --assume-yes --install-recommends \
- build-essential cmake g++ gcc gFortran perl ruby rubygems git \
- curl wget \
- unzip \
- imagemagick jhead \
- libjpeg-dev libboost-dev libgsl0-dev libx11-dev libxext-dev liblapack-dev \
- libzip-dev \
- libcv-dev libcvaux-dev \
- > "$TOOLS_LOG_PATH/apt-get_install.log" 2>&1
-
-sudo gem install parallel > /dev/null 2>&1
-
-echo " < done - `date`"
-
-## downloading sources
-echo
-echo " > getting the sources"
-
-## getting all archives if not already present; save them to .tmp and rename them after download
-while read target source
-do
- if [ ! -f "$target" ] ; then
- echo " - getting $source"
-
- curl --progress-bar --location -o "$target.tmp" "$source"
- mv "$target.tmp" "$target"
- echo " - finished $target"
- echo
- else
- echo " - already downloaded $source"
- fi
-done < "$TOOLS_LOG_PATH/extract_$i.log" 2>&1 &
-done
-for i in *.tgz *.tar.gz ; do
- tar xzf "$i" > "$TOOLS_LOG_PATH/extract_$i.log" 2>&1 &
-done
-for i in *.zip ; do
- unzip "$i" > "$TOOLS_LOG_PATH/extract_$i.log" 2>&1 &
-done
-
-wait
-
-mv -f graclus1.2 "$GRACLUS_PATH"
-mv -f clapack-3.2.1-CMAKE "$CLAPACK_PATH"
-mv -f vlfeat-0.9.13 "$VLFEAT_PATH"
-mv -f bundler-v0.4-source "$BUNDLER_PATH"
-mv -f parallel-20100922 "$PARALLEL_PATH"
-mv -f PoissonRecon "$PSR_PATH"
-mv -f cmvs "$CMVS_PATH"
-
-echo " < done - `date`"
-
-
-## copying patches
-echo
-echo " - copying patches"
-echo
-
-for file in `find $TOOLS_PATCHED_PATH -type f -print` ; do
- cp $file $TOOLS_PATH/${file/$TOOLS_PATCHED_PATH/.}
-done
-
-echo " < done - `date`"
-
-
-# building
-echo
-echo " - building"
-echo
-
-sudo chown -R `id -u`:`id -g` *
-#sudo chmod -R 777 *
-
-
-echo " > graclus"
- cd "$GRACLUS_PATH"
-
- if [ "$ARCH" = "i686" ]; then
- sed -i "$GRACLUS_PATH/Makefile.in" -e "11c\COPTIONS = -DNUMBITS=32"
- fi
-
- if [ "$ARCH" = "x86_64" ]; then
- sed -i "$GRACLUS_PATH/Makefile.in" -e "11c\COPTIONS = -DNUMBITS=64"
- fi
-
- echo " - cleaning graclus"
- make clean > "$TOOLS_LOG_PATH/graclus_1_clean.log" 2>&1
-
- echo " - building graclus"
- make -j > "$TOOLS_LOG_PATH/graclus_2_build.log" 2>&1
-
- mkdir "$TOOLS_INC_PATH/metisLib"
- cp -f "$GRACLUS_PATH/metisLib/"*.h "$TOOLS_INC_PATH/metisLib/"
-
- cp -f lib* "$TOOLS_LIB_PATH/"
-echo " < done - `date`"
-echo
-
-echo " > poisson surface reconstruction "
- cd "$PSR_PATH"
-
- sed -i "$PSR_PATH/Makefile" -e "21c\BIN = ./"
-
- echo " - building poisson surface reconstruction"
- make -j > "$TOOLS_LOG_PATH/poisson_1_build.log" 2>&1
-
- cp -f "$PSR_PATH/PoissonRecon" "$TOOLS_BIN_PATH/PoissonRecon"
-
-echo " < done - `date`"
-echo
-
-
-echo " > parallel"
- cd "$PARALLEL_PATH"
-
- echo " - configuring parallel"
- ./configure > "$TOOLS_LOG_PATH/parallel_1_build.log" 2>&1
-
- echo " - building paralel"
- make -j > "$TOOLS_LOG_PATH/parallel_2_build.log" 2>&1
-
- cp -f src/parallel "$TOOLS_BIN_PATH/"
-
-echo " < done - `date`"
-echo
-
-
-echo " > clapack"
- cd "$CLAPACK_PATH"
- cp make.inc.example make.inc
-
- set +e
- echo " - building clapack"
- make all -j > "$TOOLS_LOG_PATH/clapack_1_build.log" 2>&1
- set -e
-
- echo " - installing clapack"
- make lapack_install > "$TOOLS_LOG_PATH/clapack_2_install.log" 2>&1
-
- sudo cp -Rf INCLUDE "$INC_PATH/clapack"
-
-echo " < done - `date`"
-echo
-
-
-echo " > vlfeat"
- cd "$VLFEAT_PATH"
-
- echo " - installing vlfeat"
-
- if [ "$ARCH" = "i686" ]; then
- cp -f "$VLFEAT_PATH/bin/glnx86/sift" "$TOOLS_BIN_PATH/vlsift"
- cp -f "$VLFEAT_PATH/bin/glnx86/libvl.so" "$TOOLS_LIB_PATH/"
- fi
-
- if [ "$ARCH" = "x86_64" ]; then
- cp -f "$VLFEAT_PATH/bin/glnxa64/sift" "$TOOLS_BIN_PATH/vlsift"
- cp -f "$VLFEAT_PATH/bin/glnxa64/libvl.so" "$TOOLS_LIB_PATH/"
- fi
-echo " < done - `date`"
-echo
-
-
-echo " > cmvs/pmvs"
- cd "$CMVS_PATH/program/main"
-
- sed -i "$CMVS_PATH/program/main/genOption.cc" -e "5c\#include \n"
- sed -i "$CMVS_PATH/program/base/cmvs/bundle.cc" -e "3c\#include \n"
-
- sed -i "$CMVS_PATH/program/main/Makefile" -e "10c\#Your INCLUDE path (e.g., -I\/usr\/include)"
- sed -i "$CMVS_PATH/program/main/Makefile" -e "11c\YOUR_INCLUDE_PATH =-I$INC_PATH -I$TOOLS_INC_PATH"
- sed -i "$CMVS_PATH/program/main/Makefile" -e "13c\#Your metis directory (contains header files under graclus1.2/metisLib/)"
- sed -i "$CMVS_PATH/program/main/Makefile" -e "14c\YOUR_INCLUDE_METIS_PATH = -I$TOOLS_INC_PATH/metisLib/"
- sed -i "$CMVS_PATH/program/main/Makefile" -e "16c\#Your LDLIBRARY path (e.g., -L/usr/lib)"
- sed -i "$CMVS_PATH/program/main/Makefile" -e "17c\YOUR_LDLIB_PATH = -L$LIB_PATH -L$TOOLS_LIB_PATH"
-
- if [ "$ARCH" = "i686" ]; then
- sed -i "$CMVS_PATH/program/main/Makefile" -e "22c\CXXFLAGS_CMVS = -O2 -Wall -Wno-deprecated -DNUMBITS=32 \\\\"
- sed -i "$CMVS_PATH/program/main/Makefile" -e '24c\ -fopenmp -DNUMBITS=32 ${OPENMP_FLAG}'
- fi
-
- if [ "$ARCH" = "x86_64" ]; then
- sed -i "$CMVS_PATH/program/main/Makefile" -e "22c\CXXFLAGS_CMVS = -O2 -Wall -Wno-deprecated -DNUMBITS=64 \\\\"
- sed -i "$CMVS_PATH/program/main/Makefile" -e '24c\ -fopenmp -DNUMBITS=64 ${OPENMP_FLAG}'
- fi
-
- echo " - cleaning cmvs"
- make clean > "$TOOLS_LOG_PATH/cmvs_1_clean.log" 2>&1
-
- echo " - building cmvs"
- make -j > "$TOOLS_LOG_PATH/cmvs_2_build.log" 2>&1
-
- echo " - make depend cmvs"
- sudo make depend > "$TOOLS_LOG_PATH/cmvs_3_depend.log" 2>&1
-
- cp -f "$CMVS_PATH/program/main/cmvs" "$CMVS_PATH/program/main/pmvs2" "$CMVS_PATH/program/main/genOption" "$TOOLS_BIN_PATH/"
- cp -f "$CMVS_PATH/program/main/"*so* "$TOOLS_LIB_PATH/"
-echo " < done - `date`"
-echo
-
-
-echo " > bundler"
- cd "$BUNDLER_PATH"
-
- sed -i "$BUNDLER_PATH/src/BundlerApp.h" -e "620c\ BundlerApp();"
-
- echo " - cleaning bundler"
- make clean > "$TOOLS_LOG_PATH/bundler_1_clean.log" 2>&1
-
- echo " - building bundler"
- make -j > "$TOOLS_LOG_PATH/bundler_2_build.log" 2>&1
-
- cp -f "$BUNDLER_PATH/bin/Bundle2PMVS" "$BUNDLER_PATH/bin/Bundle2Vis" "$BUNDLER_PATH/bin/KeyMatchFull" "$BUNDLER_PATH/bin/KeyMatch" "$BUNDLER_PATH/bin/bundler" "$BUNDLER_PATH/bin/RadialUndistort" "$TOOLS_BIN_PATH/"
-
- cp -f "$BUNDLER_PATH/lib/libANN_char.so" "$TOOLS_LIB_PATH/"
-echo " < done - `date`"
-echo
-
-
-cd "$TOOLS_PATH"
-
-sudo install -o `id -u` -g `id -g` -m 644 -t "$LIB_PATH" lib/*.so
-sudo ldconfig -v > "$TOOLS_LOG_PATH/ldconfig.log" 2>&1
-
-sudo chown -R `id -u`:`id -g` *
-#sudo chmod -R 777 *
-
-echo " - script finished - `date`"
-
-exit
diff --git a/licenses/libext_copyright.txt b/licenses/libext_copyright.txt
new file mode 100644
index 000000000..60cc18d54
--- /dev/null
+++ b/licenses/libext_copyright.txt
@@ -0,0 +1,199 @@
+This package was downloaded from
+http://xorg.freedesktop.org/releases/individual/lib/
+
+Copyright 1986, 1987, 1988, 1989, 1994, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+Copyright (c) 1996 Digital Equipment Corporation, Maynard, Massachusetts.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
+BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of Digital Equipment Corporation
+shall not be used in advertising or otherwise to promote the sale, use or other
+dealings in this Software without prior written authorization from Digital
+Equipment Corporation.
+
+Copyright (c) 1997 by Silicon Graphics Computer Systems, Inc.
+Permission to use, copy, modify, and distribute this
+software and its documentation for any purpose and without
+fee is hereby granted, provided that the above copyright
+notice appear in all copies and that both that copyright
+notice and this permission notice appear in supporting
+documentation, and that the name of Silicon Graphics not be
+used in advertising or publicity pertaining to distribution
+of the software without specific prior written permission.
+Silicon Graphics makes no representation about the suitability
+of this software for any purpose. It is provided "as is"
+without any express or implied warranty.
+SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
+GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
+THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+Copyright 1992 Network Computing Devices
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of NCD. not be used in advertising or
+publicity pertaining to distribution of the software without specific,
+written prior permission. NCD. makes no representations about the
+suitability of this software for any purpose. It is provided "as is"
+without express or implied warranty.
+
+NCD. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NCD.
+BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+Copyright 1991,1993 by Digital Equipment Corporation, Maynard, Massachusetts,
+and Olivetti Research Limited, Cambridge, England.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital or Olivetti
+not be used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL AND OLIVETTI DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL THEY BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
+Copyright 1986, 1987, 1988 by Hewlett-Packard Corporation
+
+Permission to use, copy, modify, and distribute this
+software and its documentation for any purpose and without
+fee is hereby granted, provided that the above copyright
+notice appear in all copies and that both that copyright
+notice and this permission notice appear in supporting
+documentation, and that the name of Hewlett-Packard not be used in
+advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+Hewlett-Packard makes no representations about the
+suitability of this software for any purpose. It is provided
+"as is" without express or implied warranty.
+
+This software is not subject to any license of the American
+Telephone and Telegraph Company or of the Regents of the
+University of California.
+
+Copyright (c) 1994, 1995 Hewlett-Packard Company
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the Hewlett-Packard
+Company shall not be used in advertising or otherwise to promote the
+sale, use or other dealings in this Software without prior written
+authorization from the Hewlett-Packard Company.
+
+Copyright Digital Equipment Corporation, 1996
+
+Permission to use, copy, modify, distribute, and sell this
+documentation for any purpose is hereby granted without fee,
+provided that the above copyright notice and this permission
+notice appear in all copies. Digital Equipment Corporation
+makes no representations about the suitability for any purpose
+of the information in this document. This documentation is
+provided ``as is'' without express or implied warranty.
+
+Copyright (c) 1999, 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice (including the next
+paragraph) shall be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+Copyright (c) 1989 X Consortium, Inc. and Digital Equipment Corporation.
+Copyright (c) 1992 X Consortium, Inc. and Intergraph Corporation.
+Copyright (c) 1993 X Consortium, Inc. and Silicon Graphics, Inc.
+Copyright (c) 1994, 1995 X Consortium, Inc. and Hewlett-Packard Company.
+
+Permission to use, copy, modify, and distribute this documentation for
+any purpose and without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+Digital Equipment Corporation, Intergraph Corporation, Silicon
+Graphics, Hewlett-Packard, and the X Consortium make no
+representations about the suitability for any purpose of the
+information in this document. This documentation is provided ``as is''
+without express or implied warranty.
diff --git a/licenses/libx11_copyright.txt b/licenses/libx11_copyright.txt
new file mode 100644
index 000000000..0d563ab13
--- /dev/null
+++ b/licenses/libx11_copyright.txt
@@ -0,0 +1,944 @@
+This package was downloaded from
+http://xorg.freedesktop.org/releases/individual/lib/
+
+The following is the 'standard copyright' agreed upon by most contributors,
+and is currently the canonical license preferred by the X.Org Foundation.
+This is a slight variant of the common MIT license form published by the
+Open Source Initiative at http://www.opensource.org/licenses/mit-license.php
+
+Copyright holders of new code should use this license statement where
+possible, and insert their name to this list. Please sort by surname
+for people, and by the full name for other entities (e.g. Juliusz
+Chroboczek sorts before Intel Corporation sorts before Daniel Stone).
+
+See each individual source file or directory for the license that applies
+to that file.
+
+Copyright (C) 2003-2006,2008 Jamey Sharp, Josh Triplett
+Copyright © 2009 Red Hat, Inc.
+Copyright 1990-1992,1999,2000,2004,2009,2010 Oracle and/or its affiliates.
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice (including the next
+paragraph) shall be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+ ----------------------------------------------------------------------
+
+The following licenses are 'legacy' - usually MIT/X11 licenses with the name
+of the copyright holder(s) in the license statement:
+
+Copyright 1984-1994, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+X Window System is a trademark of The Open Group.
+
+ ----------------------------------------
+
+Copyright 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1994, 1996 X Consortium
+Copyright 2000 The XFree86 Project, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from the X Consortium.
+
+Copyright 1985, 1986, 1987, 1988, 1989, 1990, 1991 by
+Digital Equipment Corporation
+
+Portions Copyright 1990, 1991 by Tektronix, Inc.
+
+Permission to use, copy, modify and distribute this documentation for
+any purpose and without fee is hereby granted, provided that the above
+copyright notice appears in all copies and that both that copyright notice
+and this permission notice appear in all copies, and that the names of
+Digital and Tektronix not be used in in advertising or publicity pertaining
+to this documentation without specific, written prior permission.
+Digital and Tektronix makes no representations about the suitability
+of this documentation for any purpose.
+It is provided ``as is'' without express or implied warranty.
+
+ ----------------------------------------
+
+Copyright (c) 1999-2000 Free Software Foundation, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+FREE SOFTWARE FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the Free Software Foundation
+shall not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization from the
+Free Software Foundation.
+
+ ----------------------------------------
+
+Code and supporting documentation (c) Copyright 1990 1991 Tektronix, Inc.
+ All Rights Reserved
+
+This file is a component of an X Window System-specific implementation
+of Xcms based on the TekColor Color Management System. TekColor is a
+trademark of Tektronix, Inc. The term "TekHVC" designates a particular
+color space that is the subject of U.S. Patent No. 4,985,853 (equivalent
+foreign patents pending). Permission is hereby granted to use, copy,
+modify, sell, and otherwise distribute this software and its
+documentation for any purpose and without fee, provided that:
+
+1. This copyright, permission, and disclaimer notice is reproduced in
+ all copies of this software and any modification thereof and in
+ supporting documentation;
+2. Any color-handling application which displays TekHVC color
+ cooordinates identifies these as TekHVC color coordinates in any
+ interface that displays these coordinates and in any associated
+ documentation;
+3. The term "TekHVC" is always used, and is only used, in association
+ with the mathematical derivations of the TekHVC Color Space,
+ including those provided in this file and any equivalent pathways and
+ mathematical derivations, regardless of digital (e.g., floating point
+ or integer) representation.
+
+Tektronix makes no representation about the suitability of this software
+for any purpose. It is provided "as is" and with all faults.
+
+TEKTRONIX DISCLAIMS ALL WARRANTIES APPLICABLE TO THIS SOFTWARE,
+INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE. IN NO EVENT SHALL TEKTRONIX BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER IN AN ACTION OF
+CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR THE PERFORMANCE OF THIS SOFTWARE.
+
+ ----------------------------------------
+
+(c) Copyright 1995 FUJITSU LIMITED
+This is source code modified by FUJITSU LIMITED under the Joint
+Development Agreement for the CDE/Motif PST.
+
+ ----------------------------------------
+
+Copyright 1992 by Oki Technosystems Laboratory, Inc.
+Copyright 1992 by Fuji Xerox Co., Ltd.
+
+Permission to use, copy, modify, distribute, and sell this software
+and its documentation for any purpose is hereby granted without fee,
+provided that the above copyright notice appear in all copies and
+that both that copyright notice and this permission notice appear
+in supporting documentation, and that the name of Oki Technosystems
+Laboratory and Fuji Xerox not be used in advertising or publicity
+pertaining to distribution of the software without specific, written
+prior permission.
+Oki Technosystems Laboratory and Fuji Xerox make no representations
+about the suitability of this software for any purpose. It is provided
+"as is" without express or implied warranty.
+
+OKI TECHNOSYSTEMS LABORATORY AND FUJI XEROX DISCLAIM ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL OKI TECHNOSYSTEMS
+LABORATORY AND FUJI XEROX BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
+OR PERFORMANCE OF THIS SOFTWARE.
+
+ ----------------------------------------
+
+Copyright 1990, 1991, 1992, 1993, 1994 by FUJITSU LIMITED
+
+Permission to use, copy, modify, distribute, and sell this software
+and its documentation for any purpose is hereby granted without fee,
+provided that the above copyright notice appear in all copies and
+that both that copyright notice and this permission notice appear
+in supporting documentation, and that the name of FUJITSU LIMITED
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+FUJITSU LIMITED makes no representations about the suitability of
+this software for any purpose.
+It is provided "as is" without express or implied warranty.
+
+FUJITSU LIMITED DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+EVENT SHALL FUJITSU LIMITED BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
+ ----------------------------------------
+
+
+Copyright (c) 1995 David E. Wexelblat. All rights reserved
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL DAVID E. WEXELBLAT BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of David E. Wexelblat shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from David E. Wexelblat.
+
+ ----------------------------------------
+
+Copyright 1990, 1991 by OMRON Corporation
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name OMRON not be used in
+advertising or publicity pertaining to distribution of the software without
+specific, written prior permission. OMRON makes no representations
+about the suitability of this software for any purpose. It is provided
+"as is" without express or implied warranty.
+
+OMRON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+EVENT SHALL OMRON BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTUOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
+ ----------------------------------------
+
+Copyright 1985, 1986, 1987, 1988, 1989, 1990, 1991 by
+Digital Equipment Corporation
+
+Portions Copyright 1990, 1991 by Tektronix, Inc
+
+Rewritten for X.org by Chris Lee
+
+Permission to use, copy, modify, distribute, and sell this documentation
+for any purpose and without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+Chris Lee makes no representations about the suitability for any purpose
+of the information in this document. It is provided \`\`as-is'' without
+express or implied warranty.
+
+ ----------------------------------------
+
+Copyright 1993 by Digital Equipment Corporation, Maynard, Massachusetts,
+Copyright 1994 by FUJITSU LIMITED
+Copyright 1994 by Sony Corporation
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Digital, FUJITSU
+LIMITED and Sony Corporation not be used in advertising or publicity
+pertaining to distribution of the software without specific, written
+prior permission.
+
+DIGITAL, FUJITSU LIMITED AND SONY CORPORATION DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DIGITAL, FUJITSU LIMITED
+AND SONY CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
+ ----------------------------------------
+
+
+Copyright 1991 by the Open Software Foundation
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of Open Software Foundation
+not be used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission. Open Software
+Foundation makes no representations about the suitability of this
+software for any purpose. It is provided "as is" without express or
+implied warranty.
+
+OPEN SOFTWARE FOUNDATION DISCLAIMS ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL OPEN SOFTWARE FOUNDATIONN BE
+LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ ----------------------------------------
+
+Copyright 1990, 1991, 1992,1993, 1994 by FUJITSU LIMITED
+Copyright 1993, 1994 by Sony Corporation
+
+Permission to use, copy, modify, distribute, and sell this software and
+its documentation for any purpose is hereby granted without fee, provided
+that the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of FUJITSU LIMITED and Sony Corporation
+not be used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission. FUJITSU LIMITED and
+Sony Corporation makes no representations about the suitability of this
+software for any purpose. It is provided "as is" without express or
+implied warranty.
+
+FUJITSU LIMITED AND SONY CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD
+TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL FUJITSU LIMITED OR SONY CORPORATION BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
+USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ ----------------------------------------
+
+Copyright (c) 1993, 1995 by Silicon Graphics Computer Systems, Inc.
+
+Permission to use, copy, modify, and distribute this
+software and its documentation for any purpose and without
+fee is hereby granted, provided that the above copyright
+notice appear in all copies and that both that copyright
+notice and this permission notice appear in supporting
+documentation, and that the name of Silicon Graphics not be
+used in advertising or publicity pertaining to distribution
+of the software without specific prior written permission.
+Silicon Graphics makes no representation about the suitability
+of this software for any purpose. It is provided "as is"
+without any express or implied warranty.
+
+SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
+GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
+THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ ----------------------------------------
+
+Copyright 1991, 1992, 1993, 1994 by FUJITSU LIMITED
+Copyright 1993 by Digital Equipment Corporation
+
+Permission to use, copy, modify, distribute, and sell this software
+and its documentation for any purpose is hereby granted without fee,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of FUJITSU LIMITED and
+Digital Equipment Corporation not be used in advertising or publicity
+pertaining to distribution of the software without specific, written
+prior permission. FUJITSU LIMITED and Digital Equipment Corporation
+makes no representations about the suitability of this software for
+any purpose. It is provided "as is" without express or implied
+warranty.
+
+FUJITSU LIMITED AND DIGITAL EQUIPMENT CORPORATION DISCLAIM ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+FUJITSU LIMITED AND DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR
+ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+
+ ----------------------------------------
+
+Copyright 1992, 1993 by FUJITSU LIMITED
+Copyright 1993 by Fujitsu Open Systems Solutions, Inc.
+Copyright 1994 by Sony Corporation
+
+Permission to use, copy, modify, distribute and sell this software
+and its documentation for any purpose is hereby granted without fee,
+provided that the above copyright notice appear in all copies and
+that both that copyright notice and this permission notice appear
+in supporting documentation, and that the name of FUJITSU LIMITED,
+Fujitsu Open Systems Solutions, Inc. and Sony Corporation not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+FUJITSU LIMITED, Fujitsu Open Systems Solutions, Inc. and
+Sony Corporation make no representations about the suitability of
+this software for any purpose. It is provided "as is" without
+express or implied warranty.
+
+FUJITSU LIMITED, FUJITSU OPEN SYSTEMS SOLUTIONS, INC. AND SONY
+CORPORATION DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
+IN NO EVENT SHALL FUJITSU OPEN SYSTEMS SOLUTIONS, INC., FUJITSU LIMITED
+AND SONY CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
+OR PERFORMANCE OF THIS SOFTWARE.
+
+ ----------------------------------------
+
+Copyright 1987, 1988, 1990, 1993 by Digital Equipment Corporation,
+Maynard, Massachusetts,
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+ ----------------------------------------
+
+Copyright 1993 by SunSoft, Inc.
+Copyright 1999-2000 by Bruno Haible
+
+Permission to use, copy, modify, distribute, and sell this software
+and its documentation for any purpose is hereby granted without fee,
+provided that the above copyright notice appear in all copies and
+that both that copyright notice and this permission notice appear
+in supporting documentation, and that the names of SunSoft, Inc. and
+Bruno Haible not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission. SunSoft, Inc. and Bruno Haible make no representations
+about the suitability of this software for any purpose. It is
+provided "as is" without express or implied warranty.
+
+SunSoft Inc. AND Bruno Haible DISCLAIM ALL WARRANTIES WITH REGARD
+TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS, IN NO EVENT SHALL SunSoft, Inc. OR Bruno Haible BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ ----------------------------------------
+
+Copyright 1991 by the Open Software Foundation
+Copyright 1993 by the TOSHIBA Corp.
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the names of Open Software Foundation and TOSHIBA
+not be used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission. Open Software
+Foundation and TOSHIBA make no representations about the suitability of this
+software for any purpose. It is provided "as is" without express or
+implied warranty.
+
+OPEN SOFTWARE FOUNDATION AND TOSHIBA DISCLAIM ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL OPEN SOFTWARE FOUNDATIONN OR TOSHIBA BE
+LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ ----------------------------------------
+
+Copyright 1988 by Wyse Technology, Inc., San Jose, Ca.,
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name Wyse not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+WYSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+ ----------------------------------------
+
+
+Copyright 1991 by the Open Software Foundation
+Copyright 1993, 1994 by the Sony Corporation
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the names of Open Software Foundation and
+Sony Corporation not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+Open Software Foundation and Sony Corporation make no
+representations about the suitability of this software for any purpose.
+It is provided "as is" without express or implied warranty.
+
+OPEN SOFTWARE FOUNDATION AND SONY CORPORATION DISCLAIM ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL OPEN
+SOFTWARE FOUNDATIONN OR SONY CORPORATION BE LIABLE FOR ANY SPECIAL,
+INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
+ ----------------------------------------
+
+Copyright 1992, 1993 by FUJITSU LIMITED
+Copyright 1993 by Fujitsu Open Systems Solutions, Inc.
+
+Permission to use, copy, modify, distribute and sell this software
+and its documentation for any purpose is hereby granted without fee,
+provided that the above copyright notice appear in all copies and
+that both that copyright notice and this permission notice appear
+in supporting documentation, and that the name of FUJITSU LIMITED and
+Fujitsu Open Systems Solutions, Inc. not be used in advertising or
+publicity pertaining to distribution of the software without specific,
+written prior permission.
+FUJITSU LIMITED and Fujitsu Open Systems Solutions, Inc. makes no
+representations about the suitability of this software for any purpose.
+It is provided "as is" without express or implied warranty.
+
+FUJITSU LIMITED AND FUJITSU OPEN SYSTEMS SOLUTIONS, INC. DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL FUJITSU OPEN SYSTEMS
+SOLUTIONS, INC. AND FUJITSU LIMITED BE LIABLE FOR ANY SPECIAL, INDIRECT
+OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+OF THIS SOFTWARE.
+
+ ----------------------------------------
+
+Copyright 1993, 1994 by Sony Corporation
+
+Permission to use, copy, modify, distribute, and sell this software
+and its documentation for any purpose is hereby granted without fee,
+provided that the above copyright notice appear in all copies and
+that both that copyright notice and this permission notice appear
+in supporting documentation, and that the name of Sony Corporation
+not be used in advertising or publicity pertaining to distribution
+of the software without specific, written prior permission.
+Sony Corporation makes no representations about the suitability of
+this software for any purpose. It is provided "as is" without
+express or implied warranty.
+
+SONY CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+EVENT SHALL SONY CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
+ ----------------------------------------
+
+Copyright 1986, 1998 The Open Group
+Copyright (c) 2000 The XFree86 Project, Inc.
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+X CONSORTIUM OR THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium or of the
+XFree86 Project shall not be used in advertising or otherwise to promote the
+sale, use or other dealings in this Software without prior written
+authorization from the X Consortium and the XFree86 Project.
+
+ ----------------------------------------
+
+Copyright 1990, 1991 by OMRON Corporation, NTT Software Corporation,
+ and Nippon Telegraph and Telephone Corporation
+Copyright 1991 by the Open Software Foundation
+Copyright 1993 by the FUJITSU LIMITED
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the names of OMRON, NTT Software, NTT, and
+Open Software Foundation not be used in advertising or publicity
+pertaining to distribution of the software without specific,
+written prior permission. OMRON, NTT Software, NTT, and Open Software
+Foundation make no representations about the suitability of this
+software for any purpose. It is provided "as is" without express or
+implied warranty.
+
+OMRON, NTT SOFTWARE, NTT, AND OPEN SOFTWARE FOUNDATION
+DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
+SHALL OMRON, NTT SOFTWARE, NTT, OR OPEN SOFTWARE FOUNDATION BE
+LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ ----------------------------------------
+
+Copyright 1988 by Wyse Technology, Inc., San Jose, Ca,
+Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL AND WYSE DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+EVENT SHALL DIGITAL OR WYSE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
+ ----------------------------------------
+
+
+Copyright 1991, 1992 by Fuji Xerox Co., Ltd.
+Copyright 1992, 1993, 1994 by FUJITSU LIMITED
+
+Permission to use, copy, modify, distribute, and sell this software
+and its documentation for any purpose is hereby granted without fee,
+provided that the above copyright notice appear in all copies and
+that both that copyright notice and this permission notice appear
+in supporting documentation, and that the name of Fuji Xerox,
+FUJITSU LIMITED not be used in advertising or publicity pertaining
+to distribution of the software without specific, written prior
+permission. Fuji Xerox, FUJITSU LIMITED make no representations
+about the suitability of this software for any purpose.
+It is provided "as is" without express or implied warranty.
+
+FUJI XEROX, FUJITSU LIMITED DISCLAIM ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL FUJI XEROX,
+FUJITSU LIMITED BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
+DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
+ ----------------------------------------
+
+Copyright 2006 Josh Triplett
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+ ----------------------------------------
+
+(c) Copyright 1996 by Sebastien Marineau and Holger Veit
+
+
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+HOLGER VEIT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+Except as contained in this notice, the name of Sebastien Marineau or Holger Veit
+shall not be used in advertising or otherwise to promote the sale, use or other
+dealings in this Software without prior written authorization from Holger Veit or
+Sebastien Marineau.
+
+ ----------------------------------------
+
+Copyright 1990, 1991 by OMRON Corporation, NTT Software Corporation,
+ and Nippon Telegraph and Telephone Corporation
+Copyright 1991 by the Open Software Foundation
+Copyright 1993 by the TOSHIBA Corp.
+Copyright 1993, 1994 by Sony Corporation
+Copyright 1993, 1994 by the FUJITSU LIMITED
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the names of OMRON, NTT Software, NTT, Open
+Software Foundation, and Sony Corporation not be used in advertising
+or publicity pertaining to distribution of the software without specific,
+written prior permission. OMRON, NTT Software, NTT, Open Software
+Foundation, and Sony Corporation make no representations about the
+suitability of this software for any purpose. It is provided "as is"
+without express or implied warranty.
+
+OMRON, NTT SOFTWARE, NTT, OPEN SOFTWARE FOUNDATION, AND SONY
+CORPORATION DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
+SHALL OMRON, NTT SOFTWARE, NTT, OPEN SOFTWARE FOUNDATION, OR SONY
+CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+ ----------------------------------------
+
+Copyright 2000 by Bruno Haible
+
+Permission to use, copy, modify, distribute, and sell this software
+and its documentation for any purpose is hereby granted without fee,
+provided that the above copyright notice appear in all copies and
+that both that copyright notice and this permission notice appear
+in supporting documentation, and that the name of Bruno Haible not
+be used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission. Bruno Haible
+makes no representations about the suitability of this software for
+any purpose. It is provided "as is" without express or implied
+warranty.
+
+Bruno Haible DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+NO EVENT SHALL Bruno Haible BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
+OR PERFORMANCE OF THIS SOFTWARE.
+
+ ----------------------------------------
+
+Copyright © 2003 Keith Packard
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of Keith Packard not be used in
+advertising or publicity pertaining to distribution of the software without
+specific, written prior permission. Keith Packard makes no
+representations about the suitability of this software for any purpose. It
+is provided "as is" without express or implied warranty.
+
+KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
+ ----------------------------------------
+
+Copyright (c) 2007-2009, Troy D. Hanson
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ ----------------------------------------
+
+Copyright 1992, 1993 by TOSHIBA Corp.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted, provided
+that the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of TOSHIBA not be used in advertising
+or publicity pertaining to distribution of the software without specific,
+written prior permission. TOSHIBA make no representations about the
+suitability of this software for any purpose. It is provided "as is"
+without express or implied warranty.
+
+TOSHIBA DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+TOSHIBA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+
+ ----------------------------------------
+
+Copyright IBM Corporation 1993
+
+All Rights Reserved
+
+License to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of IBM not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS, AND
+NONINFRINGEMENT OF THIRD PARTY RIGHTS, IN NO EVENT SHALL
+IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+ ----------------------------------------
+
+Copyright 1990, 1991 by OMRON Corporation, NTT Software Corporation,
+ and Nippon Telegraph and Telephone Corporation
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the names of OMRON, NTT Software, and NTT
+not be used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission. OMRON, NTT Software,
+and NTT make no representations about the suitability of this
+software for any purpose. It is provided "as is" without express or
+implied warranty.
+
+OMRON, NTT SOFTWARE, AND NTT, DISCLAIM ALL WARRANTIES WITH REGARD
+TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS, IN NO EVENT SHALL OMRON, NTT SOFTWARE, OR NTT, BE
+LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/licenses/license.md b/licenses/license.md
new file mode 100644
index 000000000..7cd375fd3
--- /dev/null
+++ b/licenses/license.md
@@ -0,0 +1,27 @@
+Licensing for portions of OpenDroneMap are as follows:
+* ImageMagick - Apache 2.0 - http://www.imagemagick.org/script/license.php
+* Jhead - None - http://www.sentex.net/~mwandel/jhead/
+* libjpeg - GPLv2 - http://sourceforge.net/projects/libjpeg/
+* Boost - Boost Software License, Version 1.0 - http://www.boost.org/LICENSE_1_0.txt
+* libgsl0 - GPL - http://www.gnu.org/software/gsl/
+* liblapack - Modified BSD - http://www.netlib.org/lapack/LICENSE.txt
+* Flann - BSD2 - http://opensource.org/licenses/bsd-license.php
+* libzip - BSD - http://www.nih.at/libzip/LICENSE.html
+* libcv - BSD - http://opencv.org/license.html
+* libcvaux - BSD - http://opencv.org/license.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
+* PoissonRecon - BSD - http://www.cs.jhu.edu/~misha/Code/PoissonRecon/license.txt
+* vlfeat - BSD - http://www.vlfeat.org/license.html
+* graclus - GPLv3 - http://www.gnu.org/copyleft/gpl.html
+* PROJ.4 - MIT - http://trac.osgeo.org/proj/wiki/WikiStart#License
+* PCL - BSD - http://pointclouds.org
+ * Flann - BSD2 - http://opensource.org/licenses/bsd-license.php
+ * Eigen - MPL2 - http://www.mozilla.org/MPL/2.0
+ * Qhull - http://www.qhull.org/COPYING.txt
+ * 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
diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt
new file mode 100644
index 000000000..e1afd164b
--- /dev/null
+++ b/modules/CMakeLists.txt
@@ -0,0 +1,9 @@
+# Add ODM sub-modules
+add_subdirectory(odm_extract_utm)
+add_subdirectory(odm_georef)
+add_subdirectory(odm_meshing)
+add_subdirectory(odm_orthophoto)
+add_subdirectory(odm_25dmeshing)
+if (ODM_BUILD_SLAM)
+ add_subdirectory(odm_slam)
+endif ()
diff --git a/modules/odm_25dmeshing/CMakeLists.txt b/modules/odm_25dmeshing/CMakeLists.txt
new file mode 100644
index 000000000..4c19bbbed
--- /dev/null
+++ b/modules/odm_25dmeshing/CMakeLists.txt
@@ -0,0 +1,47 @@
+project(odm_25dmeshing)
+cmake_minimum_required(VERSION 2.8)
+
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR})
+
+# Set pcl dir to the input spedified with option -DCGAL_DIR="path"
+set(CGAL_DIR "CGAL_DIR-NOTFOUND" CACHE "CGAL_DIR" "Path to the CGAL installation directory")
+
+# Link
+find_package(CGAL COMPONENTS Core HINTS "${CGAL_DIR}")
+
+if ( CGAL_FOUND )
+
+ find_package( Eigen3 )
+
+ if( EIGEN3_FOUND )
+ include_directories(${EIGEN3_INCLUDE_DIR})
+ add_definitions(-DCGAL_EIGEN3_ENABLED)
+ else()
+ message(FATAL_ERROR "This program requires the Eigen3 library, and will not be compiled.")
+ endif()
+
+ include( ${CGAL_USE_FILE} )
+
+ find_package( TBB )
+ if( TBB_FOUND )
+ include(${TBB_USE_FILE})
+ else()
+ message(WARNING "TBB not found, parallel processing will be disabled.")
+ endif()
+
+ # Add compiler options.
+ add_definitions(-Wall -Wextra -std=c++11)
+
+ # Add source directory
+ aux_source_directory("./src" SRC_LIST)
+
+ # Add exectuteable
+ add_executable(${PROJECT_NAME} ${SRC_LIST})
+
+ target_link_libraries(odm_25dmeshing ${CGAL_LIBRARIES} ${TBB_LIBRARIES})
+else()
+
+ message(FATAL_ERROR "This program requires the CGAL library, and will not be compiled.")
+
+endif()
+
diff --git a/modules/odm_25dmeshing/FindEigen3.cmake b/modules/odm_25dmeshing/FindEigen3.cmake
new file mode 100644
index 000000000..e56005eb3
--- /dev/null
+++ b/modules/odm_25dmeshing/FindEigen3.cmake
@@ -0,0 +1,84 @@
+# - Try to find Eigen3 lib
+#
+# This module supports requiring a minimum version, e.g. you can do
+# find_package(Eigen3 3.1.2)
+# to require version 3.1.2 or newer of Eigen3.
+#
+# Once done this will define
+#
+# EIGEN3_FOUND - system has eigen lib with correct version
+# EIGEN3_INCLUDE_DIR - the eigen include directory
+# EIGEN3_VERSION - eigen version
+
+# Copyright (c) 2006, 2007 Montel Laurent,
+# Copyright (c) 2008, 2009 Gael Guennebaud,
+# Copyright (c) 2009 Benoit Jacob
+# Redistribution and use is allowed according to the terms of the 2-clause BSD license.
+
+include(FindPackageHandleStandardArgs)
+
+if(NOT Eigen3_FIND_VERSION)
+ if(NOT Eigen3_FIND_VERSION_MAJOR)
+ set(Eigen3_FIND_VERSION_MAJOR 2)
+ endif(NOT Eigen3_FIND_VERSION_MAJOR)
+ if(NOT Eigen3_FIND_VERSION_MINOR)
+ set(Eigen3_FIND_VERSION_MINOR 91)
+ endif(NOT Eigen3_FIND_VERSION_MINOR)
+ if(NOT Eigen3_FIND_VERSION_PATCH)
+ set(Eigen3_FIND_VERSION_PATCH 0)
+ endif(NOT Eigen3_FIND_VERSION_PATCH)
+
+ set(Eigen3_FIND_VERSION "${Eigen3_FIND_VERSION_MAJOR}.${Eigen3_FIND_VERSION_MINOR}.${Eigen3_FIND_VERSION_PATCH}")
+endif(NOT Eigen3_FIND_VERSION)
+
+macro(_eigen3_get_version)
+ file(READ "${EIGEN3_INCLUDE_DIR}/Eigen/src/Core/util/Macros.h" _eigen3_version_header)
+
+ string(REGEX MATCH "define[ \t]+EIGEN_WORLD_VERSION[ \t]+([0-9]+)" _eigen3_world_version_match "${_eigen3_version_header}")
+ set(EIGEN3_WORLD_VERSION "${CMAKE_MATCH_1}")
+ string(REGEX MATCH "define[ \t]+EIGEN_MAJOR_VERSION[ \t]+([0-9]+)" _eigen3_major_version_match "${_eigen3_version_header}")
+ set(EIGEN3_MAJOR_VERSION "${CMAKE_MATCH_1}")
+ string(REGEX MATCH "define[ \t]+EIGEN_MINOR_VERSION[ \t]+([0-9]+)" _eigen3_minor_version_match "${_eigen3_version_header}")
+ set(EIGEN3_MINOR_VERSION "${CMAKE_MATCH_1}")
+
+ set(EIGEN3_VERSION ${EIGEN3_WORLD_VERSION}.${EIGEN3_MAJOR_VERSION}.${EIGEN3_MINOR_VERSION})
+endmacro(_eigen3_get_version)
+
+if (EIGEN3_INCLUDE_DIR)
+
+ if (EXISTS ${EIGEN3_INCLUDE_DIR}/signature_of_eigen3_matrix_library)
+ # in cache already and valid
+ _eigen3_get_version()
+ set(EIGEN3_FOUND ${EIGEN3_VERSION_OK})
+
+ find_package_handle_standard_args(Eigen3
+ REQUIRED_VARS EIGEN3_INCLUDE_DIR
+ VERSION_VAR EIGEN3_VERSION)
+
+ else()
+ message(STATUS "Eigen3 path specified in cmake variable EIGEN3_INCLUDE_DIR is "
+ "set to ${EIGEN3_INCLUDE_DIR}, but that path does not contains the file "
+ "signature_of_eigen3_matrix_library and is considered as invalid.")
+ endif()
+
+
+
+else (EIGEN3_INCLUDE_DIR)
+
+ find_path(EIGEN3_INCLUDE_DIR NAMES signature_of_eigen3_matrix_library
+ HINTS ENV EIGEN3_INC_DIR
+ ENV EIGEN3_DIR
+ PATHS ${KDE4_INCLUDE_DIR}
+ PATH_SUFFIXES include eigen3 eigen
+ DOC "Directory containing the Eigen3 header files"
+ )
+
+ if(EIGEN3_INCLUDE_DIR)
+ _eigen3_get_version()
+ endif(EIGEN3_INCLUDE_DIR)
+
+ find_package_handle_standard_args(Eigen3
+ REQUIRED_VARS EIGEN3_INCLUDE_DIR
+ VERSION_VAR EIGEN3_VERSION)
+
+endif(EIGEN3_INCLUDE_DIR)
diff --git a/modules/odm_25dmeshing/src/CGAL.hpp b/modules/odm_25dmeshing/src/CGAL.hpp
new file mode 100644
index 000000000..b203cae98
--- /dev/null
+++ b/modules/odm_25dmeshing/src/CGAL.hpp
@@ -0,0 +1,38 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
+typedef Kernel::FT FT;
+typedef Kernel::Point_3 Point3;
+typedef Kernel::Vector_3 Vector3;
+
+//We define a vertex_base with info. The "info" (size_t) allow us to keep track of the original point index.
+typedef CGAL::Triangulation_vertex_base_with_info_2 Vb;
+typedef CGAL::Constrained_triangulation_face_base_2 Fb;
+typedef CGAL::Triangulation_data_structure_2 Tds;
+typedef CGAL::Constrained_Delaunay_triangulation_2 CDT;
+
+typedef CGAL::Polyhedron_3 Polyhedron;
+typedef Polyhedron::HalfedgeDS HalfedgeDS;
+
+namespace SMS = CGAL::Surface_mesh_simplification;
+
+// Concurrency
+#ifdef CGAL_LINKED_WITH_TBB
+typedef CGAL::Parallel_tag Concurrency_tag;
+#else
+typedef CGAL::Sequential_tag Concurrency_tag;
+#endif
+
+//typedef CGAL::First_of_pair_property_map Point_map;
+//typedef CGAL::Second_of_pair_property_map Normal_map;
+
diff --git a/modules/odm_25dmeshing/src/Logger.cpp b/modules/odm_25dmeshing/src/Logger.cpp
new file mode 100644
index 000000000..a6c81a8b5
--- /dev/null
+++ b/modules/odm_25dmeshing/src/Logger.cpp
@@ -0,0 +1,31 @@
+#include "Logger.hpp"
+
+
+Logger::Logger(bool isPrintingInCout) : isPrintingInCout_(isPrintingInCout)
+{
+
+}
+
+Logger::~Logger()
+{
+
+}
+
+void Logger::printToFile(std::string filePath)
+{
+ std::ofstream file(filePath.c_str(), std::ios::binary);
+ file << logStream_.str();
+ file.close();
+}
+
+bool Logger::isPrintingInCout() const
+{
+ return isPrintingInCout_;
+}
+
+void Logger::setIsPrintingInCout(bool isPrintingInCout)
+{
+ isPrintingInCout_ = isPrintingInCout;
+}
+
+
diff --git a/modules/odm_25dmeshing/src/Logger.hpp b/modules/odm_25dmeshing/src/Logger.hpp
new file mode 100644
index 000000000..aa1dcad6a
--- /dev/null
+++ b/modules/odm_25dmeshing/src/Logger.hpp
@@ -0,0 +1,67 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+
+/*!
+ * \brief The Logger class is used to store program messages in a log file.
+ * \details By using the << operator while printInCout is set, the class writes both to
+ * cout and to file, if the flag is not set, output is written to file only.
+ */
+class Logger
+{
+public:
+ /*!
+ * \brief Logger Contains functionality for printing and displaying log information.
+ * \param printInCout Flag toggling if operator << also writes to cout.
+ */
+ Logger(bool isPrintingInCout = true);
+
+ /*!
+ * \brief Destructor.
+ */
+ ~Logger();
+
+ /*!
+ * \brief print Prints the contents of the log to file.
+ * \param filePath Path specifying where to write the log.
+ */
+ void printToFile(std::string filePath);
+
+ /*!
+ * \brief isPrintingInCout Check if console printing flag is set.
+ * \return Console printing flag.
+ */
+ bool isPrintingInCout() const;
+
+ /*!
+ * \brief setIsPrintingInCout Set console printing flag.
+ * \param isPrintingInCout Value, if true, messages added to the log are also printed in cout.
+ */
+ void setIsPrintingInCout(bool isPrintingInCout);
+
+ /*!
+ * Operator for printing messages to log and in the standard output stream if desired.
+ */
+ template
+ friend Logger& operator<< (Logger &log, T t)
+ {
+ // If console printing is enabled.
+ if (log.isPrintingInCout_)
+ {
+ std::cout << t;
+ std::cout.flush();
+ }
+ // Write to log.
+ log.logStream_ << t;
+
+ return log;
+ }
+
+private:
+ bool isPrintingInCout_; /*!< If flag is set, log is printed in cout and written to the log. */
+
+ std::stringstream logStream_; /*!< Stream for storing the log. */
+};
diff --git a/modules/odm_25dmeshing/src/Odm25dMeshing.cpp b/modules/odm_25dmeshing/src/Odm25dMeshing.cpp
new file mode 100644
index 000000000..9d1c1788e
--- /dev/null
+++ b/modules/odm_25dmeshing/src/Odm25dMeshing.cpp
@@ -0,0 +1,430 @@
+#include "Odm25dMeshing.hpp"
+
+int Odm25dMeshing::run(int argc, char **argv) {
+ log << logFilePath << "\n";
+
+ // If no arguments were passed, print help and return early.
+ if (argc <= 1) {
+ printHelp();
+ return EXIT_SUCCESS;
+ }
+
+ try {
+
+ parseArguments(argc, argv);
+
+ loadPointCloud();
+
+ buildMesh();
+
+ } catch (const Odm25dMeshingException& e) {
+ log.setIsPrintingInCout(true);
+ log << e.what() << "\n";
+ log.printToFile(logFilePath);
+ log << "For more detailed information, see log file." << "\n";
+ return EXIT_FAILURE;
+ } catch (const std::exception& e) {
+ log.setIsPrintingInCout(true);
+ log << "Error in OdmMeshing:\n";
+ log << e.what() << "\n";
+ log.printToFile(logFilePath);
+ log << "For more detailed information, see log file." << "\n";
+ return EXIT_FAILURE;
+ }
+
+ log.printToFile(logFilePath);
+
+ return EXIT_SUCCESS;
+}
+
+void Odm25dMeshing::parseArguments(int argc, char **argv) {
+ for (int argIndex = 1; argIndex < argc; ++argIndex) {
+ // The argument to be parsed.
+ std::string argument = std::string(argv[argIndex]);
+
+ if (argument == "-help") {
+ printHelp();
+ exit(0);
+ } else if (argument == "-verbose") {
+ log.setIsPrintingInCout(true);
+ } else if (argument == "-maxVertexCount" && argIndex < argc) {
+ ++argIndex;
+ if (argIndex >= argc) throw Odm25dMeshingException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
+ std::stringstream ss(argv[argIndex]);
+ ss >> maxVertexCount;
+ if (ss.bad()) throw Odm25dMeshingException("Argument '" + argument + "' has a bad value (wrong type).");
+ maxVertexCount = std::max(maxVertexCount, 0);
+ log << "Vertex count was manually set to: " << maxVertexCount << "\n";
+ } else if (argument == "-outliersRemovalPercentage" && argIndex < argc) {
+ ++argIndex;
+ if (argIndex >= argc) throw Odm25dMeshingException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
+ std::stringstream ss(argv[argIndex]);
+ ss >> outliersRemovalPercentage;
+ if (ss.bad()) throw Odm25dMeshingException("Argument '" + argument + "' has a bad value (wrong type).");
+
+ outliersRemovalPercentage = std::min(99.99, std::max(outliersRemovalPercentage, 0));
+ log << "Outliers removal was manually set to: " << outliersRemovalPercentage << "\n";
+ } else if (argument == "-wlopIterations" && argIndex < argc) {
+ ++argIndex;
+ if (argIndex >= argc) throw Odm25dMeshingException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
+ std::stringstream ss(argv[argIndex]);
+ ss >> wlopIterations;
+ if (ss.bad()) throw Odm25dMeshingException("Argument '" + argument + "' has a bad value (wrong type).");
+
+ wlopIterations = std::min(1000, std::max(wlopIterations, 1));
+ log << "WLOP iterations was manually set to: " << wlopIterations << "\n";
+ } else if (argument == "-inputFile" && argIndex < argc) {
+ ++argIndex;
+ if (argIndex >= argc) {
+ throw Odm25dMeshingException(
+ "Argument '" + argument
+ + "' expects 1 more input following it, but no more inputs were provided.");
+ }
+ inputFile = std::string(argv[argIndex]);
+ std::ifstream testFile(inputFile.c_str(), std::ios::binary);
+ if (!testFile.is_open()) {
+ throw Odm25dMeshingException(
+ "Argument '" + argument + "' has a bad value. (file not accessible)");
+ }
+ testFile.close();
+ log << "Reading point cloud at: " << inputFile << "\n";
+ } else if (argument == "-outputFile" && argIndex < argc) {
+ ++argIndex;
+ if (argIndex >= argc) {
+ throw Odm25dMeshingException(
+ "Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
+ }
+ outputFile = std::string(argv[argIndex]);
+ std::ofstream testFile(outputFile.c_str());
+ if (!testFile.is_open()) {
+ throw Odm25dMeshingException(
+ "Argument '" + argument + "' has a bad value.");
+ }
+ testFile.close();
+ log << "Writing output to: " << outputFile << "\n";
+ } else if (argument == "-logFile" && argIndex < argc) {
+ ++argIndex;
+ if (argIndex >= argc) {
+ throw Odm25dMeshingException(
+ "Argument '" + argument
+ + "' expects 1 more input following it, but no more inputs were provided.");
+ }
+ logFilePath = std::string(argv[argIndex]);
+ std::ofstream testFile(outputFile.c_str());
+ if (!testFile.is_open()) {
+ throw Odm25dMeshingException(
+ "Argument '" + argument + "' has a bad value.");
+ }
+ testFile.close();
+ log << "Writing log information to: " << logFilePath << "\n";
+ } else {
+ printHelp();
+ throw Odm25dMeshingException("Unrecognised argument '" + argument + "'");
+ }
+ }
+}
+
+void Odm25dMeshing::loadPointCloud(){
+ PlyInterpreter interpreter(points);
+
+ std::ifstream in(inputFile);
+ if (!in || !CGAL::read_ply_custom_points (in, interpreter, Kernel())){
+ throw Odm25dMeshingException(
+ "Error when reading points and normals from:\n" + inputFile + "\n");
+ }
+
+ flipFaces = interpreter.flip_faces();
+
+ log << "Successfully loaded " << points.size() << " points from file\n";
+}
+
+void Odm25dMeshing::buildMesh(){
+ const unsigned int NEIGHBORS = 24;
+
+ size_t pointCount = points.size();
+ size_t pointCountBeforeOutlierRemoval = pointCount;
+
+ log << "Removing outliers... ";
+
+ points.erase(CGAL::remove_outliers(points.begin(), points.end(),
+ NEIGHBORS,
+ outliersRemovalPercentage),
+ points.end());
+ std::vector(points).swap(points);
+ pointCount = points.size();
+
+ log << "removed " << pointCountBeforeOutlierRemoval - pointCount << " points\n";
+
+ log << "Computing average spacing... ";
+
+ FT avgSpacing = CGAL::compute_average_spacing(
+ points.begin(),
+ points.end(),
+ NEIGHBORS);
+
+ log << avgSpacing << "\n";
+
+ log << "Grid Z sampling... ";
+
+ size_t pointCountBeforeGridSampling = pointCount;
+
+ double gridStep = avgSpacing / 2;
+ Kernel::Iso_cuboid_3 bbox = CGAL::bounding_box(points.begin(), points.end());
+ Vector3 boxDiag = bbox.max() - bbox.min();
+
+ int gridWidth = 1 + static_cast(boxDiag.x() / gridStep + 0.5);
+ int gridHeight = 1 + static_cast(boxDiag.y() / gridStep + 0.5);
+
+ #define KEY(i, j) (i * gridWidth + j)
+
+ std::unordered_map grid;
+
+ for (size_t c = 0; c < pointCount; c++){
+ const Point3 &p = points[c];
+ Vector3 relativePos = p - bbox.min();
+ int i = static_cast((relativePos.x() / gridStep + 0.5));
+ int j = static_cast((relativePos.y() / gridStep + 0.5));
+
+ if ((i >= 0 && i < gridWidth) && (j >= 0 && j < gridHeight)){
+ int key = KEY(i, j);
+
+ if (grid.find(key) == grid.end()){
+ grid[key] = p;
+ }else if ((!flipFaces && p.z() > grid[key].z()) || (flipFaces && p.z() < grid[key].z())){
+ grid[key] = p;
+ }
+ }
+ }
+
+ std::vector gridPoints;
+ for ( auto it = grid.begin(); it != grid.end(); ++it ){
+ gridPoints.push_back(it->second);
+ }
+
+ pointCount = gridPoints.size();
+ log << "sampled " << (pointCountBeforeGridSampling - pointCount) << " points\n";
+
+ const double RETAIN_PERCENTAGE = std::min(80., 100. * static_cast(maxVertexCount) / static_cast(pointCount)); // percentage of points to retain.
+ std::vector simplifiedPoints;
+
+ log << "Performing weighted locally optimal projection simplification and regularization (retain: " << RETAIN_PERCENTAGE << "%, iterate: " << wlopIterations << ")" << "\n";
+
+ CGAL::wlop_simplify_and_regularize_point_set(
+ gridPoints.begin(),
+ gridPoints.end(),
+ std::back_inserter(simplifiedPoints),
+ RETAIN_PERCENTAGE,
+ 8 * avgSpacing,
+ wlopIterations,
+ true);
+
+ pointCount = simplifiedPoints.size();
+
+ if (pointCount < 3){
+ throw Odm25dMeshingException("Not enough points");
+ }
+
+ log << "Vertex count is " << pointCount << "\n";
+
+ typedef CDT::Point cgalPoint;
+ typedef CDT::Vertex_circulator Vertex_circulator;
+
+ std::vector< std::pair > pts;
+ try{
+ pts.reserve(pointCount);
+ } catch (const std::bad_alloc&){
+ throw Odm25dMeshingException("Not enough memory");
+ }
+
+ for (size_t i = 0; i < pointCount; ++i){
+ pts.push_back(std::make_pair(cgalPoint(simplifiedPoints[i].x(), simplifiedPoints[i].y()), i));
+ }
+
+ log << "Computing delaunay triangulation... ";
+
+ CDT cdt;
+ cdt.insert(pts.begin(), pts.end());
+
+ unsigned int numberOfTriangles = static_cast(cdt.number_of_faces());
+ unsigned int triIndexes = cdt.number_of_faces()*3;
+
+ if (numberOfTriangles == 0) throw Odm25dMeshingException("No triangles in resulting mesh");
+
+ log << numberOfTriangles << " triangles\n";
+
+ std::vector vertices;
+ std::vector vertexIndices;
+
+ try{
+ vertices.reserve(pointCount);
+ vertexIndices.reserve(triIndexes);
+ } catch (const std::bad_alloc&){
+ throw Odm25dMeshingException("Not enough memory");
+ }
+
+
+ for (size_t i = 0; i < pointCount; ++i){
+ vertices.push_back(simplifiedPoints[i].x());
+ vertices.push_back(simplifiedPoints[i].y());
+ vertices.push_back(simplifiedPoints[i].z());
+ }
+
+ for (CDT::Face_iterator face = cdt.faces_begin(); face != cdt.faces_end(); ++face) {
+ if (flipFaces){
+ vertexIndices.push_back(face->vertex(2)->info());
+ vertexIndices.push_back(face->vertex(1)->info());
+ vertexIndices.push_back(face->vertex(0)->info());
+ }else{
+ vertexIndices.push_back(face->vertex(0)->info());
+ vertexIndices.push_back(face->vertex(1)->info());
+ vertexIndices.push_back(face->vertex(2)->info());
+ }
+ }
+
+ log << "Removing spikes... ";
+
+ const float THRESHOLD = avgSpacing;
+ std::vector heights;
+ unsigned int spikesRemoved = 0;
+
+ for (CDT::Vertex_iterator vertex = cdt.vertices_begin(); vertex != cdt.vertices_end(); ++vertex){
+ // Check if the height between this vertex and its
+ // incident vertices is greater than THRESHOLD
+ Vertex_circulator vc = cdt.incident_vertices(vertex), done(vc);
+
+ if (vc != 0){
+ float height = vertices[vertex->info() * 3 + 2];
+ int threshold_over_count = 0;
+ int vertexCount = 0;
+
+ do{
+ if (cdt.is_infinite(vc)) continue;
+
+ float ivHeight = vertices[vc->info() * 3 + 2];
+
+ if (fabs(height - ivHeight) > THRESHOLD){
+ threshold_over_count++;
+ heights.push_back(ivHeight);
+ }
+
+ vertexCount++;
+ }while(++vc != done);
+
+ if (vertexCount == threshold_over_count){
+ // Replace the height of the vertex by the median height
+ // of its incident vertices
+ std::sort(heights.begin(), heights.end());
+
+ vertices[vertex->info() * 3 + 2] = heights[heights.size() / 2];
+
+ spikesRemoved++;
+ }
+
+ heights.clear();
+ }
+ }
+
+ log << "removed " << spikesRemoved << " spikes\n";
+
+ log << "Building polyhedron... ";
+
+ Polyhedron poly;
+ PolyhedronBuilder builder(vertices, vertexIndices);
+ poly.delegate( builder );
+
+ log << "done\n";
+
+ log << "Refining... ";
+
+ typedef Polyhedron::Vertex_handle Vertex_handle;
+ std::vector new_facets;
+ std::vector new_vertices;
+ CGAL::Polygon_mesh_processing::refine(poly,
+ faces(poly),
+ std::back_inserter(new_facets),
+ std::back_inserter(new_vertices),
+ CGAL::Polygon_mesh_processing::parameters::density_control_factor(2.));
+
+ log << "added " << new_vertices.size() << " new vertices\n";
+
+// log << "Edge collapsing... ";
+//
+// SMS::Count_stop_predicate stop(maxVertexCount * 3);
+// int redgesRemoved = SMS::edge_collapse(poly, stop,
+// CGAL::parameters::vertex_index_map(get(CGAL::vertex_external_index, poly))
+// .halfedge_index_map (get(CGAL::halfedge_external_index, poly))
+// .get_cost (SMS::Edge_length_cost ())
+// .get_placement(SMS::Midpoint_placement())
+// );
+//
+// log << redgesRemoved << " edges removed.\n";
+
+ log << "Final vertex count is " << poly.size_of_vertices() << "\n";
+
+ log << "Saving mesh to file.\n";
+
+ typedef typename Polyhedron::Vertex_const_iterator VCI;
+ typedef typename Polyhedron::Facet_const_iterator FCI;
+ typedef typename Polyhedron::Halfedge_around_facet_const_circulator HFCC;
+
+ std::filebuf fb;
+ fb.open(outputFile, std::ios::out);
+ std::ostream os(&fb);
+
+ os << "ply\n"
+ << "format ascii 1.0\n"
+ << "element vertex " << poly.size_of_vertices() << "\n"
+ << "property float x\n"
+ << "property float y\n"
+ << "property float z\n"
+ << "element face " << poly.size_of_facets() << "\n"
+ << "property list uchar int vertex_index\n"
+ << "end_header\n";
+
+ for (auto it = poly.vertices_begin(); it != poly.vertices_end(); it++){
+ os << it->point().x() << " " << it->point().y() << " " << it->point().z() << std::endl;
+ }
+
+ typedef CGAL::Inverse_index Index;
+ Index index(poly.vertices_begin(), poly.vertices_end());
+
+ for( FCI fi = poly.facets_begin(); fi != poly.facets_end(); ++fi) {
+ HFCC hc = fi->facet_begin();
+ HFCC hc_end = hc;
+
+ os << circulator_size(hc) << " ";
+ do {
+ os << index[VCI(hc->vertex())] << " ";
+ ++hc;
+ } while( hc != hc_end);
+
+ os << "\n";
+ }
+
+ fb.close();
+
+ log << "Successfully wrote mesh to: " << outputFile << "\n";
+}
+
+void Odm25dMeshing::printHelp() {
+ bool printInCoutPop = log.isPrintingInCout();
+ log.setIsPrintingInCout(true);
+
+ log << "Usage: odm_25dmeshing -inputFile [plyFile] [optional-parameters]\n";
+ log << "Create a 2.5D mesh from an oriented point cloud (points with normals) using a constrained delaunay triangulation. "
+ << "The program requires a path to an input PLY point cloud file, all other input parameters are optional.\n\n";
+
+ log << " -inputFile to PLY point cloud\n"
+ << " -outputFile where the output PLY 2.5D mesh should be saved (default: " << outputFile << ")\n"
+ << " -logFile log file path (default: " << logFilePath << ")\n"
+ << " -verbose whether to print verbose output (default: " << (printInCoutPop ? "true" : "false") << ")\n"
+ << " -maxVertexCount <0 - N> Maximum number of vertices in the output mesh. The mesh might have fewer vertices, but will not exceed this limit. (default: " << maxVertexCount << ")\n"
+ << " -wlopIterations <1 - 1000> Iterations of the Weighted Locally Optimal Projection (WLOP) simplification algorithm. Higher values take longer but produce a smoother mesh. (default: " << wlopIterations << ")\n"
+
+ << "\n";
+
+ log.setIsPrintingInCout(printInCoutPop);
+}
+
+
+
diff --git a/modules/odm_25dmeshing/src/Odm25dMeshing.hpp b/modules/odm_25dmeshing/src/Odm25dMeshing.hpp
new file mode 100644
index 000000000..4ebf9df39
--- /dev/null
+++ b/modules/odm_25dmeshing/src/Odm25dMeshing.hpp
@@ -0,0 +1,93 @@
+#pragma once
+
+// STL
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "CGAL.hpp"
+#include "Logger.hpp"
+#include "PlyInterpreter.hpp"
+#include "PolyhedronBuilder.hpp"
+
+class Odm25dMeshing {
+public:
+ Odm25dMeshing() :
+ log(false) {};
+ ~Odm25dMeshing() {};
+
+ /*!
+ * \brief run Runs the meshing functionality using the provided input arguments.
+ * For a list of accepted arguments, please see the main page documentation or
+ * call the program with parameter "-help".
+ * \param argc Application argument count.
+ * \param argv Argument values.
+ * \return 0 If successful.
+ */
+ int run(int argc, char **argv);
+
+private:
+
+ /*!
+ * \brief parseArguments Parses command line arguments.
+ * \param argc Application argument count.
+ * \param argv Argument values.
+ */
+ void parseArguments(int argc, char** argv);
+
+ /*!
+ * \brief loadPointCloud Loads a PLY file with points and normals from file.
+ */
+ void loadPointCloud();
+
+ /*!
+ * \brief loadPointCloud Builds a 2.5D mesh from loaded points
+ */
+ void buildMesh();
+
+ /*!
+ * \brief printHelp Prints help, explaining usage. Can be shown by calling the program with argument: "-help".
+ */
+ void printHelp();
+
+ Logger log;
+
+ std::string inputFile = "";
+ std::string outputFile = "odm_25dmesh.ply";
+ std::string logFilePath = "odm_25dmeshing_log.txt";
+ unsigned int maxVertexCount = 100000;
+ double outliersRemovalPercentage = 2;
+ unsigned int wlopIterations = 35;
+ std::vector points;
+ bool flipFaces = false;
+};
+
+class Odm25dMeshingException: public std::exception {
+
+public:
+ Odm25dMeshingException() :
+ message("Error in Odm25dMeshing") {
+ }
+ Odm25dMeshingException(std::string msgInit) :
+ message("Error in Odm25dMeshing:\n" + msgInit) {
+ }
+ ~Odm25dMeshingException() throw () {
+ }
+ virtual const char* what() const throw () {
+ return message.c_str();
+ }
+
+private:
+ std::string message; /**< The error message **/
+};
diff --git a/modules/odm_25dmeshing/src/PlyInterpreter.cpp b/modules/odm_25dmeshing/src/PlyInterpreter.cpp
new file mode 100644
index 000000000..f8a074888
--- /dev/null
+++ b/modules/odm_25dmeshing/src/PlyInterpreter.cpp
@@ -0,0 +1,40 @@
+#include "PlyInterpreter.hpp"
+
+// Init and test if input file contains the right properties
+bool PlyInterpreter::is_applicable(CGAL::Ply_reader& reader) {
+ return reader.does_tag_exist ("x")
+ && reader.does_tag_exist ("y")
+ && reader.does_tag_exist ("z")
+ && reader.does_tag_exist ("nx")
+ && reader.does_tag_exist ("ny")
+ && reader.does_tag_exist ("nz");
+}
+
+// Describes how to process one line (= one point object)
+void PlyInterpreter::process_line(CGAL::Ply_reader& reader) {
+ FT x = (FT)0., y = (FT)0., z = (FT)0.,
+ nx = (FT)0., ny = (FT)0., nz = (FT)0.;
+
+ reader.assign (x, "x");
+ reader.assign (y, "y");
+ reader.assign (z, "z");
+ reader.assign (nx, "nx");
+ reader.assign (ny, "ny");
+ reader.assign (nz, "nz");
+
+ Point3 p(x, y, z);
+// Vector3 n(nx, ny, nz);
+
+ if (nz >= 0 && zNormalsDirectionCount < std::numeric_limits::max()){
+ zNormalsDirectionCount++;
+ }else if (nz < 0 && zNormalsDirectionCount > std::numeric_limits::min()){
+ zNormalsDirectionCount--;
+ }
+
+// points.push_back(std::make_pair(p, n));
+ points.push_back(p);
+}
+
+bool PlyInterpreter::flip_faces(){
+ return zNormalsDirectionCount < 0;
+}
diff --git a/modules/odm_25dmeshing/src/PlyInterpreter.hpp b/modules/odm_25dmeshing/src/PlyInterpreter.hpp
new file mode 100644
index 000000000..eca6bcb77
--- /dev/null
+++ b/modules/odm_25dmeshing/src/PlyInterpreter.hpp
@@ -0,0 +1,27 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "CGAL.hpp"
+
+// points, normals
+//typedef std::pair Pwn;
+
+class PlyInterpreter {
+ std::vector& points;
+ long zNormalsDirectionCount;
+
+ public:
+ PlyInterpreter (std::vector& points)
+ : points (points), zNormalsDirectionCount(0)
+ { }
+ bool is_applicable (CGAL::Ply_reader& reader);
+ void process_line (CGAL::Ply_reader& reader);
+ bool flip_faces();
+};
diff --git a/modules/odm_25dmeshing/src/PolyhedronBuilder.cpp b/modules/odm_25dmeshing/src/PolyhedronBuilder.cpp
new file mode 100644
index 000000000..69b06d441
--- /dev/null
+++ b/modules/odm_25dmeshing/src/PolyhedronBuilder.cpp
@@ -0,0 +1,2 @@
+#include "PolyhedronBuilder.hpp"
+
diff --git a/modules/odm_25dmeshing/src/PolyhedronBuilder.hpp b/modules/odm_25dmeshing/src/PolyhedronBuilder.hpp
new file mode 100644
index 000000000..f68dbe0c7
--- /dev/null
+++ b/modules/odm_25dmeshing/src/PolyhedronBuilder.hpp
@@ -0,0 +1,43 @@
+#include
+#include
+
+#include
+#include
+
+#include "CGAL.hpp"
+
+// A modifier creating a triangle with the incremental builder.
+template
+class PolyhedronBuilder : public CGAL::Modifier_base {
+public:
+ std::vector &vertices;
+ std::vector &vertexIndices;
+
+ PolyhedronBuilder( std::vector &vertices, std::vector &vertexIndices )
+ : vertices(vertices), vertexIndices(vertexIndices) {}
+
+ void operator()( HDS& hds) {
+ typedef typename HDS::Vertex Vertex;
+ typedef typename Vertex::Point Point;
+
+ CGAL::Polyhedron_incremental_builder_3 builder( hds, true);
+ builder.begin_surface( vertices.size() / 3, vertexIndices.size() / 3 );
+
+ for(size_t i = 0; i < vertices.size(); i+=3 ){
+ builder.add_vertex(Point(vertices[i+0], vertices[i+1], vertices[i+2]));
+ }
+
+ for(size_t i = 0; i < vertexIndices.size(); i+=3){
+ builder.begin_facet();
+ builder.add_vertex_to_facet(vertexIndices[i+0]);
+ builder.add_vertex_to_facet(vertexIndices[i+1]);
+ builder.add_vertex_to_facet(vertexIndices[i+2]);
+ builder.end_facet();
+ }
+
+ // finish up the surface
+ builder.end_surface();
+ }
+};
+
+
diff --git a/modules/odm_25dmeshing/src/main.cpp b/modules/odm_25dmeshing/src/main.cpp
new file mode 100644
index 000000000..75e1934ec
--- /dev/null
+++ b/modules/odm_25dmeshing/src/main.cpp
@@ -0,0 +1,31 @@
+/*
+OpenDroneMap - https://www.opendronemap.org
+Copyright (C) 2017 OpenDroneMap Contributors
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+#include "Odm25dMeshing.hpp"
+
+/*!
+ * \mainpage main OpenDroneMap 2.5D Meshing Module
+ *
+ * The OpenDroneMap 2.5D Meshing Module generates a 2.5D mesh using a constrained
+ * delaunay triangulation from any point cloud (points with corresponding normals).
+ */
+
+int main(int argc, char** argv)
+{
+ Odm25dMeshing om;
+ return om.run(argc, argv);
+}
diff --git a/modules/odm_extract_utm/CMakeLists.txt b/modules/odm_extract_utm/CMakeLists.txt
new file mode 100644
index 000000000..460b83e96
--- /dev/null
+++ b/modules/odm_extract_utm/CMakeLists.txt
@@ -0,0 +1,21 @@
+project(odm_extract_utm)
+cmake_minimum_required(VERSION 2.8)
+
+set(PROJ4_INCLUDE_DIR "/usr/include/" CACHE "PROJ4_INCLUDE_DIR" "Path to the proj4 inlcude directory")
+
+find_library(PROJ4_LIBRARY "libproj.so" PATHS "/usr/lib" "/usr/lib/x86_64-linux-gnu")
+find_library(EXIV2_LIBRARY "libexiv2.so" PATHS "/usr/lib" "/usr/lib/x86_64-linux-gnu")
+
+# Add compiler options.
+add_definitions(-Wall -Wextra)
+
+# Add source directory
+aux_source_directory("./src" SRC_LIST)
+
+# Add exectuteable
+add_executable(${PROJECT_NAME} ${SRC_LIST})
+
+# Link
+target_link_libraries(${PROJECT_NAME} ${PROJ4_LIBRARY})
+target_link_libraries(${PROJECT_NAME} ${EXIV2_LIBRARY})
+
diff --git a/modules/odm_extract_utm/src/Logger.cpp b/modules/odm_extract_utm/src/Logger.cpp
new file mode 100644
index 000000000..a6c81a8b5
--- /dev/null
+++ b/modules/odm_extract_utm/src/Logger.cpp
@@ -0,0 +1,31 @@
+#include "Logger.hpp"
+
+
+Logger::Logger(bool isPrintingInCout) : isPrintingInCout_(isPrintingInCout)
+{
+
+}
+
+Logger::~Logger()
+{
+
+}
+
+void Logger::printToFile(std::string filePath)
+{
+ std::ofstream file(filePath.c_str(), std::ios::binary);
+ file << logStream_.str();
+ file.close();
+}
+
+bool Logger::isPrintingInCout() const
+{
+ return isPrintingInCout_;
+}
+
+void Logger::setIsPrintingInCout(bool isPrintingInCout)
+{
+ isPrintingInCout_ = isPrintingInCout;
+}
+
+
diff --git a/modules/odm_extract_utm/src/Logger.hpp b/modules/odm_extract_utm/src/Logger.hpp
new file mode 100644
index 000000000..31c5538cb
--- /dev/null
+++ b/modules/odm_extract_utm/src/Logger.hpp
@@ -0,0 +1,68 @@
+#pragma once
+
+// STL
+#include
+#include
+#include
+#include
+
+/*!
+ * \brief The Logger class is used to store program messages in a log file.
+ * \details By using the << operator while printInCout is set, the class writes both to
+ * cout and to file, if the flag is not set, output is written to file only.
+ */
+class Logger
+{
+public:
+ /*!
+ * \brief Logger Contains functionality for printing and displaying log information.
+ * \param printInCout Flag toggling if operator << also writes to cout.
+ */
+ Logger(bool isPrintingInCout = true);
+
+ /*!
+ * \brief Destructor.
+ */
+ ~Logger();
+
+ /*!
+ * \brief print Prints the contents of the log to file.
+ * \param filePath Path specifying where to write the log.
+ */
+ void printToFile(std::string filePath);
+
+ /*!
+ * \brief isPrintingInCout Check if console printing flag is set.
+ * \return Console printing flag.
+ */
+ bool isPrintingInCout() const;
+
+ /*!
+ * \brief setIsPrintingInCout Set console printing flag.
+ * \param isPrintingInCout Value, if true, messages added to the log are also printed in cout.
+ */
+ void setIsPrintingInCout(bool isPrintingInCout);
+
+ /*!
+ * Operator for printing messages to log and in the standard output stream if desired.
+ */
+ template
+ friend Logger& operator<< (Logger &log, T t)
+ {
+ // If console printing is enabled.
+ if (log.isPrintingInCout_)
+ {
+ std::cout << t;
+ std::cout.flush();
+ }
+ // Write to log.
+ log.logStream_ << t;
+
+ return log;
+ }
+
+private:
+ bool isPrintingInCout_; /*!< If flag is set, log is printed in cout and written to the log. */
+
+ std::stringstream logStream_; /*!< Stream for storing the log. */
+};
diff --git a/modules/odm_extract_utm/src/UtmExtractor.cpp b/modules/odm_extract_utm/src/UtmExtractor.cpp
new file mode 100644
index 000000000..ff2687843
--- /dev/null
+++ b/modules/odm_extract_utm/src/UtmExtractor.cpp
@@ -0,0 +1,353 @@
+// STL
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+// Proj4
+#include
+
+// This
+#include "UtmExtractor.hpp"
+
+UtmExtractor::UtmExtractor() : log_(false)
+{
+ logFile_ = "odm_extracting_utm_log.txt";
+}
+
+UtmExtractor::~UtmExtractor()
+{
+}
+
+
+
+int UtmExtractor::run(int argc, char **argv)
+{
+ if (argc <= 1)
+ {
+ printHelp();
+ return EXIT_SUCCESS;
+ }
+
+ try
+ {
+ parseArguments(argc, argv);
+ extractUtm();
+ }
+ catch (const UtmExtractorException& e)
+ {
+ log_.setIsPrintingInCout(true);
+ log_ << e.what() << "\n";
+ log_.printToFile(logFile_);
+ log_ << "For more detailed information, see log file." << "\n";
+ return EXIT_FAILURE;
+ }
+ catch (const std::exception& e)
+ {
+ log_.setIsPrintingInCout(true);
+ log_ << "Error in OdmExtractUtm:\n";
+ log_ << e.what() << "\n";
+ log_.printToFile(logFile_);
+ log_ << "For more detailed information, see log file." << "\n";
+ return EXIT_FAILURE;
+ }
+ catch (...)
+ {
+ log_.setIsPrintingInCout(true);
+ log_ << "Unknown error in OdmExtractUtm:\n";
+ log_.printToFile(logFile_);
+ log_ << "For more detailed information, see log file." << "\n";
+ return EXIT_FAILURE;
+ }
+
+ log_.printToFile(logFile_);
+ return EXIT_SUCCESS;
+}
+
+void UtmExtractor::parseArguments(int argc, char **argv)
+{
+ for(int argIndex = 1; argIndex < argc; ++argIndex)
+ {
+ // The argument to be parsed
+ std::string argument = std::string(argv[argIndex]);
+ if (argument == "-help")
+ {
+ printHelp();
+ }
+ else if (argument == "-verbose")
+ {
+ log_.setIsPrintingInCout(true);
+ }
+ else if (argument == "-imageListFile")
+ {
+ ++argIndex;
+ if (argIndex >= argc)
+ {
+ throw UtmExtractorException("Missing argument for '" + argument + "'.");
+ }
+ imageListFileName_ = std::string(argv[argIndex]);
+ std::ifstream testFile(imageListFileName_.c_str(), std::ios_base::binary);
+ if (!testFile.is_open())
+ {
+ throw UtmExtractorException("Argument '" + argument + "' has a bad value (file not accessible).");
+ }
+ log_ << "imageListFile was set to: " << imageListFileName_ << "\n";
+ }
+ else if (argument == "-imagesPath")
+ {
+ ++argIndex;
+ if (argIndex >= argc)
+ {
+ throw UtmExtractorException("Missing argument for '" + argument + "'.");
+ }
+ std::stringstream ss(argv[argIndex]);
+ ss >> imagesPath_;
+ if (ss.bad())
+ {
+ throw UtmExtractorException("Argument '" + argument + "' has a bad value. (wrong type)");
+ }
+ log_ << "imagesPath was set to: " << imagesPath_ << "\n";
+ }
+ else if (argument == "-outputCoordFile")
+ {
+ ++argIndex;
+ if (argIndex >= argc)
+ {
+ throw UtmExtractorException("Missing argument for '" + argument + "'.");
+ }
+ std::stringstream ss(argv[argIndex]);
+ ss >> outputCoordFileName_;
+ if (ss.bad())
+ {
+ throw UtmExtractorException("Argument '" + argument + "' has a bad value. (wrong type)");
+ }
+ log_ << "outputCoordFile was set to: " << outputCoordFileName_ << "\n";
+ }
+ else if (argument == "-logFile")
+ {
+ ++argIndex;
+ if (argIndex >= argc)
+ {
+ throw UtmExtractorException("Missing argument for '" + argument + "'.");
+ }
+ std::stringstream ss(argv[argIndex]);
+ ss >> logFile_;
+ if (ss.bad())
+ {
+ throw UtmExtractorException("Argument '" + argument + "' has a bad value. (wrong type)");
+ }
+ log_ << "logFile_ was set to: " << logFile_ << "\n";
+ }
+ else
+ {
+ printHelp();
+ throw UtmExtractorException("Unrecognised argument '" + argument + "'.");
+ }
+ }
+
+}
+
+void UtmExtractor::extractUtm()
+{
+ // Open file listing all used camera images
+ std::ifstream imageListStream(imageListFileName_.c_str());
+ if (!imageListStream.good()) {
+ throw UtmExtractorException("Failed to open " + imageListFileName_ + " for reading.");
+ }
+
+ // Traverse images
+ int utmZone = 99; // for auto-select
+ char hemisphere;
+ std::string imageFilename;
+ std::vector coords;
+ while (getline(imageListStream, imageFilename)) {
+
+ // Read image and load metadata
+ Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(imagesPath_ + "/" + imageFilename);
+ if (image.get() == 0) {
+ std::string error(imageFilename);
+ error += ": Image cannot be read";
+ throw Exiv2::Error(1, error);
+ }
+ else {
+ image->readMetadata();
+
+ Exiv2::ExifData &exifData = image->exifData();
+ if (exifData.empty()) {
+ std::string error(imageFilename);
+ error += ": No Exif data found in the file";
+ throw Exiv2::Error(1, error);
+ }
+
+ // Parse exif data for positional data
+ double lon, lat, alt = 0.0;
+
+ parsePosition(exifData, lon, lat, alt);
+
+ if (lon == 0.0 || lat == 0.0 || alt == 0.0) {
+ std::string error("Failed parsing GPS position for " + imageFilename);
+ throw UtmExtractorException(error);
+ }
+ // Convert to UTM
+ double x, y, z = 0.0;
+ convert(lon, lat, alt, x, y, z, utmZone, hemisphere);
+ if (x == 0.0 || y == 0.0 || z == 0.0) {
+ std::string error("Failed to convert GPS position to UTM for " + imageFilename);
+ throw UtmExtractorException(error);
+ }
+ coords.push_back(Coord(x, y, z));
+ }
+ }
+ imageListStream.close();
+
+ // Calculate average
+ double dx = 0.0, dy = 0.0;
+ double num = static_cast(coords.size());
+ for (std::vector::iterator iter = coords.begin(); iter != coords.end(); ++iter) {
+ dx += iter->x/num;
+ dy += iter->y/num;
+ }
+
+ dx = floor(dx);
+ dy = floor(dy);
+
+ // Open output file
+ std::ofstream outputCoordStream(outputCoordFileName_.c_str());
+ if (!outputCoordStream.good()) {
+ throw UtmExtractorException("Failed to open " + outputCoordFileName_ + " for writing.");
+ }
+ outputCoordStream.precision(10);
+
+ // Write coordinate file
+ outputCoordStream << "WGS84 UTM " << utmZone << hemisphere << std::endl;
+ outputCoordStream << dx << " " << dy << std::endl;
+ for (std::vector::iterator iter = coords.begin(); iter != coords.end(); ++iter) {
+ outputCoordStream << (iter->x - dx) << " " << (iter->y - dy) << " " << iter->z << std::endl;
+ }
+
+ outputCoordStream.close();
+
+}
+
+void UtmExtractor::convert(const double &lon, const double &lat, const double &alt, double &x, double &y, double &z, int &utmZone, char &hemisphere)
+{
+ // Create WGS84 longitude/latitude coordinate system
+ projPJ pjLatLon = pj_init_plus("+proj=latlong +datum=WGS84");
+ if (!pjLatLon) {
+ throw UtmExtractorException("Couldn't create WGS84 coordinate system with PROJ.4.");
+ }
+
+ // Calculate UTM zone if it's set to magic 99
+ // NOTE: Special UTM cases in Norway/Svalbard not supported here
+ if (utmZone == 99) {
+ utmZone = ((static_cast(floor((lon + 180.0)/6.0)) % 60) + 1);
+ if (lat < 0)
+ hemisphere = 'S';
+ else
+ hemisphere = 'N';
+ }
+
+ std::ostringstream ostr;
+ ostr << utmZone;
+ if (hemisphere == 'S')
+ ostr << " +south";
+
+ // Create UTM coordinate system
+ projPJ pjUtm = pj_init_plus(("+proj=utm +datum=WGS84 +zone=" + ostr.str()).c_str());
+ if (!pjUtm) {
+ throw UtmExtractorException("Couldn't create UTM coordinate system with PROJ.4.");
+ }
+
+ // Convert to radians
+ x = lon * DEG_TO_RAD;
+ y = lat * DEG_TO_RAD;
+ z = alt;
+
+ // Transform
+ int res = pj_transform(pjLatLon, pjUtm, 1, 1, &x, &y, &z);
+ if (res != 0) {
+ throw UtmExtractorException("Failed to transform coordinates");
+ }
+}
+
+void UtmExtractor::parsePosition(Exiv2::ExifData &exifData, double &lon, double &lat, double &alt)
+{
+ Exiv2::Exifdatum& latitudeTag = exifData["Exif.GPSInfo.GPSLatitude"];
+ Exiv2::Exifdatum& latitudeRef = exifData["Exif.GPSInfo.GPSLatitudeRef"];
+ Exiv2::Exifdatum& longitudeTag = exifData["Exif.GPSInfo.GPSLongitude"];
+ Exiv2::Exifdatum& longitudeRef = exifData["Exif.GPSInfo.GPSLongitudeRef"];
+ Exiv2::Exifdatum& altitudeTag = exifData["Exif.GPSInfo.GPSAltitude"];
+ Exiv2::Exifdatum& altitudeRef = exifData["Exif.GPSInfo.GPSAltitudeRef"];
+
+ // Latitude: parse into a double
+ if (latitudeTag.count() < 3)
+ throw UtmExtractorException("Image is missing GPS Latitude data");
+ else {
+ Exiv2::URational rLat[] = {latitudeTag.toRational(0), latitudeTag.toRational(1), latitudeTag.toRational(2)};
+ bool south = (strcmp(latitudeRef.toString().c_str(), "S") == 0);
+ double degrees, minutes, seconds;
+
+ degrees = (double)rLat[0].first / (double)rLat[0].second;
+ minutes = (double)rLat[1].first / (double)rLat[1].second / 60.0;
+ seconds = (double)rLat[2].first / (double)rLat[2].second / 3600.0;
+ lat = (south ? -1 : 1) * (degrees + minutes + seconds);
+ }
+
+ // Longitude
+ if (longitudeTag.count() < 3)
+ throw UtmExtractorException("Image is missing GPS Longitude data");
+ else {
+ Exiv2::URational rLon[] = {longitudeTag.toRational(0), longitudeTag.toRational(1), longitudeTag.toRational(2)};
+ bool west = (strcmp(longitudeRef.toString().c_str(), "W") == 0);
+ double degrees, minutes, seconds;
+
+ degrees = (double)rLon[0].first / (double)rLon[0].second;
+ minutes = (double)rLon[1].first / (double)rLon[1].second / 60.0;
+ seconds = (double)rLon[2].first / (double)rLon[2].second / 3600.0;
+ lon = (west ? -1 : 1) * (degrees + minutes + seconds);
+ }
+
+ // Altitude
+ if (altitudeTag.count() < 1)
+ throw UtmExtractorException("Image is missing GPS Altitude data");
+ else {
+ Exiv2::URational rAlt = altitudeTag.toRational(0);
+ bool below = (altitudeRef.count() >= 1 && altitudeRef.toLong() == 1);
+ alt = (below ? -1 : 1) * (double) rAlt.first / (double) rAlt.second;
+ }
+}
+
+void UtmExtractor::printHelp()
+{
+log_.setIsPrintingInCout(true);
+
+ log_ << "Purpose:\n";
+ log_ << "Create a coordinate file containing the GPS positions of all cameras to be used later in the ODM toolchain for automatic georeferecing.\n";
+
+ log_ << "Usage:\n";
+ log_ << "The program requires paths to a image list file, a image folder path and an output textfile to store the results.\n";
+
+ log_ << "The following flags are available:\n";
+ log_ << "Call the program with flag \"-help\", or without parameters to print this message, or check any generated log file.\n";
+ log_ << "Call the program with flag \"-verbose\", to print log messages in the standard output.\n\n";
+
+ log_ << "Parameters are specified as: \"- \", (without <>), and the following parameters are configurable:\n";
+ log_ << "\"-imageListFile \" (mandatory)\n";
+ log_ << "Path to the list containing the image names used in the bundle.out file.\n";
+
+ log_ << "\"-imagesPath \" (mandatory)\n";
+ log_ << "Path folder containing all images in the imageListFile.\n";
+
+ log_ << "\"-outputCoordFile \" (mandatory)\n";
+ log_ << "Path output textfile.\n";
+
+ log_.setIsPrintingInCout(false);
+}
diff --git a/modules/odm_extract_utm/src/UtmExtractor.hpp b/modules/odm_extract_utm/src/UtmExtractor.hpp
new file mode 100644
index 000000000..64b8e4155
--- /dev/null
+++ b/modules/odm_extract_utm/src/UtmExtractor.hpp
@@ -0,0 +1,98 @@
+#pragma once
+
+// Logging
+#include "Logger.hpp"
+#include
+
+
+/*!
+* \breif The Coord struct Class used in UtmExtractor to extract GPS positions from images and ODM output
+*/
+struct Coord
+{
+ double x, y, z;
+ Coord(double ix, double iy, double iz) : x(ix), y(iy), z(iz) {}
+};
+
+class UtmExtractor
+{
+public:
+ UtmExtractor();
+ ~UtmExtractor();
+
+ /*!
+ * \brief run Runs the texturing functionality using the provided input arguments.
+ * For a list of the accepted arguments, please see the main page documentation or
+ * call the program with parameter "-help".
+ * \param argc Application argument count.
+ * \param argv Argument values.
+ * \return 0 if successful.
+ */
+ int run (int argc, char **argv);
+
+private:
+
+ /*!
+ * \brief parseArguments Parses command line arguments.
+ * \param argc Application argument count.
+ * \param argv Argument values.
+ */
+ void parseArguments(int argc, char **argv);
+
+ /*!
+ * \breif extractUtm Performs the extraction of coordinates inside the run function.
+ */
+ void extractUtm();
+
+ /*!
+ * /brief Static method that converts a WGS84 longitude/latitude coordinate in decimal degrees to UTM.
+ *
+ * \param lon The longitude in decimal degrees (negative if western hemisphere).
+ * \param lat The latitude in decimal degrees (negative if southern hemisphere).
+ * \param alt The altitude in meters.
+ * \param x Output parameter, the easting UTM value in meters.
+ * \param y Output parameter, the northing UTM value in meters.
+ * \param utmZone Input or output parameter, the UTM zone. Set to 99 for automatic selection.
+ * \param hemisphere Input or output parameter, 'N' for norther hemisphere, 'S' for southern. Automatically selected if utmZone is 99.
+ *
+ * \returns True if successful (otherwise output parameters are 0)
+ */
+ static void convert(const double &lon, const double &lat, const double &alt, double &x, double &y, double &z, int &utmZone, char &hemisphere);
+
+ /*!
+ * \brief Static method that parses a GPS position from jhead data.
+ *
+ * \param jheadDataStream Jhead data stream with EXIF information.
+ * \param lon Output parameter, the longitude in decimal degrees.
+ * \param lat Output parameter, the latitude in decimal degrees.
+ * \param alt Output parameter, the altitude in meters.
+ *
+ * \returns True if successful (otherwise output parameters are 0)
+ */
+ static void parsePosition(Exiv2::ExifData &exifData, double &lon, double &lat, double &alt);
+
+ /*!
+ * \brief printHelp Prints help, explaining usage. Can be shown by calling the program with arguments: "-help".
+ */
+ void printHelp();
+
+ std::string imageListFileName_; /**< Path to the image list. */
+ std::string outputCoordFileName_; /**< Path to the file to store the output textfile. */
+ std::string imagesPath_; /**< Path to the folder with all images in the image list. */
+
+ Logger log_; /**< Logging object. */
+ std::string logFile_; /**< Path to store the log file. */
+
+};
+
+class UtmExtractorException : public std::exception
+{
+public:
+ UtmExtractorException() : message("Error in OdmExtractUtm") {}
+ UtmExtractorException(std::string msgInit) : message("Error in OdmExtractUtm:\n" + msgInit) {}
+ ~UtmExtractorException() throw() {}
+ virtual const char* what() const throw() {return message.c_str(); }
+
+private:
+ std::string message; /**< The error message. */
+};
diff --git a/modules/odm_extract_utm/src/main.cpp b/modules/odm_extract_utm/src/main.cpp
new file mode 100644
index 000000000..1d1aa158b
--- /dev/null
+++ b/modules/odm_extract_utm/src/main.cpp
@@ -0,0 +1,9 @@
+
+
+#include "UtmExtractor.hpp"
+
+int main (int argc, char **argv)
+{
+ UtmExtractor utmExtractor;
+ return utmExtractor.run(argc, argv);
+}
diff --git a/modules/odm_georef/CMakeLists.txt b/modules/odm_georef/CMakeLists.txt
new file mode 100644
index 000000000..765bf7c87
--- /dev/null
+++ b/modules/odm_georef/CMakeLists.txt
@@ -0,0 +1,36 @@
+project(odm_georef)
+cmake_minimum_required(VERSION 2.8)
+
+# Set pcl dir to the input spedified with option -DPCL_DIR="path"
+set(PCL_DIR "PCL_DIR-NOTFOUND" CACHE "PCL_DIR" "Path to the pcl installation directory")
+set(OPENCV_DIR "OPENCV_DIR-NOTFOUND" CACHE "OPENCV_DIR" "Path to the opencv installation directory")
+set(PROJ4_INCLUDE_DIR "/usr/include/" CACHE "PROJ4_INCLUDE_DIR" "Path to the proj4 inlcude directory")
+find_library(PROJ4_LIBRARY "libproj.so" PATHS "/usr/lib" "/usr/lib/x86_64-linux-gnu")
+#set(PROJ4_LIBRARY "/usr/lib/x86_64-linux-gnu/libproj.so" CACHE "PROJ4_LIBRARY" "Path to the proj4 library directory")
+
+# Add compiler options.
+add_definitions(-Wall -Wextra -Wconversion -pedantic)
+#add_definitions(-pedantic -pedantic-errors -Wall -Wextra -Werror -Wfatal-errors -Wabi -Wctor-dtor-privacy -Wnon-virtual-dtor -Wreorder -Weffc++ -Wstrict-null-sentinel -Wnon-template-friend -Wold-style-cast -Woverloaded-virtual -Wpmf-conversions -Wsign-promo -Waddress -Warray-bounds -Wattributes -Wbuiltin-macro-redefined -Wc++0x-compat -Wcast-align -Wcast-qual -Wchar-subscripts -Wclobbered -Wcomment -Wconversion -Wcoverage-mismatch -Wdeprecated -Wdeprecated-declarations -Wdisabled-optimization -Wdiv-by-zero -Wempty-body -Wenum-compare -Wendif-labels -Wfatal-errors -Wfloat-equal -Wformat -Wformat=2 -Wformat-contains-nul -Wformat-extra-args -Wformat-nonliteral -Wformat-security -Wformat-y2k -Wignored-qualifiers -Winit-self -Wint-to-pointer-cast -Winvalid-offsetof -Winvalid-pch -Wlogical-op -Wmain -Wvariadic-macros -Wmissing-braces -Wmissing-field-initializers -Wmissing-include-dirs -Wmissing-noreturn -Wvla -Wmultichar -Wfatal-errors -Wnonnull -Woverflow -Woverlength-strings -Wpacked -Wpacked-bitfield-compat -Wparentheses -Wpointer-arith -Wredundant-decls -Wsequence-point -Wshadow -Wsign-compare -Wsign-conversion -Wstack-protector -Wstrict-overflow=5 -Wswitch -Wswitch-enum -Wsync-nand -Wvolatile-register-var -Wtrigraphs -Wtype-limits -Wuninitialized -Wunknown-pragmas -Wwrite-strings -Wpragmas -Wunreachable-code -Wunused -Wunused-function -Wunused-label -Wunused-parameter -Wunused-value -Wunused-variable -Wno-return-type)
+
+# Find pcl at the location specified by PCL_DIR
+find_package(PCL 1.8 HINTS "${PCL_DIR}/share/pcl-1.8")
+
+# Find OpenCV at the default location
+find_package(OpenCV HINTS "${OPENCV_DIR}" REQUIRED)
+
+# Only link with required opencv modules.
+set(OpenCV_LIBS opencv_core opencv_imgproc opencv_highgui)
+
+# Add the PCL and Eigen include dirs.
+# Necessary since the PCL_INCLUDE_DIR variable set bu find_package is broken.)
+include_directories(${PCL_ROOT}/include/pcl-${PCL_VERSION_MAJOR}.${PCL_VERSION_MINOR})
+include_directories(${EIGEN_ROOT})
+
+# Add source directory
+aux_source_directory("./src" SRC_LIST)
+
+# Add exectuteable
+add_executable(${PROJECT_NAME} ${SRC_LIST})
+
+# Link
+target_link_libraries(${PROJECT_NAME} ${PCL_COMMON_LIBRARIES} ${PCL_IO_LIBRARIES} ${PCL_SURFACE_LIBRARIES} ${PROJ4_LIBRARY} ${OpenCV_LIBS})
diff --git a/modules/odm_georef/src/FindTransform.cpp b/modules/odm_georef/src/FindTransform.cpp
new file mode 100644
index 000000000..a0f0a581c
--- /dev/null
+++ b/modules/odm_georef/src/FindTransform.cpp
@@ -0,0 +1,149 @@
+// This
+#include "FindTransform.hpp"
+
+Vec3::Vec3(double x, double y, double z) :x_(x), y_(y), z_(z)
+{
+
+}
+Vec3::Vec3(const Vec3 &o) : x_(o.x_), y_(o.y_), z_(o.z_)
+{
+
+}
+
+Vec3 Vec3::cross(Vec3 o) const
+{
+ Vec3 res;
+ res.x_ = y_*o.z_ - z_*o.y_;
+ res.y_ = z_*o.x_ - x_*o.z_;
+ res.z_ = x_*o.y_ - y_*o.x_;
+ return res;
+}
+
+double Vec3::dot(Vec3 o) const
+{
+ return x_*o.x_ + y_*o.y_ + z_*o.z_;
+}
+
+double Vec3::length() const
+{
+ return sqrt(x_*x_ + y_*y_ + z_*z_);
+}
+
+Vec3 Vec3::norm() const
+{
+ Vec3 res;
+ double l = length();
+ res.x_ = x_ / l;
+ res.y_ = y_ / l;
+ res.z_ = z_ / l;
+ return res;
+}
+
+Vec3 Vec3::operator*(double d) const
+{
+ return Vec3(x_*d, y_*d, z_*d);
+}
+
+Vec3 Vec3::operator+(Vec3 o) const
+{
+ return Vec3(x_ + o.x_, y_ + o.y_,z_ + o.z_);
+}
+
+Vec3 Vec3::operator-(Vec3 o) const
+{
+ return Vec3(x_ - o.x_, y_ - o.y_,z_ - o.z_);
+}
+
+OnMat3::OnMat3(Vec3 r1, Vec3 r2, Vec3 r3) : r1_(r1), r2_(r2), r3_(r3)
+{
+ c1_.x_ = r1_.x_; c2_.x_ = r1_.y_; c3_.x_ = r1_.z_;
+ c1_.y_ = r2_.x_; c2_.y_ = r2_.y_; c3_.y_ = r2_.z_;
+ c1_.z_ = r3_.x_; c2_.z_ = r3_.y_; c3_.z_ = r3_.z_;
+}
+OnMat3::OnMat3(const OnMat3 &o) : r1_(o.r1_), r2_(o.r2_), r3_(o.r3_)
+{
+ c1_.x_ = r1_.x_; c2_.x_ = r1_.y_; c3_.x_ = r1_.z_;
+ c1_.y_ = r2_.x_; c2_.y_ = r2_.y_; c3_.y_ = r2_.z_;
+ c1_.z_ = r3_.x_; c2_.z_ = r3_.y_; c3_.z_ = r3_.z_;
+}
+
+double OnMat3::det() const
+{
+ return r1_.x_*r2_.y_*r3_.z_ + r1_.y_*r2_.z_*r3_.x_ + r1_.z_*r2_.x_*r3_.y_ - r1_.z_*r2_.y_*r3_.x_ - r1_.y_*r2_.x_*r3_.z_ - r1_.x_*r2_.z_*r3_.y_;
+}
+
+OnMat3 OnMat3::transpose() const
+{
+ return OnMat3(Vec3(r1_.x_, r2_.x_, r3_.x_), Vec3(r1_.y_, r2_.y_, r3_.y_), Vec3(r1_.z_, r2_.z_, r3_.z_));
+}
+
+OnMat3 OnMat3::operator*(OnMat3 o) const
+{
+ return OnMat3( Vec3(r1_.dot(o.c1_), r1_.dot(o.c2_), r1_.dot(o.c3_)),
+ Vec3(r2_.dot(o.c1_), r2_.dot(o.c2_), r2_.dot(o.c3_)),
+ Vec3(r3_.dot(o.c1_), r3_.dot(o.c2_), r3_.dot(o.c3_)));
+}
+
+Vec3 OnMat3::operator*(Vec3 o)
+{
+ return Vec3(r1_.dot(o), r2_.dot(o), r3_.dot(o));
+}
+
+Mat4::Mat4()
+{
+ r1c1_ = 1.0; r1c2_ = 0.0; r1c3_ = 0.0; r1c4_ = 0.0;
+ r2c1_ = 0.0; r2c2_ = 1.0; r2c3_ = 0.0; r2c4_ = 0.0;
+ r3c1_ = 0.0; r3c2_ = 0.0; r3c3_ = 1.0; r3c4_ = 0.0;
+ r4c1_ = 0.0; r4c2_ = 0.0; r4c3_ = 0.0; r4c4_ = 1.0;
+}
+
+Mat4::Mat4(OnMat3 rotation, Vec3 translation, double scaling)
+{
+ r1c1_ = scaling * rotation.r1_.x_; r1c2_ = scaling * rotation.r1_.y_; r1c3_ = scaling * rotation.r1_.z_; r1c4_ = translation.x_;
+ r2c1_ = scaling * rotation.r2_.x_; r2c2_ = scaling * rotation.r2_.y_; r2c3_ = scaling * rotation.r2_.z_; r2c4_ = translation.y_;
+ r3c1_ = scaling * rotation.r3_.x_; r3c2_ = scaling * rotation.r3_.y_; r3c3_ = scaling * rotation.r3_.z_; r3c4_ = translation.z_;
+ r4c1_ = 0.0; r4c2_ = 0.0; r4c3_ = 0.0; r4c4_ = 1.0;
+}
+
+Vec3 Mat4::operator*(Vec3 o)
+{
+ return Vec3(
+ r1c1_ * o.x_ + r1c2_* o.y_ + r1c3_* o.z_ + r1c4_,
+ r2c1_ * o.x_ + r2c2_* o.y_ + r2c3_* o.z_ + r2c4_,
+ r3c1_ * o.x_ + r3c2_* o.y_ + r3c3_* o.z_ + r3c4_
+ );
+}
+
+void FindTransform::findTransform(Vec3 fromA, Vec3 fromB, Vec3 fromC, Vec3 toA, Vec3 toB, Vec3 toC)
+{
+ Vec3 a1 = toA;
+ Vec3 b1 = toB;
+ Vec3 c1 = toC;
+ Vec3 a2 = fromA;
+ Vec3 b2 = fromB;
+ Vec3 c2 = fromC;
+
+ Vec3 y1 = (a1 - c1).cross(b1 - c1).norm();
+ Vec3 z1 = (a1 - c1).norm();
+ Vec3 x1 = y1.cross(z1);
+
+ Vec3 y2 = (a2 - c2).cross(b2 - c2).norm();
+ Vec3 z2 = (a2 - c2).norm();
+ Vec3 x2 = y2.cross(z2);
+ OnMat3 mat1 = OnMat3(x1, y1, z1).transpose();
+ OnMat3 mat2 = OnMat3(x2, y2, z2).transpose();
+
+ OnMat3 rotation = mat1 * mat2.transpose();
+ Vec3 translation = c1 - c2;
+
+ double scale = (a1 - c1).length() / (a2 - c2).length();
+
+ translation = rotation * c2 * (-scale) + c1;
+ Mat4 transformation(rotation, translation, scale);
+ transform_ = transformation;
+}
+
+double FindTransform::error(Vec3 fromA, Vec3 toA)
+{
+ return (transform_*fromA - toA).length();
+}
diff --git a/modules/odm_georef/src/FindTransform.hpp b/modules/odm_georef/src/FindTransform.hpp
new file mode 100644
index 000000000..19842e423
--- /dev/null
+++ b/modules/odm_georef/src/FindTransform.hpp
@@ -0,0 +1,165 @@
+// C++
+#include
+#include
+#include
+#include
+#include
+
+/*!
+ * \brief Handles basic 3d vector math.
+ **/
+struct Vec3
+{
+ Vec3(double x = 0.0, double y = 0.0, double z = 0.0);
+ Vec3(const Vec3 &o);
+
+ double x_,y_,z_; /**< The x, y and z values of the vector. **/
+
+ /*!
+ * \brief cross The cross product between two vectors.
+ **/
+ Vec3 cross(Vec3 o) const;
+
+ /*!
+ * \brief dot The scalar product between two vectors.
+ **/
+ double dot(Vec3 o) const;
+
+ /*!
+ * \brief length The length of the vector.
+ **/
+ double length() const;
+
+ /*!
+ * \brief norm Returns a normalized version of this vector.
+ **/
+ Vec3 norm() const;
+
+ /*!
+ * \brief Scales this vector.
+ **/
+ Vec3 operator*(double d) const;
+
+ /*!
+ * \brief Addition between two vectors.
+ **/
+ Vec3 operator+(Vec3 o) const;
+
+ /*!
+ * \brief Subtraction between two vectors.
+ **/
+ Vec3 operator-(Vec3 o) const;
+
+ friend std::ostream & operator<<(std::ostream &os, Vec3 v)
+ {
+ return os << "[" << std::setprecision(8) << v.x_ << ", " << std::setprecision(4) << v.y_ << ", " << v.z_ << "]";
+ }
+};
+
+/*!
+ * \brief Describes a 3d orthonormal matrix.
+ **/
+class OnMat3
+{
+public:
+ OnMat3(Vec3 r1, Vec3 r2, Vec3 r3);
+ OnMat3(const OnMat3 &o);
+
+ Vec3 r1_; /**< The first row of the matrix. **/
+ Vec3 r2_; /**< The second row of the matrix. **/
+ Vec3 r3_; /**< The third row of the matrix. **/
+ Vec3 c1_; /**< The first column of the matrix. **/
+ Vec3 c2_; /**< The second column of the matrix. **/
+ Vec3 c3_; /**< The third column of the matrix. **/
+
+ /*!
+ * \brief The determinant of the matrix.
+ **/
+ double det() const;
+
+ /*!
+ * \brief The transpose of the OnMat3 (equal to inverse).
+ **/
+ OnMat3 transpose() const;
+
+ /*!
+ * \brief Matrix multiplication between two ON matrices.
+ **/
+ OnMat3 operator*(OnMat3 o) const;
+
+ /*!
+ * \brief Right side multiplication with a 3d vector.
+ **/
+ Vec3 operator*(Vec3 o);
+
+ friend std::ostream & operator<<(std::ostream &os, OnMat3 m)
+ {
+ return os << "[" << std::endl << m.r1_ << std::endl << m.r2_ << std::endl << m.r3_ << std::endl << "]" << std::endl;
+ }
+};
+
+/*!
+ * \brief Describes an affine transformation.
+ **/
+class Mat4
+{
+public:
+ Mat4();
+ Mat4(OnMat3 rotation, Vec3 translation, double scaling);
+
+ /*!
+ * \brief Right side multiplication with a 3d vector.
+ **/
+ Vec3 operator*(Vec3 o);
+
+ double r1c1_; /**< Matrix element 0 0 **/
+ double r1c2_; /**< Matrix element 0 1 **/
+ double r1c3_; /**< Matrix element 0 2 **/
+ double r1c4_; /**< Matrix element 0 3 **/
+ double r2c1_; /**< Matrix element 1 0 **/
+ double r2c2_; /**< Matrix element 1 1 **/
+ double r2c3_; /**< Matrix element 1 2 **/
+ double r2c4_; /**< Matrix element 1 3 **/
+ double r3c1_; /**< Matrix element 2 0 **/
+ double r3c2_; /**< Matrix element 2 1 **/
+ double r3c3_; /**< Matrix element 2 2 **/
+ double r3c4_; /**< Matrix element 2 3 **/
+ double r4c1_; /**< Matrix element 3 0 **/
+ double r4c2_; /**< Matrix element 3 1 **/
+ double r4c3_; /**< Matrix element 3 2 **/
+ double r4c4_; /**< Matrix element 3 3 **/
+
+ friend std::ostream & operator<<(std::ostream &os, Mat4 m)
+ {
+ std::stringstream ss;
+ ss.precision(8);
+ ss.setf(std::ios::fixed, std::ios::floatfield);
+
+ ss << "[ " << m.r1c1_ << ",\t" << m.r1c2_ << ",\t" << m.r1c3_ << ",\t" << m.r1c4_ << " ]" << std::endl <<
+ "[ " << m.r2c1_ << ",\t" << m.r2c2_ << ",\t" << m.r2c3_ << ",\t" << m.r2c4_ << " ]" << std::endl <<
+ "[ " << m.r3c1_ << ",\t" << m.r3c2_ << ",\t" << m.r3c3_ << ",\t" << m.r3c4_ << " ]" << std::endl <<
+ "[ " << m.r4c1_ << ",\t" << m.r4c2_ << ",\t" << m.r4c3_ << ",\t" << m.r4c4_ << " ]";
+
+ return os << ss.str();
+ }
+
+};
+
+class FindTransform
+{
+public:
+ /*!
+ * \brief findTransform Generates an affine transform from the three 'from' vector to the three 'to' vectors.
+ * The transform is such that transform * fromA = toA,
+ * transform * fromB = toB,
+ * transform * fromC = toC,
+ **/
+ void findTransform(Vec3 fromA, Vec3 fromB, Vec3 fromC, Vec3 toA, Vec3 toB, Vec3 toC);
+
+ /*!
+ * \brief error Returns the distance beteween the 'from' and 'to' vectors, after the transform has been applied.
+ **/
+ double error(Vec3 fromA, Vec3 toA);
+
+ Mat4 transform_; /**< The affine transform. **/
+};
diff --git a/modules/odm_georef/src/Georef.cpp b/modules/odm_georef/src/Georef.cpp
new file mode 100644
index 000000000..3676a65a7
--- /dev/null
+++ b/modules/odm_georef/src/Georef.cpp
@@ -0,0 +1,1732 @@
+// PCL
+#include
+#include
+
+// OpenCV
+#include
+#include
+
+// This
+#include "Georef.hpp"
+
+std::ostream& operator<<(std::ostream &os, const GeorefSystem &geo)
+{
+ return os << geo.system_ << "\n" << static_cast(geo.eastingOffset_) << " " << static_cast(geo.northingOffset_);
+}
+
+GeorefGCP::GeorefGCP()
+ :x_(0.0), y_(0.0), z_(0.0), use_(false), localX_(0.0), localY_(0.0), localZ_(0.0),cameraIndex_(0), pixelX_(0), pixelY_(0.0), image_("")
+{
+}
+
+GeorefGCP::~GeorefGCP()
+{
+}
+
+void GeorefGCP::extractGCP(std::istringstream &gcpStream)
+{
+ gcpStream >> x_ >> y_ >> z_ >> pixelX_ >> pixelY_ >> image_;
+}
+
+Vec3 GeorefGCP::getPos()
+{
+ return Vec3(localX_,localY_,localZ_);
+}
+
+Vec3 GeorefGCP::getReferencedPos()
+{
+ return Vec3(x_,y_,z_);
+}
+
+GeorefCamera::GeorefCamera()
+ :focalLength_(0.0), k1_(0.0), k2_(0.0), transform_(NULL), position_(NULL), pose_(NULL)
+{
+}
+
+GeorefCamera::GeorefCamera(const GeorefCamera &other)
+ : focalLength_(other.focalLength_), k1_(other.k1_), k2_(other.k2_),
+ easting_(other.easting_), northing_(other.northing_), altitude_(other.altitude_),
+ transform_(NULL), position_(NULL), pose_(NULL)
+{
+ if(NULL != other.transform_)
+ {
+ transform_ = new Eigen::Affine3f(*other.transform_);
+ }
+ if(NULL != other.position_)
+ {
+ position_ = new Eigen::Vector3f(*other.position_);
+ }
+ if(pose_ != other.pose_)
+ {
+ pose_ = new Eigen::Affine3f(*other.pose_);
+ }
+}
+
+GeorefCamera::~GeorefCamera()
+{
+ if(NULL != transform_)
+ {
+ delete transform_;
+ transform_ = NULL;
+ }
+ if(NULL != position_)
+ {
+ delete position_;
+ position_ = NULL;
+ }
+ if(pose_ != NULL)
+ {
+ delete pose_;
+ pose_ = NULL;
+ }
+}
+
+void GeorefCamera::extractCamera(std::ifstream &bundleStream)
+{
+ // Extract intrinsic parameters.
+ bundleStream >> focalLength_ >> k1_ >> k2_;
+
+ Eigen::Vector3f t;
+ Eigen::Matrix3f rot;
+ Eigen::Affine3f transform;
+ Eigen::Affine3f pose;
+
+ bundleStream >> transform(0,0); // Read rotation (0,0) from bundle file
+ bundleStream >> transform(0,1); // Read rotation (0,1) from bundle file
+ bundleStream >> transform(0,2); // Read rotation (0,2) from bundle file
+
+ bundleStream >> transform(1,0); // Read rotation (1,0) from bundle file
+ bundleStream >> transform(1,1); // Read rotation (1,1) from bundle file
+ bundleStream >> transform(1,2); // Read rotation (1,2) from bundle file
+
+ bundleStream >> transform(2,0); // Read rotation (2,0) from bundle file
+ bundleStream >> transform(2,1); // Read rotation (2,1) from bundle file
+ bundleStream >> transform(2,2); // Read rotation (2,2) from bundle file
+
+ bundleStream >> t(0); // Read translation (0,3) from bundle file
+ bundleStream >> t(1); // Read translation (1,3) from bundle file
+ bundleStream >> t(2); // Read translation (2,3) from bundle file
+
+ //
+ pose(0,0) = transform(0,0);
+ pose(0,1) = transform(0,1);
+ pose(0,2) = transform(0,2);
+
+ pose(1,0) = transform(1,0);
+ pose(1,1) = transform(1,1);
+ pose(1,2) = transform(1,2);
+
+ pose(2,0) = transform(2,0);
+ pose(2,1) = transform(2,1);
+ pose(2,2) = transform(2,2);
+
+ pose(0,3) = t(0);
+ pose(1,3) = t(1);
+ pose(2,3) = t(2);
+
+ pose(3,0) = 0.0;
+ pose(3,1) = 0.0;
+ pose(3,2) = 0.0;
+ pose(3,3) = 1.0;
+
+ pose = pose.inverse();
+
+ // Column negation
+ pose(0,2) = -1.0*pose(0,2);
+ pose(1,2) = -1.0*pose(1,2);
+ pose(2,2) = -1.0*pose(2,2);
+
+ pose(0,1) = -1.0*pose(0,1);
+ pose(1,1) = -1.0*pose(1,1);
+ pose(2,1) = -1.0*pose(2,1);
+
+ if (pose_ != NULL)
+ {
+ delete pose_;
+ pose_ = NULL;
+ }
+
+ pose_ = new Eigen::Affine3f(pose);
+
+ rot = transform.matrix().topLeftCorner<3,3>();
+
+ // Calculate translation according to -R't and store in vector.
+ t = -rot.transpose()*t;
+
+ transform(0,3) = t(0);
+ transform(1,3) = t(1);
+ transform(2,3) = t(2);
+
+
+ // Set transform and position.
+ if(NULL != transform_)
+ {
+ delete transform_;
+ transform_ = NULL;
+ }
+
+ transform_ = new Eigen::Affine3f(transform);
+
+ if(NULL != position_)
+ {
+ delete position_;
+ position_ = NULL;
+ }
+ position_ = new Eigen::Vector3f(t);
+}
+
+void GeorefCamera::extractCameraGeoref(std::istringstream &coordStream)
+{
+ coordStream >> easting_ >> northing_ >> altitude_;
+}
+
+Vec3 GeorefCamera::getPos()
+{
+ return Vec3((*position_)(0),(*position_)(1),(*position_)(2));
+}
+
+Vec3 GeorefCamera::getReferencedPos()
+{
+ return Vec3(easting_,northing_,altitude_);
+}
+
+bool GeorefCamera::isValid()
+{
+ return focalLength_ != 0 && k1_ != 0 && k2_ != 0;
+}
+
+std::ostream& operator<<(std::ostream &os, const GeorefCamera &cam)
+{
+ os << "Focal, k1, k2 : " << cam.focalLength_ << ", " << cam.k1_ << ", " << cam.k2_ << "\n";
+ if(NULL != cam.transform_)
+ {
+ os << "Transform :\n" << cam.transform_->matrix() << "\n";
+ }
+ else
+ {
+ os << "Transform :\nNULL\n";
+ }
+ if(NULL != cam.position_)
+ {
+ os << "Position :\n" << cam.position_->matrix() << "\n";
+ }
+ else
+ {
+ os << "Position :\nNULL\n";
+ }
+ os << "east, north, alt : " << cam.easting_ << ", " << cam.northing_ << ", " << cam.altitude_ << '\n';
+ return os;
+}
+
+Georef::Georef() : log_(false)
+{
+ georeferencePointCloud_ = false;
+ useGCP_ = false;
+ bundleFilename_ = "";
+ inputCoordFilename_ = "";
+ outputCoordFilename_ = "";
+ inputObjFilename_ = "";
+ outputObjFilename_ = "";
+ exportCoordinateFile_ = false;
+ exportGeorefSystem_ = false;
+}
+
+Georef::~Georef()
+{
+}
+
+int Georef::run(int argc, char *argv[])
+{
+ try
+ {
+ parseArguments(argc, argv);
+ createGeoreferencedModel();
+ }
+ catch (const GeorefException& e)
+ {
+ log_.setIsPrintingInCout(true);
+ log_ << e.what() << "\n";
+ log_.print(logFile_);
+ return EXIT_FAILURE;
+ }
+ catch (const std::exception& e)
+ {
+ log_.setIsPrintingInCout(true);
+ log_ << "Error in Georef:\n";
+ log_ << e.what() << "\n";
+ log_.print(logFile_);
+ return EXIT_FAILURE;
+ }
+ catch (...)
+ {
+ log_.setIsPrintingInCout(true);
+ log_ << "Unknown error, terminating:\n";
+ log_.print(logFile_);
+ return EXIT_FAILURE;
+ }
+
+ log_.print(logFile_);
+
+ return EXIT_SUCCESS;
+}
+
+void Georef::parseArguments(int argc, char *argv[])
+{
+ bool outputSpecified = false;
+ bool outputPointCloudSpecified = false;
+ bool imageListSpecified = false;
+ bool gcpFileSpecified = false;
+ bool imageLocation = false;
+ // bool bundleResized = false;
+ bool outputCoordSpecified = false;
+ bool inputCoordSpecified = false;
+
+ logFile_ = std::string(argv[0]) + "_log.txt";
+ log_ << logFile_ << "\n";
+
+ finalTransformFile_ = std::string(argv[0]) + "_transform.txt";
+
+ // If no arguments were passed, print help.
+ if (argc == 1)
+ {
+ printHelp();
+ }
+
+ log_ << "Arguments given\n";
+ for(int argIndex = 1; argIndex < argc; ++argIndex)
+ {
+ log_ << argv[argIndex] << '\n';
+ }
+
+ log_ << '\n';
+ for(int argIndex = 1; argIndex < argc; ++argIndex)
+ {
+ // The argument to be parsed.
+ std::string argument = std::string(argv[argIndex]);
+
+ if(argument == "-help")
+ {
+ printHelp();
+ }
+ else if(argument == "-verbose")
+ {
+ log_.setIsPrintingInCout(true);
+ }
+ else if (argument == "-logFile")
+ {
+ ++argIndex;
+ if (argIndex >= argc)
+ {
+ throw GeorefException("Missing argument for '" + argument + "'.");
+ }
+ logFile_ = std::string(argv[argIndex]);
+ std::ofstream testFile(logFile_.c_str());
+ if (!testFile.is_open())
+ {
+ throw GeorefException("Argument '" + argument + "' has a bad value.");
+ }
+ log_ << "Log file path was set to: " << logFile_ << "\n";
+ }
+ else if (argument == "-outputTransformFile")
+ {
+ ++argIndex;
+ if (argIndex >= argc)
+ {
+ throw GeorefException("Missing argument for '" + argument + "'.");
+ }
+ finalTransformFile_ = std::string(argv[argIndex]);
+ std::ofstream testFile(logFile_.c_str());
+ if (!testFile.is_open())
+ {
+ throw GeorefException("Argument '" + argument + "' has a bad value.");
+ }
+ log_ << "Transform file path was set to: " << finalTransformFile_ << "\n";
+ }
+ else if(argument == "-bundleFile" && argIndex < argc)
+ {
+ argIndex++;
+ if (argIndex >= argc)
+ {
+ throw GeorefException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
+ }
+ bundleFilename_ = std::string(argv[argIndex]);
+ log_ << "Reading cameras from: " << bundleFilename_ << "\n";
+ }
+ else if(argument == "-inputCoordFile" && argIndex < argc)
+ {
+ argIndex++;
+ if (argIndex >= argc)
+ {
+ throw GeorefException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
+ }
+ inputCoordFilename_ = std::string(argv[argIndex]);
+ log_ << "Reading cameras gps exif positions from: " << inputCoordFilename_ << "\n";
+ inputCoordSpecified = true;
+ }
+ else if(argument == "-outputCoordFile" && argIndex < argc)
+ {
+ argIndex++;
+ if (argIndex >= argc)
+ {
+ throw GeorefException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
+ }
+ outputCoordFilename_ = std::string(argv[argIndex]);
+ log_ << "Exporting cameras georeferenced gps positions to: " << outputCoordFilename_ << "\n";
+ exportCoordinateFile_ = true;
+ outputCoordSpecified = true;
+ }
+ else if(argument == "-inputFile" && argIndex < argc)
+ {
+ argIndex++;
+ if (argIndex >= argc)
+ {
+ throw GeorefException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
+ }
+ inputObjFilename_ = std::string(argv[argIndex]);
+ log_ << "Reading textured mesh from: " << inputObjFilename_ << "\n";
+ }
+ else if(argument == "-inputPointCloudFile" && argIndex < argc)
+ {
+ argIndex++;
+ if (argIndex >= argc)
+ {
+ throw GeorefException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
+ }
+ inputPointCloudFilename_ = std::string(argv[argIndex]);
+ log_ << "Reading point cloud from: " << inputPointCloudFilename_ << "\n";
+ georeferencePointCloud_ = true;
+ }
+ else if(argument == "-gcpFile" && argIndex < argc)
+ {
+ argIndex++;
+ if (argIndex >= argc)
+ {
+ throw GeorefException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
+ }
+ gcpFilename_ = std::string(argv[argIndex]);
+ log_ << "Reading GCPs from: " << gcpFilename_ << "\n";
+ gcpFileSpecified = true;
+ }
+ else if(argument == "-imagesListPath" && argIndex < argc)
+ {
+ argIndex++;
+ if (argIndex >= argc)
+ {
+ throw GeorefException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
+ }
+ imagesListPath_ = std::string(argv[argIndex]);
+ log_ << "Reading image list from: " << imagesListPath_ << "\n";
+ imageListSpecified = true;
+ }
+ else if(argument == "-imagesPath" && argIndex < argc)
+ {
+ argIndex++;
+ if (argIndex >= argc)
+ {
+ throw GeorefException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
+ }
+ imagesLocation_ = std::string(argv[argIndex]);
+ log_ << "Images location is set to: " << imagesLocation_ << "\n";
+ imageLocation = true;
+ }
+ else if(argument == "-georefFileOutputPath" && argIndex < argc)
+ {
+ argIndex++;
+ if (argIndex >= argc)
+ {
+ throw GeorefException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
+ }
+ georefFilename_ = std::string(argv[argIndex]);
+ log_ << "Georef file output path is set to: " << georefFilename_ << "\n";
+ exportGeorefSystem_ = true;
+ }
+ /*else if(argument == "-bundleResizedTo" && argIndex < argc)
+ {
+ argIndex++;
+ if (argIndex >= argc)
+ {
+ throw GeorefException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
+ }
+ std::stringstream ss(argv[argIndex]);
+ ss >> bundleResizedTo_;
+ if (ss.bad())
+ {
+ throw GeorefException("Argument '" + argument + "' has a bad value. (wrong type)");
+ }
+ log_ << "Bundle resize value is set to: " << bundleResizedTo_ << "\n";
+ bundleResized = true;
+ }*/
+ else if(argument == "-outputFile" && argIndex < argc)
+ {
+ argIndex++;
+ if (argIndex >= argc)
+ {
+ throw GeorefException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
+ }
+ outputObjFilename_ = std::string(argv[argIndex]);
+ log_ << "Writing output to: " << outputObjFilename_ << "\n";
+ outputSpecified = true;
+ }
+ else if(argument == "-outputPointCloudFile" && argIndex < argc)
+ {
+ argIndex++;
+ if (argIndex >= argc)
+ {
+ throw GeorefException("Argument '" + argument + "' expects 1 more input following it, but no more inputs were provided.");
+ }
+ outputPointCloudFilename_ = std::string(argv[argIndex]);
+ log_ << "Writing output to: " << outputPointCloudFilename_ << "\n";
+ outputPointCloudSpecified = true;
+ }
+ else
+ {
+ printHelp();
+ throw GeorefException("Unrecognised argument '" + argument + "'");
+ }
+ }
+
+ if (inputCoordSpecified && outputCoordSpecified)
+ {
+ throw GeorefException("Both output and input coordfile specified, only one of those are accepted.");
+ }
+
+ if (imageListSpecified && gcpFileSpecified && imageLocation ) // && bundleResized)
+ {
+ useGCP_ = true;
+ }
+ else
+ {
+ log_ << '\n';
+ log_ << "Missing input in order to use GCP for georeferencing. Using EXIF data instead.\n";
+ }
+
+ if(georeferencePointCloud_ && !outputPointCloudSpecified)
+ {
+ setDefaultPointCloudOutput();
+ }
+
+ if(!outputSpecified)
+ {
+ setDefaultOutput();
+ }
+}
+
+void Georef::printHelp()
+{
+ bool printInCoutPop = log_.isPrintingInCout();
+ log_.setIsPrintingInCout(true);
+
+ log_ << "Georef.exe\n\n";
+
+ log_ << "Purpose:" << "\n";
+ log_ << "Georeference a textured mesh with the use of ground control points or exif data from the images." << "\n";
+
+ log_ << "Usage:" << "\n";
+ log_ << "The program requires a path to a camera bundle file, a camera georeference coords file, and an input OBJ mesh file. All other input parameters are optional." << "\n\n";
+
+ log_ << "The following flags are available\n";
+ log_ << "Call the program with flag \"-help\", or without parameters to print this message, or check any generated log file.\n";
+ log_ << "Call the program with flag \"-verbose\", to print log messages in the standard output stream as well as in the log file.\n\n";
+
+ log_ << "Parameters are specified as: \"- \", (without <>), and the following parameters are configureable: " << "\n";
+ log_ << "\"-bundleFile \" (mandatory)" << "\n";
+ log_ << "\"Input cameras bundle file.\n\n";
+
+ log_ << "\"-gcpFile \" (mandatory if using ground control points)\n";
+ log_ << "Path to the file containing the ground control points used for georeferencing.\n";
+ log_ << "The file needs to be on the following line format:\n";
+ log_ << "easting northing height pixelrow pixelcol imagename\n\n";
+
+ log_ << "\"-inputCoordFile \" (mandatory if using exif data)" << "\n";
+ log_ << "\"Input cameras geroreferenced coords file.\n\n";
+
+ log_ << "\"-outputCoordFile \" (optional)" << "\n";
+ log_ << "\"Output cameras geroreferenced coords file.\n\n";
+
+ log_ << "\"-inputFile \" (mandatory)" << "\n";
+ log_ << "\"Input obj file that must contain a textured mesh.\n\n";
+
+ log_ << "\"-inputPointCloudFile \" (optional)" << "\n";
+ log_ << "\"Input ply file that must contain a point cloud.\n\n";
+
+ log_ << "\"-imagesListPath \" (mandatory if using ground control points)\n";
+ log_ << "Path to the list containing the image names used in the bundle.out file.\n\n";
+
+ log_ << "\"-imagesPath \" (mandatory if using ground control points)\n";
+ log_ << "Path to the folder containing full resolution images.\n\n";
+
+ // log_ << "\"-bundleResizedTo \" (mandatory if using ground control points)\n";
+ // log_ << "The resized resolution used in bundler.\n\n";
+
+ log_ << "\"-outputFile \" (optional, default _geo)" << "\n";
+ log_ << "\"Output obj file that will contain the georeferenced texture mesh.\n\n";
+
+ log_ << "\"-outputPointCloudFile \" (mandatory if georeferencing a point cloud)" << "\n";
+ log_ << "\"Output ply file that will contain the georeferenced point cloud.\n\n";
+
+ log_.setIsPrintingInCout(printInCoutPop);
+}
+
+void Georef::setDefaultOutput()
+{
+ if(inputObjFilename_.empty())
+ {
+ throw GeorefException("Tried to generate default output file without having an input file.");
+ }
+
+ std::string tmp = inputObjFilename_;
+ size_t findPos = tmp.find_last_of(".");
+
+ if(std::string::npos == findPos)
+ {
+ throw GeorefException("Tried to generate default ouptut file, could not find .obj in the input file:\n\'"+inputObjFilename_+"\'");
+ }
+
+ tmp = tmp.substr(0, findPos);
+
+ outputObjFilename_ = tmp + "_geo.obj";
+ log_ << "Writing output to: " << outputObjFilename_ << "\n";
+}
+
+void Georef::setDefaultPointCloudOutput()
+{
+ if(inputPointCloudFilename_.empty())
+ {
+ throw GeorefException("Tried to generate default point cloud ouptut file without having an input file.");
+ }
+
+ std::string tmp = inputPointCloudFilename_;
+ size_t findPos = tmp.find_last_of(".");
+
+ if(std::string::npos == findPos)
+ {
+ throw GeorefException("Tried to generate default ouptut file, could not find .ply in the input file:\n\'"+inputPointCloudFilename_+"\'");
+ }
+
+ tmp = tmp.substr(0, findPos);
+
+ outputPointCloudFilename_ = tmp + "_geo.ply";
+ log_ << "Writing output to: " << outputPointCloudFilename_ << "\n";
+}
+
+void Georef::createGeoreferencedModel()
+{
+ if (useGCP_)
+ {
+ createGeoreferencedModelFromGCPData();
+ }
+ else
+ {
+ createGeoreferencedModelFromExifData();
+ }
+}
+
+void Georef::readCameras()
+{
+ // Read translations from bundle file
+ std::ifstream bundleStream(bundleFilename_.c_str());
+ if (!bundleStream.good())
+ {
+ throw GeorefException("Failed opening bundle file " + bundleFilename_ + " for reading." + '\n');
+ }
+
+ // Read Cameras.
+ std::string bundleLine;
+ std::getline(bundleStream, bundleLine); // Read past bundle version comment
+ int numCameras, numPoints;
+ bundleStream >> numCameras >> numPoints;
+ for (int i=0; i> imageName;
+ imageList_.push_back(imageName);
+ }
+
+ // Number of GCPs read
+ size_t nrGCPs = 0;
+
+ std::ifstream gcpStream(gcpFilename_.c_str());
+ if (!gcpStream.good())
+ {
+ throw GeorefException("Failed opening gcp file " + gcpFilename_ + " for reading.\n");
+ }
+ std::string gcpString;
+
+ // Read the first line in the file as the format of the projected coordinates
+ std::getline(gcpStream, georefSystem_.system_);
+
+ log_ << '\n';
+ log_<< "Reading following GCPs from file:\n";
+
+ // Read all GCPs
+ while(std::getline(gcpStream, gcpString))
+ {
+ std::istringstream istr(gcpString);
+ GeorefGCP gcp;
+ gcp.extractGCP(istr);
+ gcps_.push_back(gcp);
+ ++nrGCPs;
+
+ log_<<"x_: "<(gcps_.size());
+ northingOffset += (gcps_[gcpIndex].y_)/static_cast(gcps_.size());
+ }
+
+ georefSystem_.eastingOffset_ = static_cast(std::floor(eastingOffset));
+ georefSystem_.northingOffset_ = static_cast(std::floor(northingOffset));
+
+ log_ << '\n';
+ log_<<"The calculated easting offset for the georeferenced system: "<(georefSystem_.eastingOffset_);
+ gcps_[gcpIndex].y_ -= static_cast(georefSystem_.northingOffset_);
+ log_<<"x_: "<::Ptr meshCloud (new pcl::PointCloud);
+ pcl::fromPCLPointCloud2 (mesh.cloud, *meshCloud);
+
+ // The number of GCP that is usable
+ int nrGCPUsable = 0;
+
+ for (size_t gcpIndex = 0; gcpIndex < gcps_.size(); ++gcpIndex)
+ {
+ // Bool to check if the GCP is intersecting any triangle
+ bool exists = false;
+
+ // Translate the GeoreferenceCamera to pcl-format in order to use pcl-functions
+ pcl::TextureMapping::Camera cam;
+ cam.focal_length = cameras_[gcps_[gcpIndex].cameraIndex_].focalLength_;
+ cam.pose = *(cameras_[gcps_[gcpIndex].cameraIndex_].pose_);
+ cam.texture_file = imagesLocation_ + '/' + gcps_[gcpIndex].image_;
+
+ cv::Mat image = cv::imread(cam.texture_file);
+ cam.height = static_cast(image.rows);
+ cam.width = static_cast(image.cols);
+
+ // The pixel position for the GCP in pcl-format in order to use pcl-functions
+ pcl::PointXY gcpPos;
+ gcpPos.x = static_cast(gcps_[gcpIndex].pixelX_);
+ gcpPos.y = static_cast(gcps_[gcpIndex].pixelY_);
+
+ // Move vertices in mesh into the camera coordinate system
+ pcl::PointCloud::Ptr cameraCloud (new pcl::PointCloud);
+ pcl::transformPointCloud (*meshCloud, *cameraCloud, cam.pose.inverse());
+
+ // The vertex indicies to be used in order to calculate the GCP in the models coordinates
+ size_t vert0Index = 0; size_t vert1Index = 0; size_t vert2Index = 0;
+
+ pcl::PointXY bestPixelPos0; pcl::PointXY bestPixelPos1; pcl::PointXY bestPixelPos2;
+
+ // The closest distance of a triangle to the camera
+ double bestDistance = std::numeric_limits::infinity();
+
+ // Loop through all submeshes in model
+ for (size_t meshIndex = 0; meshIndex < mesh.tex_polygons.size(); ++meshIndex)
+ {
+ // Loop through all faces in submesh and check if inside polygon
+ for (size_t faceIndex = 0; faceIndex < mesh.tex_polygons[meshIndex].size(); ++faceIndex)
+ {
+ // Variables for the vertices in face as projections in the camera plane
+ pcl::PointXY pixelPos0; pcl::PointXY pixelPos1; pcl::PointXY pixelPos2;
+ if (isFaceProjected(cam,
+ cameraCloud->points[mesh.tex_polygons[meshIndex][faceIndex].vertices[0]],
+ cameraCloud->points[mesh.tex_polygons[meshIndex][faceIndex].vertices[1]],
+ cameraCloud->points[mesh.tex_polygons[meshIndex][faceIndex].vertices[2]],
+ pixelPos0, pixelPos1, pixelPos2))
+ {
+ // If the pixel position of the GCP is inside the current triangle
+ if (checkPointInsideTriangle(pixelPos0, pixelPos1, pixelPos2, gcpPos))
+ {
+ // Extract distances for all vertices for face to camera
+ double d0 = cameraCloud->points[mesh.tex_polygons[meshIndex][faceIndex].vertices[0]].z;
+ double d1 = cameraCloud->points[mesh.tex_polygons[meshIndex][faceIndex].vertices[1]].z;
+ double d2 = cameraCloud->points[mesh.tex_polygons[meshIndex][faceIndex].vertices[2]].z;
+
+ // Calculate largest distance and store in distance variable
+ double distance = std::max(d0, std::max(d1,d2));
+
+ // If the triangle is closer to the camera use this triangle
+ if (distance < bestDistance)
+ {
+ // Update variables for the closest polygon
+ bestDistance = distance;
+ vert0Index = mesh.tex_polygons[meshIndex][faceIndex].vertices[0];
+ vert1Index = mesh.tex_polygons[meshIndex][faceIndex].vertices[1];
+ vert2Index = mesh.tex_polygons[meshIndex][faceIndex].vertices[2];
+ bestPixelPos0 = pixelPos0;
+ bestPixelPos1 = pixelPos1;
+ bestPixelPos2 = pixelPos2;
+ exists = true;
+ ++nrGCPUsable;
+ }
+ }
+ }
+ }
+ }
+
+ if(exists)
+ {
+ // Shorthands for the vertices
+ pcl::PointXYZ v0 = meshCloud->points[vert0Index];
+ pcl::PointXYZ v1 = meshCloud->points[vert1Index];
+ pcl::PointXYZ v2 = meshCloud->points[vert2Index];
+ // Use barycentric coordinates to calculate position for the polygon intersection
+ pcl::PointXYZ gcpLocal = barycentricCoordinates(gcpPos, v0, v1, v2, bestPixelPos0, bestPixelPos1, bestPixelPos2);
+
+ log_ << "Position in model for gcp " << gcpIndex + 1<< ": x=" < transform;
+
+ transform(0, 0) = static_cast(transFinal.transform_.r1c1_);
+ transform(1, 0) = static_cast(transFinal.transform_.r2c1_);
+ transform(2, 0) = static_cast(transFinal.transform_.r3c1_);
+ transform(3, 0) = static_cast(transFinal.transform_.r4c1_);
+
+ transform(0, 1) = static_cast(transFinal.transform_.r1c2_);
+ transform(1, 1) = static_cast(transFinal.transform_.r2c2_);
+ transform(2, 1) = static_cast(transFinal.transform_.r3c2_);
+ transform(3, 1) = static_cast(transFinal.transform_.r4c2_);
+
+ transform(0, 2) = static_cast(transFinal.transform_.r1c3_);
+ transform(1, 2) = static_cast(transFinal.transform_.r2c3_);
+ transform(2, 2) = static_cast(transFinal.transform_.r3c3_);
+ transform(3, 2) = static_cast(transFinal.transform_.r4c3_);
+
+ transform(0, 3) = static_cast(transFinal.transform_.r1c4_);
+ transform(1, 3) = static_cast(transFinal.transform_.r2c4_);
+ transform(2, 3) = static_cast(transFinal.transform_.r3c4_);
+ transform(3, 3) = static_cast(transFinal.transform_.r4c4_);
+
+ log_ << '\n';
+ log_ << "Applying transform to mesh...\n";
+ // Move the mesh into position.
+ pcl::transformPointCloud(*meshCloud, *meshCloud, transform);
+ log_ << ".. mesh transformed.\n";
+
+ // Update the mesh.
+ pcl::toPCLPointCloud2 (*meshCloud, mesh.cloud);
+
+ // Iterate over each part of the mesh (one per material), to make texture file paths relative the .mtl file.
+ for(size_t t = 0; t < mesh.tex_materials.size(); ++t)
+ {
+ // The material of the current submesh.
+ pcl::TexMaterial& material = mesh.tex_materials[t];
+
+ size_t find = material.tex_file.find_last_of("/\\");
+ if(std::string::npos != find)
+ {
+ material.tex_file = material.tex_file.substr(find + 1);
+ }
+ }
+
+ log_ << '\n';
+ if (saveOBJFile(outputObjFilename_, mesh, 8) == -1)
+ {
+ throw GeorefException("Error when saving model:\n" + outputObjFilename_ + "\n");
+ }
+ else
+ {
+ log_ << "Successfully saved model.\n";
+ }
+
+ if(georeferencePointCloud_)
+ {
+ //pcl::PointCloud2::Ptr pointCloud;
+ pcl::PointCloud::Ptr pointCloud(new pcl::PointCloud());
+ if(pcl::io::loadPLYFile (inputPointCloudFilename_.c_str(), *pointCloud.get()) == -1) {
+ throw GeorefException("Error when reading point cloud:\n" + inputPointCloudFilename_ + "\n");
+ }
+ else
+ {
+ log_ << "Successfully loaded " << pointCloud->size() << " points with corresponding normals from file.\n";
+ }
+ log_ << '\n';
+ log_ << "Applying transform to point cloud...\n";
+ pcl::transformPointCloud(*pointCloud, *pointCloud, transform);
+ log_ << ".. point cloud transformed.\n";
+
+ pcl::PLYWriter plyWriter;
+
+ log_ << '\n';
+ log_ << "Saving point cloud file to \'" << outputPointCloudFilename_ << "\'...\n";
+ //pcl::io::savePLYFileASCII(outputPointCloudFilename_.c_str(), *pointCloud.get());
+ plyWriter.write(outputPointCloudFilename_.c_str(), *pointCloud.get(), false, false);
+ log_ << ".. point cloud file saved.\n";
+ }
+
+ if(exportCoordinateFile_)
+ {
+ log_ << '\n';
+ log_ << "Saving georeferenced camera positions to ";
+ log_ << outputCoordFilename_;
+ log_<< "\n";
+ std::ofstream coordStream(outputCoordFilename_.c_str());
+ coordStream << georefSystem_.system_ <(georefSystem_.eastingOffset_) << " " << static_cast(georefSystem_.northingOffset_) << std::endl;
+ for(size_t cameraIndex = 0; cameraIndex < cameras_.size(); ++cameraIndex)
+ {
+ Vec3 globalCameraPosition = (transFinal.transform_)*(cameras_[cameraIndex].getPos());
+ coordStream << globalCameraPosition.x_ << " " << globalCameraPosition.y_ << " " << globalCameraPosition.z_ << std::endl;
+ }
+ coordStream.close();
+ log_ << "...coordinate file saved.\n";
+ }
+
+ if(exportGeorefSystem_)
+ {
+ printGeorefSystem();
+ }
+}
+
+void Georef::createGeoreferencedModelFromGCPData()
+{
+ readCameras();
+
+ readGCPs();
+
+ calculateGCPOffset();
+
+ performGeoreferencingWithGCP();
+
+}
+
+void Georef::createGeoreferencedModelFromExifData()
+{
+ readCameras();
+
+ // Read coords from coord file generated by extract_utm tool
+ std::ifstream coordStream(inputCoordFilename_.c_str());
+ if (!coordStream.good())
+ {
+ throw GeorefException("Failed opening coordinate file " + inputCoordFilename_ + " for reading." + '\n');
+ }
+
+ std::string coordString;
+ std::getline(coordStream, georefSystem_.system_); // System
+ {
+ std::getline(coordStream, coordString);
+ std::stringstream ss(coordString);
+
+ ss >> georefSystem_.eastingOffset_ >> georefSystem_.northingOffset_;
+ }
+
+ log_ << '\n';
+ log_ << "Geographical reference system\n";
+ log_ << georefSystem_ << '\n';
+
+ // The number of cameras in the coords file.
+ size_t nGeorefCameras = 0;
+
+ // Read the georefernced position for all cameras.
+ while (std::getline(coordStream, coordString))
+ {
+ if(nGeorefCameras >= cameras_.size())
+ {
+ throw GeorefException("Error, to many cameras in \'" + inputCoordFilename_ + "\' coord file.\n");
+ }
+
+ std::istringstream istr(coordString);
+ cameras_[nGeorefCameras].extractCameraGeoref(istr);
+
+ ++nGeorefCameras;
+ }
+ coordStream.close();
+
+ if(nGeorefCameras < cameras_.size())
+ {
+ throw GeorefException("Not enough cameras in \'" + inputCoordFilename_ + "\' coord file.\n");
+ }
+
+ // Remove invalid cameras
+ std::vector goodCameras;
+ for (size_t i = 0; i < cameras_.size(); i++){
+ if (cameras_[i].isValid()) goodCameras.push_back(GeorefCamera(cameras_[i]));
+ }
+ cameras_.clear();
+ cameras_ = goodCameras;
+
+ // The optimal camera triplet.
+ size_t cam0, cam1, cam2;
+
+ log_ << '\n';
+ log_ << "Choosing optimal camera triplet...\n";
+ chooseBestCameraTriplet(cam0, cam1, cam2);
+ log_ << "... optimal camera triplet chosen:\n";
+ log_ << cam0 << ", " << cam1 << ", " << cam2 << '\n';
+ log_ << '\n';
+ FindTransform transFinal;
+ transFinal.findTransform(cameras_[cam0].getPos(), cameras_[cam1].getPos(), cameras_[cam2].getPos(),
+ cameras_[cam0].getReferencedPos(), cameras_[cam1].getReferencedPos(), cameras_[cam2].getReferencedPos());
+ log_ << "Final transform:\n";
+ log_ << transFinal.transform_ << '\n';
+
+ printFinalTransform(transFinal.transform_);
+
+ // The transform used to move the chosen area into the ortho photo.
+ Eigen::Transform transform;
+
+ transform(0, 0) = static_cast(transFinal.transform_.r1c1_); transform(1, 0) = static_cast(transFinal.transform_.r2c1_);
+ transform(2, 0) = static_cast(transFinal.transform_.r3c1_); transform(3, 0) = static_cast(transFinal.transform_.r4c1_);
+
+ transform(0, 1) = static_cast(transFinal.transform_.r1c2_); transform(1, 1) = static_cast(transFinal.transform_.r2c2_);
+ transform(2, 1) = static_cast(transFinal.transform_.r3c2_); transform(3, 1) = static_cast(transFinal.transform_.r4c2_);
+
+ transform(0, 2) = static_cast(transFinal.transform_.r1c3_); transform(1, 2) = static_cast(transFinal.transform_.r2c3_);
+ transform(2, 2) = static_cast(transFinal.transform_.r3c3_); transform(3, 2) = static_cast(transFinal.transform_.r4c3_);
+
+ transform(0, 3) = static_cast(transFinal.transform_.r1c4_); transform(1, 3) = static_cast