Skip to content

Commit

Permalink
Dockerfile with example cpp to reconstruct 3D points from multiple 2D…
Browse files Browse the repository at this point in the history
… images
  • Loading branch information
alyssaq authored and Alyssa Quek committed Nov 16, 2016
0 parents commit aed6c4c
Show file tree
Hide file tree
Showing 4 changed files with 240 additions and 0 deletions.
93 changes: 93 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
FROM python:3.5
MAINTAINER Alyssa Quek

# Common libs and for OpenCV
RUN apt-get update && \
apt-get install -y \
build-essential \
cmake \
git \
wget \
unzip \
yasm \
vim \
ninja-build \
pkg-config \
libswscale-dev \
libtbb2 \
libtbb-dev \
libjpeg-dev \
libpng-dev \
libtiff-dev \
libjasper-dev \
libavformat-dev \
libpq-dev \
libeigen3-dev

# SFM dependencies: google-glog + gflags, blas + lapack, suitespare, VTK (viz toolkit)
RUN apt-get install -y \
libgoogle-glog-dev \
libatlas-base-dev \
libsuitesparse-dev \
libvtk5-dev \
python-vtk \
libgtk2.0-dev \
libqt4-dev

RUN pip install --upgrade pip && pip install numpy

# Install Ceres Solver
WORKDIR /
RUN git clone https://ceres-solver.googlesource.com/ceres-solver \
&& cd ceres-solver \
&& mkdir build && cd build \
&& cmake -G Ninja .. \
&& ninja -j4 \
&& ninja install \
&& ldconfig

ENV PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:/usr/local/share/pkgconfig:/usr/lib/pkgconfig
# Include eigen into C++ build include
ENV CPLUS_INCLUDE_PATH=$CPLUS_INCLUDE_PATH:/usr/include/eigen3/:/usr/local/include/opencv:/usr/local/include/opencv2
ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib

WORKDIR /

# Force HAVE_EIGEN and GFLAGS_FOUND to TRUE as cmake does not seem to set those flags correctly
RUN cv_version=master \
&& wget https://github.com/opencv/opencv/archive/"$cv_version".zip -O opencv.zip \
&& unzip opencv.zip \
&& wget https://github.com/opencv/opencv_contrib/archive/"$cv_version".zip -O opencv_contrib.zip \
&& unzip opencv_contrib \
&& mkdir /opencv-"$cv_version"/cmake_binary \
&& cd /opencv-"$cv_version"/cmake_binary \
&& cmake -G Ninja \
-DOPENCV_EXTRA_MODULES_PATH=/opencv_contrib-"$cv_version"/modules \
-DHAVE_EIGEN=TRUE -DGFLAGS_FOUND=TRUE \
-DBUILD_TIFF=ON \
-DENABLE_AVX=ON \
-DWITH_OPENGL=ON \
-DWITH_OPENCL=ON \
-DWITH_IPP=ON \
-DWITH_TBB=ON \
-DWITH_EIGEN=ON \
-DWITH_VTK=ON \
-DWITH_V4L=ON \
-DBUILD_EXAMPLES=ON \
-DINSTALL_C_EXAMPLES=ON \
-DINSTALL_PYTHON_EXAMPLES=ON \
-DBUILD_TESTS=OFF \
-DBUILD_PERF_TESTS=OFF \
-DCMAKE_BUILD_TYPE=RELEASE \
-DCMAKE_INSTALL_PREFIX=$(python3.5 -c "import sys; print(sys.prefix)") \
-DPYTHON_EXECUTABLE=$(which python3.5) \
-DPYTHON_INCLUDE_DIR=$(python3.5 -c "from distutils.sysconfig import get_python_inc; print(get_python_inc())") \
-DPYTHON_PACKAGES_PATH=$(python3.5 -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())") .. \
&& ninja -j4 install \
&& rm /opencv.zip \
&& rm /opencv_contrib.zip

RUN pip install -r requirements.txt

# Define default command
CMD ["bash"]
41 changes: 41 additions & 0 deletions README
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# 3D reconstruction from multiple 2D images

The current structure from motion (SFM) module only runs in Linux.
As such, I used [docker](https://www.docker.com) on my Mac to reconstruct the 3D points.

## Docker Dev Environment
```sh
# Build the docker image
docker build -t python-opencv .
# Run the docker container mounting `reconstruction` folder to `/app`
docker run -it -v <path_to_reconstruction_folder>:/app python-opencv /bin/bash
```

## Run
1) Download 2D temple images from <http://vision.middlebury.edu/mview/data>
2) Save list of images to `images.txt`:
```sh
# images.txt will contain lines of filepath
# /app/temple/temple0302.png
ls temple/*.png > images.txt
sed -i -e 's/^/\/app\//' images.txt
```
3) In the docker container, compile the cpp file
```
g++ example_sfm.cpp -L/usr/local/lib/ -lopencv_core -lopencv_sfm -lopencv_viz
```
4) Run the example with the list of images
```
./a.out images.txt 350 240 360
```

## Test
```sh
# Test eigen
g++ -I /usr/local/Cellar/eigen/3.2.10/include/eigen3/ eigen_test.cpp -o eigen
./a.out


# Test with full includes
g++ example_sfm.cpp -I /usr/include/eigen3/ -I/usr/local/include/opencv -I/usr/local/include/opencv2 -L /usr/local/share/OpenCV/3rdparty/lib/ -L/usr/local/lib/ -L /usr/include/eigen3/ -lopencv_core -lopencv_imgproc -lopencv_highgui -lopencv_ml -lopencv_optflow -lopencv_sfm -lopencv_viz
```
100 changes: 100 additions & 0 deletions example_sfm.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#define CERES_FOUND true

#include <opencv2/sfm.hpp>
#include <opencv2/viz.hpp>
#include <opencv2/calib3d.hpp>
#include <opencv2/core.hpp>
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
using namespace std;
using namespace cv;
using namespace cv::sfm;

static void help() {
cout
<< "\n------------------------------------------------------------------------------------\n"
<< " This program shows the multiview reconstruction capabilities in the \n"
<< " OpenCV Structure From Motion (SFM) module.\n"
<< " It reconstruct a scene from a set of 2D images \n"
<< " Usage:\n"
<< " example_sfm_scene_reconstruction <path_to_file> <f> <cx> <cy>\n"
<< " where: path_to_file is the file absolute path into your system which contains\n"
<< " the list of images to use for reconstruction. \n"
<< " f is the focal lenght in pixels. \n"
<< " cx is the image principal point x coordinates in pixels. \n"
<< " cy is the image principal point y coordinates in pixels. \n"
<< "------------------------------------------------------------------------------------\n\n"
<< endl;
}
int getdir(const string _filename, vector<string> &files)
{
ifstream myfile(_filename.c_str());
if (!myfile.is_open()) {
cout << "Unable to read file: " << _filename << endl;
exit(0);
} else {;
size_t found = _filename.find_last_of("/\\");
string line_str, path_to_file = _filename.substr(0, found);
while ( getline(myfile, line_str) ) {
cout << line_str << endl;
files.push_back(line_str);
}
}
return 1;
}
int main(int argc, char* argv[])
{
// Read input parameters
if ( argc != 5 )
{
help();
exit(0);
}
// Parse the image paths
vector<string> images_paths;
getdir( argv[1], images_paths );
// Build instrinsics
float f = atof(argv[2]),
cx = atof(argv[3]), cy = atof(argv[4]);
Matx33d K = Matx33d( f, 0, cx,
0, f, cy,
0, 0, 1);
bool is_projective = true;
vector<Mat> Rs_est, ts_est, points3d_estimated;
sfm::reconstruct(images_paths, Rs_est, ts_est, K, points3d_estimated, is_projective);

// Print output
cout << "\n----------------------------\n" << endl;
cout << "Reconstruction: " << endl;
cout << "============================" << endl;
cout << "Estimated 3D points: " << points3d_estimated.size() << endl;
cout << "Estimated cameras: " << Rs_est.size() << endl;
cout << "Refined intrinsics: " << endl << K << endl << endl;
cout << "3D Visualization: " << endl;
cout << "============================" << endl;
viz::Viz3d window("Coordinate Frame");
window.setWindowSize(Size(500,500));
window.setWindowPosition(Point(150,150));
window.setBackgroundColor(); // black by default
// Create the pointcloud
cout << "Recovering points ... ";

// recover estimated points3d
ofstream points_file;
cv::MatIterator_<double> mat_it;
points_file.open("points.txt");
points_file.precision(std::numeric_limits<double>::digits10);
for (int i = 0; i < points3d_estimated.size(); ++i) {
std::cout << points3d_estimated[i] << std::endl;
for(mat_it = points3d_estimated[i].begin<double>(); mat_it != points3d_estimated[i].end<double>(); mat_it++){
points_file << *mat_it << " ";
}
points_file << "\n";
}
cout << "Done. Points saved to points.txt" << endl;
points_file.close();

return 0;
}
6 changes: 6 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
matplotlib
scipy
docopt
Pillow
future
ipython

0 comments on commit aed6c4c

Please sign in to comment.