diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 000000000..515de1d89
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,44 @@
+FROM ubuntu:20.04
+
+WORKDIR /app
+ENV preset=2
+ENV mode=1
+ENV nolog=0
+ENV reverse=0
+ENV nomt=1
+ENV speed=0
+ENV nogui=1
+ENV DEBIAN_FRONTEND noninteractive
+RUN apt-get update && \
+ apt install -y git
+RUN git clone https://github.com/IldarGreat/dso.git
+RUN apt-get install -y build-essential \
+ libsuitesparse-dev libeigen3-dev libboost-all-dev \
+ libopencv-dev
+
+WORKDIR /app
+RUN git clone --recursive https://github.com/stevenlovegrove/Pangolin.git -b v0.6
+WORKDIR /app/Pangolin
+RUN apt-get install -y cmake && \
+ apt-get clean && \
+ apt install -y libglew-dev && \
+ apt-get install -y libegl1-mesa-dev
+
+RUN cmake -B build && \
+ cmake --build build
+
+RUN apt-get install -y zlib1g-dev
+WORKDIR /app/dso/thirdparty/
+RUN tar -zxvf libzip-1.1.1.tar.gz
+WORKDIR /app/dso/thirdparty/libzip-1.1.1/
+RUN ./configure && \
+ make && \
+ cp lib/zipconf.h /usr/local/include/zipconf.h
+
+RUN git submodule update --init
+
+WORKDIR /app/dso/build
+RUN cmake .. && \
+ make
+
+ENTRYPOINT ./bin/dso_dataset files=set/sequence calib=set/camera.txt mode=${mode} preset=${preset} nolog=${nolog} reverse=${reverse} nomt=${nomt} speed=${speed} nogui=${nogui}
diff --git a/README.md b/README.md
index 50a9f5952..e2234ebae 100644
--- a/README.md
+++ b/README.md
@@ -8,12 +8,32 @@ For more information see
* **A Photometrically Calibrated Benchmark For Monocular Visual Odometry**, *J. Engel, V. Usenko, D. Cremers*, In arXiv:1607.02555, 2016
Get some datasets from [https://vision.in.tum.de/mono-dataset](https://vision.in.tum.de/mono-dataset) .
-
-### 2. Installation
-
- git clone https://github.com/JakobEngel/dso.git
-
-#### 2.1 Required Dependencies
+### 2. Installation with docker
+
+#### 2.1 Get image
+##### Build image from Dockerfile.
+ git clone https://github.com/IldarGreat/dso.git
+ docker build . -t ildarthegreat/dso
+##### Or pull image from dockerhub
+ docker pull ildarthegreat/dso
+##### If you have arm based system
+ docker pull ildarthegreat/dsoarm64
+#### 2.2 Run container
+ docker run \
+ -v {path}:/app/dso/build/set \
+ -e mode=2 \
+ ... other environment (see Dockerfile)
+ ildarthegreat/dso (or ildarthegreat/dsoarm64)
+path - it's folder that contains the calib file camera.txt and another folder named sequence that contains a sequence of images
+Example: .../path
+ -camera.txt
+ -sequence
+
+### 3. Installation from source code
+
+ git clone https://github.com/IldarGreat/dso.git
+
+#### 3.1 Required Dependencies
##### suitesparse and eigen3 (required).
Required. Install with
@@ -22,7 +42,7 @@ Required. Install with
-#### 2.2 Optional Dependencies
+#### 3.2 Optional Dependencies
##### OpenCV (highly recommended).
Used to read / write / display images.
@@ -37,7 +57,7 @@ Install with
sudo apt-get install libopencv-dev
-##### Pangolin (highly recommended).
+##### Pangolin v0.4! (highly recommended).
Used for 3D visualization & the GUI.
Pangolin is **only** used in `IOWrapper/Pangolin/*`. You can compile without Pangolin,
however then there is not going to be any visualization / GUI capability.
@@ -46,6 +66,16 @@ and use it instead of `PangolinDSOViewer`
Install from [https://github.com/stevenlovegrove/Pangolin](https://github.com/stevenlovegrove/Pangolin)
+Or install like bellow
+
+ git clone --recursive https://github.com/stevenlovegrove/Pangolin.git -b v0.6
+ apt-get clean
+ sudo apt install libglew-dev
+ sudo apt-get install libegl1-mesa-dev
+ cd Pangolin
+ cmake -B build
+ cmake --build build
+
##### ziplib (recommended).
Used to read datasets with images as .zip, as e.g. in the TUM monoVO dataset.
@@ -64,7 +94,7 @@ to unzip the dataset image archives before loading them).
##### sse2neon (required for ARM builds).
After cloning, just run `git submodule update --init` to include this. It translates Intel-native SSE functions to ARM-native NEON functions during the compilation process.
-#### 2.3 Build
+#### 3.3 Build
cd dso
mkdir build
@@ -76,12 +106,12 @@ this will compile a library `libdso.a`, which can be linked from external projec
It will also build a binary `dso_dataset`, to run DSO on datasets. However, for this
OpenCV and Pangolin need to be installed.
+If you have error with boost, please add #include to IndexThreadReduce
-
-### 3 Usage
+### 4 Usage
Run on a dataset from [https://vision.in.tum.de/mono-dataset](https://vision.in.tum.de/mono-dataset) using
bin/dso_dataset \
@@ -98,17 +128,17 @@ other camera drivers, to use DSO interactively without ROS.
-#### 3.1 Dataset Format.
+#### 4.1 Dataset Format.
The format assumed is that of [https://vision.in.tum.de/mono-dataset](https://vision.in.tum.de/mono-dataset).
However, it should be easy to adapt it to your needs, if required. The binary is run with:
-- `files=XXX` where XXX is either a folder or .zip archive containing images. They are sorted *alphabetically*. for .zip to work, need to comiple with ziplib support.
+- `files=XXX` where XXX is either a folder or .zip archive containing images. They are sorted *alphabetically*. for .zip to work, need to comiple with ziplib support. You can use video_to_images.py in utils folder to split video into images. For example python video_to_images.py -v "path to video" . It create a folder 'images' desired sequence of images
-- `gamma=XXX` where XXX is a gamma calibration file, containing a single row with 256 values, mapping [0..255] to the respective irradiance value, i.e. containing the *discretized inverse response function*. See TUM monoVO dataset for an example.
+- `gamma=XXX` where XXX is a gamma calibration file, containing a single row with 256 values, mapping [0..255] to the respective irradiance value, i.e. containing the *discretized inverse response function*. See TUM monoVO dataset for an example or read this https://github.com/tum-vision/online_photometric_calibration
- `vignette=XXX` where XXX is a monochrome 16bit or 8bit image containing the vignette as pixelwise attenuation factors. See TUM monoVO dataset for an example.
-- `calib=XXX` where XXX is a geometric camera calibration file. See below.
+- `calib=XXX` where XXX is a geometric camera calibration file. See below. If you want you can use calibration.py in utils it use chessboard 6*9, to check camera calibration settings. For example python calibration.py -i "path to images of chessboard"
@@ -117,14 +147,14 @@ However, it should be easy to adapt it to your needs, if required. The binary is
###### Calibration File for Pre-Rectified Images
- Pinhole fx fy cx cy 0
+ fx fy cx cy 0
in_width in_height
"crop" / "full" / "none" / "fx fy cx cy 0"
out_width out_height
###### Calibration File for FOV camera model:
- FOV fx fy cx cy omega
+ fx fy cx cy omega
in_width in_height
"crop" / "full" / "fx fy cx cy 0"
out_width out_height
@@ -132,7 +162,7 @@ However, it should be easy to adapt it to your needs, if required. The binary is
###### Calibration File for Radio-Tangential camera model
- RadTan fx fy cx cy k1 k2 r1 r2
+ fx fy cx cy k1 k2 r1 r2
in_width in_height
"crop" / "full" / "fx fy cx cy 0"
out_width out_height
@@ -140,7 +170,7 @@ However, it should be easy to adapt it to your needs, if required. The binary is
###### Calibration File for Equidistant camera model
- EquiDistant fx fy cx cy k1 k2 k3 k4
+ fx fy cx cy k1 k2 k3 k4
in_width in_height
"crop" / "full" / "fx fy cx cy 0"
out_width out_height
@@ -183,7 +213,7 @@ outliers along those borders, and corrupt the scale-pyramid).
-#### 3.2 Commandline Options
+#### 4.2 Commandline Options
there are many command line options available, see `main_dso_pangolin.cpp`. some examples include
- `mode=X`:
- `mode=0` use iff a photometric calibration exists (e.g. TUM monoVO dataset).
@@ -210,11 +240,11 @@ there are many command line options available, see `main_dso_pangolin.cpp`. some
-#### 3.3 Runtime Options
+#### 4.3 Runtime Options
Some parameters can be reconfigured from the Pangolin GUI at runtime. Feel free to add more.
-#### 3.4 Accessing Data.
+#### 4.4 Accessing Data.
The easiest way to access the Data (poses, pointclouds, etc.) computed by DSO (in real-time)
is to create your own `Output3DWrapper`, and add it to the system, i.e., to `FullSystem.outputWrapper`.
The respective member functions will be called on various occations (e.g., when a new KF is created,
@@ -233,7 +263,7 @@ using the TUM RGB-D / TUM monoVO format ([timestamp x y z qx qy qz qw] of the ca
-#### 3.5 Notes
+#### 4.5 Notes
- the initializer is very slow, and does not work very reliably. Maybe replace by your own way to get an initialization.
- see [https://github.com/JakobEngel/dso_ros](https://github.com/JakobEngel/dso_ros) for a minimal example project on how to use the library with your own input / output procedures.
- see `settings.cpp` for a LOT of settings parameters. Most of which you shouldn't touch.
@@ -242,7 +272,7 @@ using the TUM RGB-D / TUM monoVO format ([timestamp x y z qx qy qz qw] of the ca
-### 4 General Notes for Good Results
+### 5 General Notes for Good Results
#### Accurate Geometric Calibration
- Please have a look at Chapter 4.3 from the DSO paper, in particular Figure 20 (Geometric Noise). Direct approaches suffer a LOT from bad geometric calibrations: Geometric distortions of 1.5 pixel already reduce the accuracy by factor 10.
@@ -272,7 +302,7 @@ little rotation) during initialization.
Possibly replace by your own initializer.
-### 5 License
+### 6 License
DSO was developed at the Technical University of Munich and Intel.
The open-source version is licensed under the GNU General Public License
Version 3 (GPLv3).
diff --git a/builddso.bash b/builddso.bash
new file mode 100644
index 000000000..4d125d0d8
--- /dev/null
+++ b/builddso.bash
@@ -0,0 +1,20 @@
+sudo apt-get install -y libsuitesparse-dev libeigen3-dev libboost-all-dev libopencv-dev libglew-dev libegl1-mesa-dev cmake zlib1g-dev curl lsb-release
+user=ildar
+cd /home/$user
+mkdir app
+cd app
+git clone --recursive https://github.com/stevenlovegrove/Pangolin.git -b v0.6
+cd Pangolin
+mkdir build
+cd build
+cmake ..
+make
+
+cd /home/$user/app
+git clone https://github.com/IldarGreat/dso.git
+cd dso
+git submodule update --init
+mkdir build
+cd build
+cmake ..
+make
diff --git a/src/IOWrapper/OpenCV/ImageRW_OpenCV.cpp b/src/IOWrapper/OpenCV/ImageRW_OpenCV.cpp
index 170cb33ce..685eb7288 100644
--- a/src/IOWrapper/OpenCV/ImageRW_OpenCV.cpp
+++ b/src/IOWrapper/OpenCV/ImageRW_OpenCV.cpp
@@ -34,7 +34,7 @@ namespace IOWrap
{
MinimalImageB* readImageBW_8U(std::string filename)
{
- cv::Mat m = cv::imread(filename, CV_LOAD_IMAGE_GRAYSCALE);
+ cv::Mat m = cv::imread(filename, cv::IMREAD_GRAYSCALE);
if(m.rows*m.cols==0)
{
printf("cv::imread could not read image %s! this may segfault. \n", filename.c_str());
@@ -52,7 +52,7 @@ MinimalImageB* readImageBW_8U(std::string filename)
MinimalImageB3* readImageRGB_8U(std::string filename)
{
- cv::Mat m = cv::imread(filename, CV_LOAD_IMAGE_COLOR);
+ cv::Mat m = cv::imread(filename, cv::IMREAD_COLOR);
if(m.rows*m.cols==0)
{
printf("cv::imread could not read image %s! this may segfault. \n", filename.c_str());
@@ -70,7 +70,7 @@ MinimalImageB3* readImageRGB_8U(std::string filename)
MinimalImage* readImageBW_16U(std::string filename)
{
- cv::Mat m = cv::imread(filename, CV_LOAD_IMAGE_UNCHANGED);
+ cv::Mat m = cv::imread(filename, cv::IMREAD_UNCHANGED);
if(m.rows*m.cols==0)
{
printf("cv::imread could not read image %s! this may segfault. \n", filename.c_str());
@@ -88,7 +88,7 @@ MinimalImage* readImageBW_16U(std::string filename)
MinimalImageB* readStreamBW_8U(char* data, int numBytes)
{
- cv::Mat m = cv::imdecode(cv::Mat(numBytes,1,CV_8U, data), CV_LOAD_IMAGE_GRAYSCALE);
+ cv::Mat m = cv::imdecode(cv::Mat(numBytes,1,CV_8U, data), cv::IMREAD_GRAYSCALE);
if(m.rows*m.cols==0)
{
printf("cv::imdecode could not read stream (%d bytes)! this may segfault. \n", numBytes);
diff --git a/utils/calibration.py b/utils/calibration.py
new file mode 100644
index 000000000..09805f4b7
--- /dev/null
+++ b/utils/calibration.py
@@ -0,0 +1,63 @@
+import cv2
+import numpy as np
+import os
+import glob
+import argparse
+
+ap = argparse.ArgumentParser()
+ap.add_argument("-i", "--images", required=True, help="path to input images")
+args = vars(ap.parse_args())
+
+# Определение размеров шахматной доски
+CHECKERBOARD = (6,9)
+criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
+# Создание вектора для хранения векторов трехмерных точек для каждого изображения шахматной доски
+objpoints = []
+# Создание вектора для хранения векторов 2D точек для каждого изображения шахматной доски
+imgpoints = []
+# Определение мировых координат для 3D точек
+objp = np.zeros((1, CHECKERBOARD[0] * CHECKERBOARD[1], 3), np.float32)
+objp[0,:,:2] = np.mgrid[0:CHECKERBOARD[0], 0:CHECKERBOARD[1]].T.reshape(-1, 2)
+prev_img_shape = None
+# Извлечение пути отдельного изображения, хранящегося в данном каталоге
+images = glob.glob(args["images"]+'/*.jpg')
+for fname in images:
+ img = cv2.imread(fname)
+ gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
+ # Найти углы шахматной доски
+ # Если на изображении найдено нужное количество углов, тогда ret = true
+ ret, corners = cv2.findChessboardCorners(gray, CHECKERBOARD, cv2.CALIB_CB_ADAPTIVE_THRESH + cv2.CALIB_CB_FAST_CHECK + cv2.CALIB_CB_NORMALIZE_IMAGE)
+
+ """
+ Если желаемый номер угла обнаружен,
+ уточняем координаты пикселей и отображаем
+ их на изображениях шахматной доски
+ """
+ if ret == True:
+ objpoints.append(objp)
+ # уточнение координат пикселей для заданных 2d точек.
+ corners2 = cv2.cornerSubPix(gray, corners, (11,11),(-1,-1), criteria)
+
+ imgpoints.append(corners2)
+ # Нарисовать и отобразить углы
+ img = cv2.drawChessboardCorners(img, CHECKERBOARD, corners2, ret)
+
+ cv2.imshow('img',img)
+ cv2.waitKey(0)
+cv2.destroyAllWindows()
+h,w = img.shape[:2]
+"""
+Выполнение калибровки камеры с помощью
+Передача значения известных трехмерных точек (объектов)
+и соответствующие пиксельные координаты
+обнаруженные углы (imgpoints)
+"""
+ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
+print("Camera matrix : \n")
+print(mtx)
+print("dist : \n")
+print(dist)
+print("rvecs : \n")
+print(rvecs)
+print("tvecs : \n")
+print(tvecs)
\ No newline at end of file
diff --git a/utils/chessboard.png b/utils/chessboard.png
new file mode 100644
index 000000000..630a0ba2b
Binary files /dev/null and b/utils/chessboard.png differ
diff --git a/utils/video_to_images.py b/utils/video_to_images.py
new file mode 100644
index 000000000..fae712e49
--- /dev/null
+++ b/utils/video_to_images.py
@@ -0,0 +1,50 @@
+import cv2
+import numpy as np
+import os
+import argparse
+
+ap = argparse.ArgumentParser()
+ap.add_argument("-v", "--video", required=True, help="path to input video")
+args = vars(ap.parse_args())
+
+# Playing video from file:
+cap = cv2.VideoCapture(args["video"])
+
+try:
+ if not os.path.exists('images'):
+ os.makedirs('images')
+except OSError:
+ print ('Error: Creating directory of data')
+
+currentFrame = 0
+rightFrameName = '0000' + str(currentFrame)
+while(True):
+ # Capture frame-by-frame
+ ret, frame = cap.read()
+ if frame is None:
+ break
+ grayFrame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
+ # Saves image of the current frame in jpg file
+ if currentFrame < 10:
+ rightFrameName = rightFrameName[:-1]
+ rightFrameName = '0000' + str(currentFrame)
+ if currentFrame >= 10 and currentFrame < 100 :
+ rightFrameName = rightFrameName[:-2]
+ rightFrameName = rightFrameName + str(currentFrame)
+ if currentFrame >= 100 and currentFrame < 1000:
+ rightFrameName = rightFrameName[:-3]
+ rightFrameName = rightFrameName + str(currentFrame)
+ if currentFrame >= 1000:
+ rightFrameName = rightFrameName[:-4]
+ rightFrameName = rightFrameName + str(currentFrame)
+ name = './images/' + rightFrameName + '.jpg'
+ print ('Creating...' + name,end="\r")
+ cv2.imwrite(name, grayFrame)
+
+ # To stop duplicate images
+ currentFrame += 1
+
+# When everything done, release the capture
+print('\nDone!')
+cap.release()
+cv2.destroyAllWindows()
\ No newline at end of file