Skip to content

Commit

Permalink
interface: add Python utility for reading MVS scenes (#1069)
Browse files Browse the repository at this point in the history
  • Loading branch information
4CJ7T authored Oct 23, 2023
1 parent 95decea commit ecd5dde
Show file tree
Hide file tree
Showing 3 changed files with 195 additions and 37 deletions.
8 changes: 4 additions & 4 deletions scripts/python/MvsReadDMAP.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
'''
Example usage of MvsUtils.py for exporting dmap file content.
Example usage of MvsUtils.py for reading DMAP file content.
usage: MvsReadDMAP.py [-h] [--input INPUT] [--output OUTPUT]
'''
Expand All @@ -25,9 +25,9 @@ def exportDMAPContent(dmap_path):

def main():
parser = ArgumentParser()
parser.add_argument('-i', '--input', type=str, required=True, help='path to the depth map directory')
parser.add_argument('-t', '--threads', type=int, default=int(os.cpu_count() * 0.5) - 1, help='number of parallel computations')
parser.add_argument('-o', '--output', type=str, required=True, help='path to the output directory')
parser.add_argument('-i', '--input', type=str, required=True, help='Path to the DMAP file directory')
parser.add_argument('-t', '--threads', type=int, default=int(os.cpu_count() * 0.5) - 1, help='Number of parallel computations')
parser.add_argument('-o', '--output', type=str, required=True, help='Path to the output directory')
args = parser.parse_args()

dmap_paths = glob(os.path.join(args.input, '*.dmap'))
Expand Down
35 changes: 35 additions & 0 deletions scripts/python/MvsReadMVS.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
'''
Example usage of MvsUtils.py for reading MVS interface archive content.
usage: MvsReadMVS.py [-h] [--input INPUT] [--output OUTPUT]
'''

from argparse import ArgumentParser
import json
from MvsUtils import loadMVSInterface
import os

def main():
parser = ArgumentParser()
parser.add_argument('-i', '--input', type=str, required=True, help='Path to the MVS interface archive')
parser.add_argument('-o', '--output', type=str, required=True, help='Path to the output json file')
args = parser.parse_args()

mvs = loadMVSInterface(args.input)

for platform_index in range(len(mvs['platforms'])):
for camera_index in range(len(mvs['platforms'][platform_index]['cameras'])):
camera = mvs['platforms'][platform_index]['cameras'][camera_index]
image_max = max(camera['width'], camera['height'])
fx = camera['K'][0][0] / image_max
fy = camera['K'][1][1] / image_max
poses_size = len(camera['poses'])
print('Camera model loaded: platform {}; camera {}; f {:.3f}x{:.3f}; poses {}'.format(platform_index, camera_index, fx, fy, poses_size))

os.makedirs(os.path.dirname(args.output), exist_ok = True)

with open(args.output, 'w') as file:
json.dump(mvs, file, indent=2)

if __name__ == '__main__':
main()
189 changes: 156 additions & 33 deletions scripts/python/MvsUtils.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'''
OpenMVS python utilities.
E.g., from MvsUtils import loadDMAP
E.g., from MvsUtils import loadDMAP, loadMVSInterface
'''

import numpy as np
Expand All @@ -21,47 +21,170 @@ def loadDMAP(dmap_path):
depth_width, depth_height = np.frombuffer(dmap.read(8), dtype=np.dtype('I'))

if (file_type != 'DR' or has_depth == False or depth_width <= 0 or depth_height <= 0 or image_width < depth_width or image_height < depth_height):
print('error: opening file \'%s\' for reading depth-data' % dmap_path)
return None
print('error: opening file \'{}\' for reading depth-data'.format(dmap_path))
return

depth_min, depth_max = np.frombuffer(dmap.read(8), dtype=np.dtype('f'))

file_name_length = np.frombuffer(dmap.read(2), dtype=np.dtype('H'))[0]
file_name = dmap.read(file_name_length).decode()
file_name_size = np.frombuffer(dmap.read(2), dtype=np.dtype('H'))[0]
file_name = dmap.read(file_name_size).decode()

view_ids_length = np.frombuffer(dmap.read(4), dtype=np.dtype('I'))[0]
reference_view_id, *neighbor_view_ids = np.frombuffer(dmap.read(4 * view_ids_length), dtype=np.dtype('I'))
view_ids_size = np.frombuffer(dmap.read(4), dtype=np.dtype('I'))[0]
reference_view_id, *neighbor_view_ids = np.frombuffer(dmap.read(4 * view_ids_size), dtype=np.dtype('I'))

K = np.frombuffer(dmap.read(72), dtype=np.dtype('d')).reshape(3, 3)
R = np.frombuffer(dmap.read(72), dtype=np.dtype('d')).reshape(3, 3)
C = np.frombuffer(dmap.read(24), dtype=np.dtype('d'))

depth_length = depth_width * depth_height
depth_map = np.frombuffer(dmap.read(4 * depth_length), dtype=np.dtype('f')).reshape(depth_height, depth_width)
normal_map = np.frombuffer(dmap.read(4 * depth_length * 3), dtype=np.dtype('f')).reshape(depth_height, depth_width, 3) if has_normal else np.asarray([])
confidence_map = np.frombuffer(dmap.read(4 * depth_length), dtype=np.dtype('f')).reshape(depth_height, depth_width) if has_conf else np.asarray([])
views_map = np.frombuffer(dmap.read(depth_length * 4), dtype=np.dtype('B')).reshape(depth_height, depth_width, 4) if has_views else np.asarray([])
data = {
'has_normal': has_normal,
'has_conf': has_conf,
'has_views': has_views,
'image_width': image_width,
'image_height': image_height,
'depth_width': depth_width,
'depth_height': depth_height,
'depth_min': depth_min,
'depth_max': depth_max,
'file_name': file_name,
'reference_view_id': reference_view_id,
'neighbor_view_ids': neighbor_view_ids,
'K': K,
'R': R,
'C': C
}

map_size = depth_width * depth_height
depth_map = np.frombuffer(dmap.read(4 * map_size), dtype=np.dtype('f')).reshape(depth_height, depth_width)
data.update({'depth_map': depth_map})
if has_normal:
normal_map = np.frombuffer(dmap.read(4 * map_size * 3), dtype=np.dtype('f')).reshape(depth_height, depth_width, 3)
data.update({'normal_map': normal_map})
if has_conf:
confidence_map = np.frombuffer(dmap.read(4 * map_size), dtype=np.dtype('f')).reshape(depth_height, depth_width)
data.update({'confidence_map': confidence_map})
if has_views:
views_map = np.frombuffer(dmap.read(map_size * 4), dtype=np.dtype('B')).reshape(depth_height, depth_width, 4)
data.update({'views_map': views_map})

data = {
'has_normal': has_normal,
'has_conf': has_conf,
'has_views': has_views,
'image_width': image_width,
'image_height': image_height,
'depth_width': depth_width,
'depth_height': depth_height,
'depth_min': depth_min,
'depth_max': depth_max,
'file_name': file_name,
'reference_view_id': reference_view_id,
'neighbor_view_ids': neighbor_view_ids,
'K': K,
'R': R,
'C': C,
'depth_map': depth_map,
'normal_map': normal_map,
'confidence_map': confidence_map,
'views_map': views_map
}
return data

def loadMVSInterface(archive_path):
with open(archive_path, 'rb') as mvs:
archive_type = mvs.read(4).decode()
version = np.frombuffer(mvs.read(4), dtype=np.dtype('I')).tolist()[0]
reserve = np.frombuffer(mvs.read(4), dtype=np.dtype('I'))

if archive_type != 'MVSI':
print('error: opening file \'{}\''.format(archive_path))
return

data = {
'project_stream': archive_type,
'project_stream_version': version,
'platforms': [],
'images': [],
'vertices': [],
'vertices_normal': [],
'vertices_color': []
}

platforms_size = np.frombuffer(mvs.read(8), dtype=np.dtype('Q'))[0]
for platform_index in range(platforms_size):
platform_name_size = np.frombuffer(mvs.read(8), dtype=np.dtype('Q'))[0]
platform_name = mvs.read(platform_name_size).decode()
data['platforms'].append({'name': platform_name, 'cameras': []})
cameras_size = np.frombuffer(mvs.read(8), dtype=np.dtype('Q'))[0]
for camera_index in range(cameras_size):
camera_name_size = np.frombuffer(mvs.read(8), dtype=np.dtype('Q'))[0]
camera_name = mvs.read(camera_name_size).decode()
data['platforms'][platform_index]['cameras'].append({'name': camera_name})
if version > 3:
band_name_size = np.frombuffer(mvs.read(8), dtype=np.dtype('Q'))[0]
band_name = mvs.read(band_name_size).decode()
data['platforms'][platform_index]['cameras'][camera_index].update({'band_name': band_name})
if version > 0:
width, height = np.frombuffer(mvs.read(8), dtype=np.dtype('I')).tolist()
data['platforms'][platform_index]['cameras'][camera_index].update({'width': width, 'height': height})
K = np.asarray(np.frombuffer(mvs.read(72), dtype=np.dtype('d'))).reshape(3, 3).tolist()
data['platforms'][platform_index]['cameras'][camera_index].update({'K': K, 'poses': []})
identity_matrix = np.asarray(np.frombuffer(mvs.read(96), dtype=np.dtype('d'))).reshape(4, 3)
poses_size = np.frombuffer(mvs.read(8), dtype=np.dtype('Q'))[0]
for _ in range(poses_size):
R = np.asarray(np.frombuffer(mvs.read(72), dtype=np.dtype('d'))).reshape(3, 3).tolist()
C = np.asarray(np.frombuffer(mvs.read(24), dtype=np.dtype('d'))).tolist()
data['platforms'][platform_index]['cameras'][camera_index]['poses'].append({'R': R, 'C': C})

images_size = np.frombuffer(mvs.read(8), dtype=np.dtype('Q'))[0]
for image_index in range(images_size):
name_size = np.frombuffer(mvs.read(8), dtype=np.dtype('Q'))[0]
name = mvs.read(name_size).decode()
data['images'].append({'name': name})
if version > 4:
mask_name_size = np.frombuffer(mvs.read(8), dtype=np.dtype('Q'))[0]
mask_name = mvs.read(mask_name_size).decode()
data['images'][image_index].update({'mask_name': mask_name})
platform_id, camera_id, pose_id = np.frombuffer(mvs.read(12), dtype=np.dtype('I')).tolist()
data['images'][image_index].update({'platform_id': platform_id, 'camera_id': camera_id, 'pose_id': pose_id})
if version > 2:
id = np.frombuffer(mvs.read(4), dtype=np.dtype('I')).tolist()[0]
data['images'][image_index].update({'id': id})
if version > 6:
min_depth, avg_depth, max_depth = np.frombuffer(mvs.read(12), dtype=np.dtype('f')).tolist()
data['images'][image_index].update({'min_depth': min_depth, 'avg_depth': avg_depth, 'max_depth': max_depth, 'view_scores': []})
view_score_size = np.frombuffer(mvs.read(8), dtype=np.dtype('Q'))[0]
for _ in range(view_score_size):
id, points = np.frombuffer(mvs.read(8), dtype=np.dtype('I')).tolist()
scale, angle, area, score = np.frombuffer(mvs.read(16), dtype=np.dtype('f')).tolist()
data['images'][image_index]['view_scores'].append({'id': id, 'points': points, 'scale': scale, 'angle': angle, 'area': area, 'score': score})

vertices_size = np.frombuffer(mvs.read(8), dtype=np.dtype('Q'))[0]
for vertex_index in range(vertices_size):
X = np.frombuffer(mvs.read(12), dtype=np.dtype('f')).tolist()
data['vertices'].append({'X': X, 'views': []})
views_size = np.frombuffer(mvs.read(8), dtype=np.dtype('Q'))[0]
for _ in range(views_size):
image_id = np.frombuffer(mvs.read(4), dtype=np.dtype('I')).tolist()[0]
confidence = np.frombuffer(mvs.read(4), dtype=np.dtype('f')).tolist()[0]
data['vertices'][vertex_index]['views'].append({'image_id': image_id, 'confidence': confidence})

vertices_normal_size = np.frombuffer(mvs.read(8), dtype=np.dtype('Q'))[0]
for _ in range(vertices_normal_size):
normal = np.frombuffer(mvs.read(12), dtype=np.dtype('f')).tolist()
data['vertices_normal'].append(normal)

vertices_color_size = np.frombuffer(mvs.read(8), dtype=np.dtype('Q'))[0]
for _ in range(vertices_color_size):
color = np.frombuffer(mvs.read(3), dtype=np.dtype('B')).tolist()
data['vertices_color'].append(color)

if version > 0:
data.update({'lines': [], 'lines_normal': [], 'lines_color': []})
lines_size = np.frombuffer(mvs.read(8), dtype=np.dtype('Q'))[0]
for line_index in range(lines_size):
pt1 = np.frombuffer(mvs.read(12), dtype=np.dtype('f')).tolist()
pt2 = np.frombuffer(mvs.read(12), dtype=np.dtype('f')).tolist()
data['lines'].append({'pt1': pt1, 'pt2': pt2, 'views': []})
views_size = np.frombuffer(mvs.read(8), dtype=np.dtype('Q'))[0]
for _ in range(views_size):
image_id = np.frombuffer(mvs.read(4), dtype=np.dtype('I')).tolist()[0]
confidence = np.frombuffer(mvs.read(4), dtype=np.dtype('f')).tolist()[0]
data['lines'][line_index]['views'].append({'image_id': image_id, 'confidence': confidence})
lines_normal_size = np.frombuffer(mvs.read(8), dtype=np.dtype('Q'))[0]
for _ in range(lines_normal_size):
normal = np.frombuffer(mvs.read(12), dtype=np.dtype('f')).tolist()
data['lines_normal'].append(normal)
lines_color_size = np.frombuffer(mvs.read(8), dtype=np.dtype('Q'))[0]
for _ in range(lines_color_size):
color = np.frombuffer(mvs.read(3), dtype=np.dtype('B')).tolist()
data['lines_color'].append(color)
if version > 1:
transform = np.frombuffer(mvs.read(128), dtype=np.dtype('d')).reshape(4, 4).tolist()
data.update({'transform': transform})
if version > 5:
rot = np.frombuffer(mvs.read(72), dtype=np.dtype('d')).reshape(3, 3).tolist()
pt_min = np.frombuffer(mvs.read(24), dtype=np.dtype('d')).tolist()
pt_max = np.frombuffer(mvs.read(24), dtype=np.dtype('d')).tolist()
data.update({'obb': {'rot': rot, 'pt_min': pt_min, 'pt_max': pt_max}})

return data

0 comments on commit ecd5dde

Please sign in to comment.