opensfm/actions/export_pmvs.py (120 lines of code) (raw):
import logging
import os
import cv2
import numpy as np
from opensfm import features
from opensfm import io
from opensfm import tracking
from opensfm.dataset import DataSet, UndistortedDataSet
logger = logging.getLogger(__name__)
def run_dataset(data: DataSet, points, image_list, output, undistorted) -> None:
"""Export reconstruction to PLY format
Args:
points: export points
image_list: export only the shots included in this file (path to .txt file)
output: output pmvs directory
undistorted: export the undistorted reconstruction
"""
udata = data.undistorted_dataset()
base_output_path = output if output else os.path.join(data.data_path, "pmvs")
io.mkdir_p(base_output_path)
logger.info(
"Converting dataset [%s] to PMVS dir [%s]" % (data.data_path, base_output_path)
)
if undistorted:
reconstructions = udata.load_undistorted_reconstruction()
else:
reconstructions = data.load_reconstruction()
# load tracks for vis.dat
try:
if undistorted:
tracks_manager = udata.load_undistorted_tracks_manager()
else:
tracks_manager = data.load_tracks_manager()
image_graph = tracking.as_weighted_graph(tracks_manager)
except IOError:
image_graph = None
tracks_manager = None
export_only = None
if image_list:
export_only = {}
with open(image_list, "r") as f:
for image in f:
export_only[image.strip()] = True
for h, reconstruction in enumerate(reconstructions):
export(
reconstruction,
h,
image_graph,
tracks_manager,
base_output_path,
data,
undistorted,
udata,
points,
export_only,
)
def export(
reconstruction,
index,
image_graph,
tracks_manager,
base_output_path,
data: DataSet,
undistorted,
udata: UndistortedDataSet,
with_points,
export_only,
) -> None:
logger.info("Reconstruction %d" % index)
output_path = os.path.join(base_output_path, "recon%d" % index)
io.mkdir_p(output_path)
io.mkdir_p(os.path.join(output_path, "visualize"))
io.mkdir_p(os.path.join(output_path, "txt"))
io.mkdir_p(os.path.join(output_path, "models"))
shot_index = {image: i for i, image in enumerate(reconstruction.shots)}
fvis = open(os.path.join(output_path, "vis.dat"), "w")
fvis.write("VISDATA\n")
fvis.write("%d\n" % len(shot_index))
for image, i in shot_index.items():
shot = reconstruction.shots[image]
base = "%08d" % i
logger.info("Image: %s %s" % (image, base))
# vis.dat for this image
if image_graph:
adj_indices = []
for adj_image in image_graph[image]:
weight = image_graph[image][adj_image]["weight"]
if weight > 0 and adj_image in shot_index:
adj_indices.append(shot_index[adj_image])
num_covisible = len(adj_indices)
fvis.write("%d " % i)
fvis.write("%d " % num_covisible)
for ai in adj_indices:
fvis.write("%d " % ai)
fvis.write("\n")
# radially undistort the original image
camera = shot.camera
if undistorted:
undistorted_image = udata.load_undistorted_image(image)
else:
original_image = data.load_image(image)[:, :, ::-1]
original_h, original_w = original_image.shape[:2]
K = camera.get_K_in_pixel_coordinates(original_w, original_h)
distortion = np.array([camera.k1, camera.k2, 0, 0])
undistorted_image = cv2.undistort(original_image, K, distortion)
# resize and save the undistorted to visualize/%08d.jpg
resized_image = features.resized_image(
undistorted_image, data.config["feature_process_size"]
)
new_image_path = os.path.join(output_path, "visualize", base + ".jpg")
cv2.imwrite(new_image_path, resized_image)
# write camera projection matrix to txt/%08d.txt
resized_h, resized_w = resized_image.shape[:2]
resized_K = camera.get_K_in_pixel_coordinates(resized_w, resized_h)
P = resized_K.dot(shot.pose.get_world_to_cam()[:3])
new_txt = os.path.join(output_path, "txt", base + ".txt")
with open(new_txt, "wb") as f:
np.savetxt(f, P, str("%f"), header="CONTOUR")
fvis.close()
# txt
with open(os.path.join(output_path, "pmvs_txt"), "w") as f:
f.write("level 1\n")
f.write("csize 2\n")
f.write("threshold 0.7\n")
f.write("wsize 7\n")
f.write("minImageNum 3\n")
f.write("CPU 8\n")
f.write("setEdge 0\n")
f.write("useBound 0\n")
f.write("useVisData {}\n".format(int(image_graph is not None)))
f.write("sequence -1\n")
f.write("timages -1 0 %d\n" % len(shot_index))
f.write("oimages 0\n")