Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
fd847c5
Allow pixel masks to be input on a per image basis
Jan 11, 2017
4108cd7
Change to storing masks as images with data in first channel
Jan 24, 2017
09fce39
Tidying code
Jan 24, 2017
b5b9259
Add feature to treat images as video series and only match nearby frames
Jan 24, 2017
2203d04
Tidy up comment
Jan 24, 2017
ceacacc
Merge pull request #133 from BrookRoberts/order_neighbors
paulinus Jan 26, 2017
cca3886
Add sensor width for DJI Phantom 4.
winsento Feb 1, 2017
97bcaaf
Merge pull request #137 from winsento/master
paulinus Feb 4, 2017
bb91c69
Add option to plot matches between image subsets
paulinus Jan 24, 2017
0abbe04
Convert id to str when bundling with GPS
paulinus Jan 25, 2017
c4cbd49
Use bilinear interpolation to remap panoramas
paulinus Jan 25, 2017
5fc86b9
Prevent opencv3 imread from using EXIF orientation
paulinus Feb 4, 2017
06fe969
Add fisheye camera model
paulinus Feb 5, 2017
7fad29b
Handle fisheye io independently of perspective
paulinus Feb 5, 2017
25ad5e6
Bundle adjust fisheye cameras
paulinus Feb 5, 2017
52abc4a
Load masks from within the Dataset class
Feb 8, 2017
c1ed100
Switch to using 0 as the mask out value for per image masks
Feb 8, 2017
08eab36
Handle fisheye cameras on the viewer
paulinus Feb 9, 2017
310f75d
Fix writing partial reconstructions
paulinus Feb 9, 2017
3cc44ec
Fix writing partial reconstructions
paulinus Feb 9, 2017
62a4db0
Undistort fisheye images
paulinus Feb 9, 2017
88ceac3
Add failing fisheye projection test
paulinus Feb 9, 2017
b70e34c
Fix fisheye projection
paulinus Feb 9, 2017
13058fd
Fix viewer's fisheye projection
paulinus Feb 10, 2017
213adde
Fisheye cameras are of fisheye type 🙃
paulinus Feb 10, 2017
7333974
Convert fisheye to perspective cameras when undistorting
paulinus Feb 14, 2017
225d570
Fix name clash for masks in mask_and_normalize_features
Feb 14, 2017
7181f4b
Compute meshes for fisheyes
paulinus Feb 14, 2017
217b49e
Merge pull request #132 from BrookRoberts/masks
paulinus Feb 15, 2017
e894649
Convert masks to 2D arrays
paulinus Feb 15, 2017
c2c875e
Scale point coordinates to fit mask size
paulinus Feb 15, 2017
2dccb84
Name mask for image.jpg as image.jpg.png
paulinus Feb 15, 2017
663c930
Add image masks for berlin
paulinus Feb 15, 2017
7dc7e1a
Remove bounding box masks
paulinus Feb 15, 2017
b6ca14f
Minify reconstruction.meshed.py
Feb 16, 2017
8694fef
Catch missing OpenCV EXIF rotation option
paulinus Feb 16, 2017
bbc9fcc
Merge pull request #144 from BrookRoberts/minify
paulinus Feb 17, 2017
9dbb717
Update sensor_data.json
merkato Feb 27, 2017
c0e55c6
vlfeat: check HAS_CPUID before use of _vl_x86cpu_info_init
EmbeddedAndroid Feb 14, 2017
30116a0
cmake: VL_DISABLE_SSE2 when building on other architectures
EmbeddedAndroid Feb 14, 2017
29b6e3a
Merge pull request #147 from merkato/patch-1
paulinus Feb 28, 2017
9ddcdee
Merge pull request #148 from EmbeddedAndroid/arm-compilation-fixes
paulinus Feb 28, 2017
8ed1f36
Merge branch 'feature-fisheye'
paulinus Feb 28, 2017
752a9fb
Test fisheye only when using OpenCV 3
paulinus Mar 1, 2017
faad6d4
Use area interpolation for downsampling
paulinus Mar 8, 2017
41d174e
Format
paulinus Mar 8, 2017
f80cc8e
Remove log plots
paulinus Mar 8, 2017
979f14d
Add doc for GCP
paulinus Mar 16, 2017
abd1591
Run doc server at 8001
paulinus Mar 16, 2017
88bb967
added missing packages in setup.py and added a better named run_all f…
Mar 16, 2017
9ec5f1b
Merge branch 'master' of https://github.com/mapillary/OpenSfM
Mar 16, 2017
a25f080
Add doc on coordinate systems
paulinus Mar 20, 2017
d301856
Add pixel coordinates doc
paulinus Mar 20, 2017
7f084bc
Handle binary Akaze descriptors
paulinus Mar 24, 2017
d30b539
Compute flann index only when flann matching is selected
paulinus Mar 24, 2017
b4dab94
Merge pull request #151 from sinjax/master
paulinus Mar 24, 2017
ce0e3d8
Update documentation to use `virtualenv`
kachayev Mar 27, 2017
46a163a
Use ENV name for virtualenv not to mess up with OpenSfM bin files
kachayev Mar 28, 2017
ae6c0ec
Specify library versions in requirements file
kachayev Mar 28, 2017
1d44100
Do not specify versions for numpy & scipy to try to avoid problems on…
kachayev Mar 28, 2017
68dc4b8
Add scipy requirement
paulinus Mar 29, 2017
1f29ff1
Merge branch 'master' into patch-1
paulinus Mar 29, 2017
f642e49
Merge pull request #154 from kachayev/patch-1
paulinus Mar 29, 2017
7a0260d
Store and return best neighbor index.
oscarlorentzon Dec 4, 2016
12835bf
Fix pytest setup-cfg section name warning.
oscarlorentzon Nov 7, 2016
f31246d
Initialize with single random neighbor.
oscarlorentzon Dec 4, 2016
366e36c
Randomly sample neighbors.
oscarlorentzon Dec 4, 2016
7ec1034
Include headers for depth where used.
oscarlorentzon Mar 18, 2017
40c0118
Save neighbour matrix and list in dataset.
oscarlorentzon Mar 19, 2017
64b7a4e
Rename image plane check overload for clarity.
oscarlorentzon Mar 19, 2017
1fa98d9
Add script for plotting saved raw depthmaps.
oscarlorentzon Mar 19, 2017
e584deb
Rename neighbor variables.
oscarlorentzon Mar 30, 2017
8e341c4
Add method for running patch match with sampling.
oscarlorentzon Mar 30, 2017
ee7987d
Add config param for choosing depthmap algorithm.
oscarlorentzon Mar 30, 2017
89629ed
Use references instead of returning pair.
oscarlorentzon Mar 31, 2017
ddf710c
Throw if depthmap method is not supported.
oscarlorentzon Mar 31, 2017
9bd7e4a
Refactor pixel assignment to method.
oscarlorentzon Mar 31, 2017
079608d
Use pointers for return values.
oscarlorentzon Apr 4, 2017
24ee416
Catch division by zero when parsing EXIF
paulinus Apr 11, 2017
a01c0bb
Save features in the features folder.
paulinus Apr 12, 2017
fe5c5ff
Add commands description
paulinus Apr 19, 2017
77d21a4
Update openmvs Interface.h
paulinus May 14, 2017
0d87840
Open binary files in binary mode.
paulinus May 14, 2017
c230ce4
Remove old run_all (replaced by opensfm_run_all)
paulinus May 14, 2017
32dc83f
Better resolution fit when undistorting panoramas
paulinus May 15, 2017
abe41ac
Merge remote-tracking branch 'remotes/upstream/master' into HEAD
Jun 8, 2017
833f74c
Convert shot.id to string as required by bundle adjuster
Jun 8, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@ data/berlin/*
!data/berlin/images

eval

# Ignore virtualenv files
env/*
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ Install OpenCV using
brew install opencv
brew install homebrew/science/ceres-solver
brew install boost-python
sudo pip install -r requirements.txt

And install OpenGV using

Expand Down Expand Up @@ -63,6 +62,10 @@ When running OpenSfM on top of [OpenCV][] 3.0 the [OpenCV Contrib][] modules are

## Building

sudo pip install virtualenv
virtualenv env
source env/bin/activate
pip install -r requirements.txt
python setup.py build


Expand All @@ -72,7 +75,7 @@ An example dataset is available at `data/berlin`.

1. Put some images in `data/DATASET_NAME/images/`
2. Put config.yaml in `data/DATASET_NAME/config.yaml`
3. Go to the root of the project and run `bin/run_all data/DATASET_NAME`
3. Go to the root of the project and run `bin/opensfm_run_all data/DATASET_NAME`
4. Start an http server from the root with `python -m SimpleHTTPServer`
5. Browse `http://localhost:8000/viewer/reconstruction.html#file=/data/DATASET_NAME/reconstruction.meshed.json`.

Expand Down
File renamed without changes.
76 changes: 76 additions & 0 deletions bin/plot_depthmaps
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#!/usr/bin/env python

import argparse
import matplotlib.pyplot as pl
import numpy as np
from textwrap import wrap

from opensfm import dataset
from opensfm import io


def plot_depthmap(im, title, depth, plane, score, nghbr):
ax = pl.subplot2grid((2, 3), (0, 0), rowspan=2)
ax_title = ax.set_title(title)
ax_title.set_y(1.05)
pl.imshow(im)
ax = pl.subplot(2, 3, 2)
ax_title = ax.set_title("Depth")
ax_title.set_y(1.08)
pl.imshow(depth)
pl.colorbar()
ax = pl.subplot(2, 3, 3)
ax_title = ax.set_title("Score")
ax_title.set_y(1.08)
pl.imshow(score)
pl.colorbar()
ax = pl.subplot(2, 3, 5)
ax_title = ax.set_title("Neighbor")
ax_title.set_y(1.08)
pl.imshow(nghbr)
pl.colorbar()
ax = pl.subplot(2, 3, 6)
ax_title = ax.set_title("Plane normal")
ax_title.set_y(1.02)
pl.imshow(color_plane_normals(plane))


def color_plane_normals(plane):
l = np.linalg.norm(plane, axis=2)
normal = plane / l[..., np.newaxis]
normal[..., 1] *= -1 # Reverse Y because it points down
normal[..., 2] *= -1 # Reverse Z because standard colormap does so
return ((normal + 1) * 128).astype(np.uint8)


if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Compute reconstruction')
parser.add_argument('dataset',
help='path to the dataset to be processed')
parser.add_argument('--image',
help='name of the image to show')
parser.add_argument('--save-figs',
help='save figures istead of showing them',
action='store_true')
args = parser.parse_args()

data = dataset.DataSet(args.dataset)

images = [args.image] if args.image else data.images()
for image in images:
depth, plane, score, nghbr, nghbrs = data.load_raw_depthmap(image)

print "Plotting depthmap for {0}".format(image)
pl.close("all")
pl.figure(figsize=(30, 16), dpi=90, facecolor='w', edgecolor='k')
title = "Shot: " + image + "\n" + "\n".join(wrap("Neighbors: " + ', '.join(nghbrs), 80))
plot_depthmap(data.image_as_array(image), title, depth, plane, score, nghbr)
pl.tight_layout()

if args.save_figs:
p = args.dataset + '/plot_depthmaps'
io.mkdir_p(p)
pl.savefig(p + '/' + image + '.png')
pl.close()
else:
pl.show()
66 changes: 35 additions & 31 deletions bin/plot_matches
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env python

import argparse
from itertools import combinations

import matplotlib.pyplot as pl
import networkx as nx
Expand Down Expand Up @@ -33,7 +34,9 @@ if __name__ == "__main__":
parser.add_argument('dataset',
help='path to the dataset to be processed')
parser.add_argument('--image',
help='name of the image to show')
help='show tracks for a specific')
parser.add_argument('--images',
help='show tracks between a subset of images (separated by commas)')
parser.add_argument('--graph',
help='display image graph',
action='store_true')
Expand Down Expand Up @@ -65,39 +68,40 @@ if __name__ == "__main__":
else:
# Plot matches between images
if args.image:
toplot = [args.image]
pairs = [(args.image, o) for o in images if o != args.image]
elif args.images:
subset = args.images.split(',')
pairs = combinations(subset, 2)
else:
toplot = images
pairs = combinations(images, 2)

i = 0
for im1 in toplot:
for im2 in images:
if im1 != im2:
matches = data.find_matches(im1, im2)
if len(matches) == 0:
continue
print 'plotting matches between', im1, im2

p1, f1, c1 = data.load_features(im1)
p2, f2, c2 = data.load_features(im2)
p1 = p1[matches[:, 0]]
p2 = p2[matches[:, 1]]

pl.figure(figsize=(20, 10))
pl.title('Images: ' + im1 + ' - ' + im2 + ', matches: ' +
str(matches.shape[0]))
plot_matches(data.image_as_array(im1),
data.image_as_array(im2), p1, p2)
i += 1
if args.save_figs:
p = args.dataset + '/plot_tracks'
io.mkdir_p(p)
pl.savefig(p + '/' + im1 + '_' + im2 + '.jpg', dpi=100)
pl.close()
else:
if i >= 10:
i = 0
pl.show()
for im1, im2 in pairs:
matches = data.find_matches(im1, im2)
if len(matches) == 0:
continue
print 'plotting matches between', im1, im2

p1, f1, c1 = data.load_features(im1)
p2, f2, c2 = data.load_features(im2)
p1 = p1[matches[:, 0]]
p2 = p2[matches[:, 1]]

pl.figure(figsize=(20, 10))
pl.title('Images: ' + im1 + ' - ' + im2 + ', matches: ' +
str(matches.shape[0]))
plot_matches(data.image_as_array(im1),
data.image_as_array(im2), p1, p2)
i += 1
if args.save_figs:
p = args.dataset + '/plot_tracks'
io.mkdir_p(p)
pl.savefig(p + '/' + im1 + '_' + im2 + '.jpg', dpi=100)
pl.close()
else:
if i >= 10:
i = 0
pl.show()

if not args.save_figs and i > 0:
pl.show()
55 changes: 30 additions & 25 deletions bin/plot_tracks
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#!/usr/bin/env python

import argparse
from itertools import combinations

import matplotlib.pyplot as pl
import networkx as nx
import numpy as np
Expand Down Expand Up @@ -30,11 +32,13 @@ def plot_matches(im1, im2, p1, p2):


if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Compute reconstruction')
parser = argparse.ArgumentParser(description='Plot tracks')
parser.add_argument('dataset',
help='path to the dataset to be processed')
parser.add_argument('--image',
help='name of the image to show')
help='show tracks for a specific')
parser.add_argument('--images',
help='show tracks between a subset of images (separated by commas)')
parser.add_argument('--graph',
help='display image graph',
action='store_true')
Expand All @@ -60,32 +64,33 @@ if __name__ == "__main__":
else:
# Plot matches between images
if args.image:
toplot = [args.image]
pairs = [(args.image, o) for o in images if o != args.image]
elif args.images:
subset = args.images.split(',')
pairs = combinations(subset, 2)
else:
toplot = images
pairs = combinations(images, 2)

i = 0
for im1 in toplot:
for im2 in images:
if im1 != im2:
t, p1, p2 = matching.common_tracks(graph, im1, im2)
if len(t) >= 10:
pl.figure(figsize=(20, 10))
pl.title('Images: ' + im1 + ' - ' + im2 +
', matches: ' + str(len(t)))
plot_matches(data.image_as_array(im1),
data.image_as_array(im2), p1, p2)
i += 1
if args.save_figs:
p = args.dataset + '/plot_tracks'
io.mkdir_p(p)
pl.savefig(p + '/' + im1 + '_' + im2 + '.jpg',
dpi=100)
pl.close()
else:
if i >= 10:
i = 0
pl.show()
for im1, im2 in pairs:
t, p1, p2 = matching.common_tracks(graph, im1, im2)
if len(t) >= 10:
pl.figure(figsize=(20, 10))
pl.title('Images: ' + im1 + ' - ' + im2 +
', matches: ' + str(len(t)))
plot_matches(data.image_as_array(im1),
data.image_as_array(im2), p1, p2)
i += 1
if args.save_figs:
p = args.dataset + '/plot_tracks'
io.mkdir_p(p)
pl.savefig(p + '/' + im1 + '_' + im2 + '.jpg',
dpi=100)
pl.close()
else:
if i >= 10:
i = 0
pl.show()

if not args.save_figs and i > 0:
pl.show()
2 changes: 1 addition & 1 deletion bin/run_eval
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ from opensfm import types

def run_dataset(run_root, name):
folder = run_root + '/' + name
call(['bin/run_all', folder])
call(['bin/opensfm_run_all', folder])

with open(run_root + '/index.html', 'a') as fout:
s = '''
Expand Down
4 changes: 0 additions & 4 deletions config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,6 @@ akaze_descriptor_channels: 3 # Number of feature channels (1,2,3)
hahog_peak_threshold: 0.00001
hahog_edge_threshold: 10

# Masks for regions that will be ignored for feature extraction
# List of bounding boxes specified as the ratio to image width and height
# masks: [{top: 0.96, bottom: 1.0, left: 0.0, right: 0.15}, {top: 0.95, bottom: 1.0, left: 0, right: 0.05}]

# Params for general matching
lowes_ratio: 0.8 # Ratio test for matches
preemptive_lowes_ratio: 0.6 # Ratio test for preemptive matches
Expand Down
1 change: 1 addition & 0 deletions data/berlin/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
processes: 8 # Number of threads to use
depthmap_min_consistent_views: 2 # Min number of views that should reconstruct a point for it to be valid
depthmap_save_debug_files: yes # Save debug files with partial reconstruction results
feature_process_size: 1024
Binary file added data/berlin/masks/01.jpg.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added data/berlin/masks/02.jpg.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added data/berlin/masks/03.jpg.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion doc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ html:
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."

livehtml: html
sphinx-autobuild -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
sphinx-autobuild -b html -p 8001 $(ALLSPHINXOPTS) $(BUILDDIR)/html

dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
Expand Down
2 changes: 1 addition & 1 deletion doc/source/_static/mathjax_conf.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MathJax.Hub.Config({
"HTML-CSS": {
availableFonts: ["TeX"],
scale: 90
scale: 100
}
});
9 changes: 9 additions & 0 deletions doc/source/building.rst
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,12 @@ When running OpenSfM on top of OpenCV version 3.0 the `OpenCV Contrib`_ modules
.. _Ceres solver: http://ceres-solver.org/
.. _Boost Python: http://www.boost.org/
.. _Networkx: https://github.com/networkx/networkx


Building the documentation
--------------------------
To build the documentation and browse it locally use
::
cd doc
make livehtml
and browse `http://localhost:8001/ <http://localhost:8001/>`_
6 changes: 3 additions & 3 deletions doc/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,17 @@

# General information about the project.
project = u'OpenSfM'
copyright = u'2016, Mapillary'
copyright = u'2017, Mapillary'
author = u'Mapillary'

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = u'0.0'
version = u'0.1'
# The full version, including alpha/beta/rc tags.
release = u'0.0.0'
release = u'0.1.0'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down
19 changes: 18 additions & 1 deletion doc/source/dataset.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,21 @@
Dataset Structure
=================

TODO
::

project/
├── config.yaml
├── images/
├── masks/
├── gcp_list.txt
├── metadata/
├── features/
├── matches/
├── tracks.tsv
├── reconstruction.json
├── reconstruction.meshed.json
├── undistorted/
├── undistorted_tracks.json
├── undistorted_reconstruction.json
└── depthmaps/
└── merged.ply
2 changes: 1 addition & 1 deletion doc/source/dense.rst
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ And the linear approximation around :math:`(x_0, y_0)` is
Undistortion
------------

The dense module assumes that images are taken with perspective projection and no radial distortion. For perspective images, undistorted versions can be generated by taking into account the computed distortion parameters, :math:`k1` and :math: `k2`.
The dense module assumes that images are taken with perspective projection and no radial distortion. For perspective images, undistorted versions can be generated by taking into account the computed distortion parameters, :math:`k1` and :math:`k2`.

Equirectangular images (360 panoramas) however can not be unwarped into a single persepective view. We need to generate multiple perspective views to cover the field of view of a panorama.

Expand Down
Loading