-
Notifications
You must be signed in to change notification settings - Fork 852
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
573 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import logging | ||
import os | ||
|
||
import cv2 | ||
import numpy as np | ||
|
||
from opensfm import csfm | ||
from opensfm import dataset | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
class Command: | ||
name = 'export_openmvs' | ||
help = "Export reconstruction to openMVS format" | ||
|
||
def add_arguments(self, parser): | ||
parser.add_argument('dataset', help='dataset to process') | ||
|
||
def run(self, args): | ||
data = dataset.DataSet(args.dataset) | ||
reconstructions = data.load_reconstruction() | ||
graph = data.load_tracks_graph() | ||
|
||
if reconstructions: | ||
self.undistort_images(reconstructions[0], data) | ||
self.export(reconstructions[0], graph, data) | ||
|
||
def export(self, reconstruction, graph, data): | ||
exporter = csfm.OpenMVSExporter() | ||
for camera in reconstruction.cameras.values(): | ||
if camera.projection_type == 'perspective': | ||
w, h = camera.width, camera.height | ||
K = np.array([ | ||
[camera.focal, 0, (w - 1.0) / 2 / max(w, h)], | ||
[0, camera.focal, (h - 1.0) / 2 / max(w, h)], | ||
[0, 0, 1], | ||
]) | ||
exporter.add_camera(str(camera.id), K) | ||
|
||
for shot in reconstruction.shots.values(): | ||
if shot.camera.projection_type == 'perspective': | ||
image_path = data._undistorted_image_file(shot.id) | ||
exporter.add_shot( | ||
str(os.path.abspath(image_path)), | ||
str(shot.id), | ||
str(shot.camera.id), | ||
shot.pose.get_rotation_matrix(), | ||
shot.pose.get_origin()) | ||
|
||
for point in reconstruction.points.values(): | ||
shots = graph[point.id].keys() | ||
coordinates = np.array(point.coordinates, dtype=np.float64) | ||
exporter.add_point(coordinates, shots) | ||
|
||
exporter.export(data.data_path + '/openmvs_scene.mvs') | ||
|
||
def undistort_images(self, reconstruction, data): | ||
for shot in reconstruction.shots.values(): | ||
if shot.camera.projection_type == 'perspective': | ||
image = data.image_as_array(shot.id) | ||
undistorted = undistort_image(image, shot) | ||
data.save_undistorted_image(shot.id, undistorted) | ||
|
||
|
||
def undistort_image(image, shot): | ||
"""Remove radial distortion from a perspective image.""" | ||
camera = shot.camera | ||
height, width = image.shape[:2] | ||
K = opencv_calibration_matrix(width, height, camera.focal) | ||
distortion = np.array([camera.k1, camera.k2, 0, 0]) | ||
return cv2.undistort(image, K, distortion) | ||
|
||
|
||
def opencv_calibration_matrix(width, height, focal): | ||
"""Calibration matrix as used by OpenCV and PMVS. | ||
Duplicated with bin.export_openmvs.opencv_calibration_matrix | ||
""" | ||
f = focal * max(width, height) | ||
return np.matrix([[f, 0, 0.5 * (width - 1)], | ||
[0, f, 0.5 * (height - 1)], | ||
[0, 0, 1.0]]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
// Isolating on a namespace to prevent collisions with opencv names | ||
#define _USE_OPENCV | ||
#include "third_party/openmvs/Interface.h" | ||
|
||
|
||
namespace csfm { | ||
|
||
class OpenMVSExporter { | ||
public: | ||
void AddCamera( | ||
const std::string &camera_id, | ||
PyObject *K) { | ||
|
||
PyArrayContiguousView<double> K_view((PyArrayObject *)K); | ||
|
||
MVS::Interface::Platform platform; | ||
platform.name = camera_id; | ||
MVS::Interface::Platform::Camera camera; | ||
camera.K = cv::Matx33d(K_view.data()); | ||
camera.R = cv::Matx33d::eye(); | ||
camera.C = cv::Point3_<double>(0, 0, 0); | ||
platform.cameras.push_back(camera); | ||
|
||
platform_ids_[camera_id] = scene_.platforms.size(); | ||
scene_.platforms.push_back(platform); | ||
} | ||
|
||
void AddShot( | ||
const std::string &path, | ||
const std::string &shot_id, | ||
const std::string &camera_id, | ||
PyObject *R, | ||
PyObject *C) { | ||
PyArrayContiguousView<double> R_view((PyArrayObject *)R); | ||
PyArrayContiguousView<double> C_view((PyArrayObject *)C); | ||
const double *C_data = C_view.data(); | ||
|
||
int platform_id = platform_ids_[camera_id]; | ||
MVS::Interface::Platform &platform = scene_.platforms[platform_id]; | ||
|
||
MVS::Interface::Platform::Pose pose; | ||
pose.R = cv::Matx33d(R_view.data()); | ||
pose.C = cv::Point3_<double>(C_data[0], C_data[1], C_data[2]); | ||
int pose_id = platform.poses.size(); | ||
platform.poses.push_back(pose); | ||
|
||
MVS::Interface::Image image; | ||
image.name = path; | ||
image.platformID = platform_id; | ||
image.cameraID = 0; | ||
image.poseID = pose_id; | ||
|
||
image_ids_[shot_id] = scene_.images.size(); | ||
scene_.images.push_back(image); | ||
} | ||
|
||
void AddPoint( | ||
PyObject *coordinates, | ||
bp::list shot_ids) { | ||
PyArrayContiguousView<double> coordinates_view((PyArrayObject *)coordinates); | ||
const double *x = coordinates_view.data(); | ||
|
||
MVS::Interface::Vertex vertex; | ||
vertex.X = cv::Point3_<double>(x[0], x[1], x[2]); | ||
for (int i = 0; i < len(shot_ids); ++i) { | ||
std::string shot_id = bp::extract<std::string>(shot_ids[i]); | ||
MVS::Interface::Vertex::View view; | ||
view.imageID = image_ids_[shot_id]; | ||
view.confidence = 0; | ||
vertex.views.push_back(view); | ||
} | ||
scene_.vertices.push_back(vertex); | ||
} | ||
|
||
void Export(std::string filename) { | ||
ARCHIVE::SerializeSave(scene_, filename); | ||
} | ||
|
||
private: | ||
std::map<std::string, int> platform_ids_; | ||
std::map<std::string, int> image_ids_; | ||
MVS::Interface scene_; | ||
}; | ||
|
||
|
||
} |
Oops, something went wrong.
d3362ce
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I intend to achieve it, but you have already completed it. 👍
d3362ce
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Testing would be very appreciated!
I'm sometimes getting SegFaults in openMVS when using the exported scenes.
d3362ce
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Congrats for the new exporter.
In order to test if it's related to the OpenSfM exporter or due to OpenMVS you can try to process the same scene in OpenMVG+OpenMVS or under OpenSfM+OpenMVS.
You must check if the segfault is due to memory limitation... since large scene can consume a lot of memory, depending of the step you are running.
d3362ce
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, i've tested using the script here https://gist.github.com/paulinus/1eba8e4528529009f033fe407a7f3c03
No segfault, but i get the wrong colors on the pointcloud. I suspect something is wrong using openMVS on the mac. I've managed to get better colors using this patch paulinus/openMVS@f815120 but it seems very unlikely that this patch is correct (why would it work for others without that patch?).
d3362ce
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the feedback. Happy to hear that already tested it ;-)
You're right there is something strange related to the point projection... We must understand it.
d3362ce
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am trying to built openMVS, and then I will compare the results between the the exporter with OpenSfM + OpenMVS and OpenMVG + OpenMVS on Windows.
d3362ce
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(out of the conversation) It would be nice to setup a Docker image with our tools as ready to use ;-)
d3362ce
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pmoulon i've just asked about the projection on openMVS issues: cdcseacave/openMVS#109
yep a docker image would be great. I'm using docker for building the test in travis, but that includes only OpenSfM. Would be great to have one with all tools included.
d3362ce
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@paulinus For the moment the only Linux distribution dedicated on photogrammetry is NuxSfM https://github.com/pyp22/NuxSFM-2.0
For sure it would be nice to build a Docker system for our projects in order to ease the usage of the users.
And perhaps attract more easily new potential contributors!
It's time to show to people that OpenSource photogrammetry is powerful
d3362ce
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It works well on Win. But if I try to exporter many images, it seems a liltte slowly, may be multi-thread should be used.