Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

common: add Python utility for reading MVS interface archives #1069

Merged
merged 25 commits into from Oct 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading