From b68283fcf235d96efd99f441949664b4ae288e00 Mon Sep 17 00:00:00 2001 From: Mihai Dusmanu Date: Sat, 27 May 2023 10:16:48 +0200 Subject: [PATCH 1/8] Adding some extra logging. --- scantools/proc/overlap.py | 10 ++++++---- scantools/proc/rendering.py | 18 +++++++++++------- scantools/utils/frustum.py | 3 ++- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/scantools/proc/overlap.py b/scantools/proc/overlap.py index afffd5f..64fd29c 100644 --- a/scantools/proc/overlap.py +++ b/scantools/proc/overlap.py @@ -30,7 +30,7 @@ def overlay(overlap: np.ndarray, image: np.ndarray): class OverlapTracer: - def __init__(self, renderer: Renderer, stride: int = 1, num_rays: Optional[float] = None): + def __init__(self, renderer: Renderer, stride: int = 1, num_rays: Optional[int] = None): self.renderer = renderer self.stride = stride self.num_rays = num_rays @@ -100,7 +100,8 @@ def trajectory_overlap(self, keys_q: List, session_q: Session, if is_self: keys_r, session_r, poses_r = keys_q, session_q, poses_q - overlap_matrix = np.full((len(keys_q), len(keys_r)), -1, float) + logger.info("Ray tracing for trajectory overlap between %d keys_q and %d keys_r", len(keys_q), len(keys_r)) + overlap_matrix = np.full((len(keys_q), len(keys_r)), -1, np.float32) overlap_matrix[discard] = 0 # cache the image poses as they might be compositions of rig poses @@ -159,7 +160,7 @@ def compute_overlaps_for_sequence(capture: Capture, id_q: str, id_ref: str, keys_q: Optional[List] = None, keys_ref: Optional[List] = None, T_q: Optional[Trajectories] = None, num_rays: int = 60, - do_caching: bool = True) -> Tuple[List[np.ndarray]]: + do_caching: bool = False) -> Tuple[List[np.ndarray]]: session_q = capture.sessions[id_q] if keys_q is None: keys_q = sorted(session_q.images.key_pairs()) @@ -203,7 +204,8 @@ def compute_overlaps_for_sequence(capture: Capture, id_q: str, id_ref: str, if do_caching and sub_mesh_path in TRACERS: tracer = TRACERS[sub_mesh_path] else: - tracer = OverlapTracer(Renderer(read_mesh(sub_mesh_path)), num_rays=num_rays) + mesh = read_mesh(sub_mesh_path) + tracer = OverlapTracer(Renderer(mesh), num_rays=num_rays) if do_caching: TRACERS[sub_mesh_path] = tracer diff --git a/scantools/proc/rendering.py b/scantools/proc/rendering.py index 80ca5a7..4163b8a 100644 --- a/scantools/proc/rendering.py +++ b/scantools/proc/rendering.py @@ -39,6 +39,11 @@ def compute_rays(T_cam2w: Pose, camera: Camera, stride: int = 1): return origins, directions +def release_scene(scene): + logger.info("Releasing scene") + rb.release_scene(scene) + + class Renderer: def __init__(self, mesh: Union[Path, o3d.geometry.TriangleMesh]): if isinstance(mesh, Path): @@ -52,13 +57,17 @@ def __init__(self, mesh: Union[Path, o3d.geometry.TriangleMesh]): vertex_colors = np.random.rand(vertices.shape[0], 3).astype(np.float32) triangles = np.asarray(mesh.triangles).astype(np.int32) del mesh + logging.info("Mesh converted to numpy - %d vertices and %d triangles", vertices.shape[0], triangles.shape[0]) + logging.info("Creating scene...") self.scene = rb.create_scene() rb.add_triangle_mesh(self.scene, vertices, triangles) self.geom = (triangles, vertices, vertex_colors) + logging.info("Renderer successfully created.") + # automatically cleanup the object if release is not called explicitly - self._finalizer = weakref.finalize(self, self._release, self.scene) + self._finalizer = weakref.finalize(self, release_scene, self.scene) def render_from_capture(self, T_cam2w: Pose, camera: Camera, with_normals: bool = False, ) -> Tuple[np.ndarray]: @@ -98,13 +107,8 @@ def compute_intersections(self, rays: Tuple) -> Tuple: locations = rb.barycentric_interpolator(tri_ids, bcoords, *self.geom[:2]) return locations, valid - @staticmethod - def _release(scene): - if scene is not None: - rb.release_scene(scene) - def release(self): if self.scene is None: raise ValueError('Cannot release twice, create a new object.') - self._release(self.scene) + release_scene(self.scene) self.scene = None diff --git a/scantools/utils/frustum.py b/scantools/utils/frustum.py index 5ed8b1e..e481533 100644 --- a/scantools/utils/frustum.py +++ b/scantools/utils/frustum.py @@ -94,7 +94,7 @@ def _worker_fn(param): pyramid_points1[start_idx_N : end_idx_N]) intersects[start_idx_N : end_idx_N, start_idx_M : end_idx_M] = ~(does_not_intersect1 | does_not_intersect2.T) if len(params) < 4: - for p in params: + for p in tqdm(params): _worker_fn(p) else: thread_map(_worker_fn, params, max_workers=num_threads) @@ -130,6 +130,7 @@ def frustum_intersections(keys_q: List, session_q: Session, T_q: Optional[Trajec keys_r: Optional[List] = None, session_r: Optional[Session] = None, poses_r: Optional[Trajectories] = None, max_depth: float = 20. ) -> np.ndarray: + logger.info("Computing frustum overlaps between %d keys_q and %d keys_r", len(keys_q), len(key_r) if keys_r else 0) frustums_q = pyramids_from_trajectory(keys_q, session_q, poses=T_q, max_depth=max_depth) if keys_r is None: frustums_r = frustums_q From c76cae5efba3c698ddfc0c93558ddb95b8df44ba Mon Sep 17 00:00:00 2001 From: Mihai Dusmanu Date: Sat, 27 May 2023 10:19:22 +0200 Subject: [PATCH 2/8] Revert --- scantools/proc/overlap.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/scantools/proc/overlap.py b/scantools/proc/overlap.py index 64fd29c..ff8b30c 100644 --- a/scantools/proc/overlap.py +++ b/scantools/proc/overlap.py @@ -160,7 +160,7 @@ def compute_overlaps_for_sequence(capture: Capture, id_q: str, id_ref: str, keys_q: Optional[List] = None, keys_ref: Optional[List] = None, T_q: Optional[Trajectories] = None, num_rays: int = 60, - do_caching: bool = False) -> Tuple[List[np.ndarray]]: + do_caching: bool = True) -> Tuple[List[np.ndarray]]: session_q = capture.sessions[id_q] if keys_q is None: keys_q = sorted(session_q.images.key_pairs()) @@ -204,8 +204,7 @@ def compute_overlaps_for_sequence(capture: Capture, id_q: str, id_ref: str, if do_caching and sub_mesh_path in TRACERS: tracer = TRACERS[sub_mesh_path] else: - mesh = read_mesh(sub_mesh_path) - tracer = OverlapTracer(Renderer(mesh), num_rays=num_rays) + tracer = OverlapTracer(Renderer(read_mesh(sub_mesh_path)), num_rays=num_rays) if do_caching: TRACERS[sub_mesh_path] = tracer From 08363c58ad0321118794f1203537c5c97c389cd4 Mon Sep 17 00:00:00 2001 From: Mihai Dusmanu Date: Sat, 27 May 2023 10:23:29 +0200 Subject: [PATCH 3/8] float32 --- scantools/proc/overlap.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scantools/proc/overlap.py b/scantools/proc/overlap.py index ff8b30c..9ff643b 100644 --- a/scantools/proc/overlap.py +++ b/scantools/proc/overlap.py @@ -196,8 +196,8 @@ def compute_overlaps_for_sequence(capture: Capture, id_q: str, id_ref: str, valid_image_indices_list = [np.array(list(range(len(keys_ref))))] selected_keys_ref_list = [keys_ref] - ov_q2r = np.zeros([len(keys_q), len(keys_ref)]) - ov_r2q = np.zeros([len(keys_ref), len(keys_q)]) + ov_q2r = np.zeros([len(keys_q), len(keys_ref)], dtype=np.float32) + ov_r2q = np.zeros([len(keys_ref), len(keys_q)], dtype=np.float32) for sub_info in zip(sub_mesh_id_list, valid_image_indices_list, selected_keys_ref_list): sub_mesh_id, valid_image_indices, selected_keys_ref = sub_info sub_mesh_path = capture.proc_path(id_ref) / session_ref.proc.meshes[sub_mesh_id] From e2d95188f0533fcb8598c06234143fed1fbe2485 Mon Sep 17 00:00:00 2001 From: Mihai Dusmanu Date: Wed, 13 Nov 2024 09:52:33 +0100 Subject: [PATCH 4/8] Fix. --- scantools/proc/rendering.py | 126 +++++++++++++++++++++++++++++++++--- scantools/utils/frustum.py | 3 +- 2 files changed, 118 insertions(+), 11 deletions(-) diff --git a/scantools/proc/rendering.py b/scantools/proc/rendering.py index 1c53dc4..e47fcbe 100644 --- a/scantools/proc/rendering.py +++ b/scantools/proc/rendering.py @@ -42,9 +42,116 @@ def compute_rays(T_cam2w: Pose, camera: Camera, stride: int = 1, p2d: np.ndarray return origins, directions -def release_scene(scene): - logger.info("Releasing scene") - rb.release_scene(scene) +class Renderer: + def __init__(self, mesh: Union[Path, o3d.geometry.TriangleMesh]): + if isinstance(mesh, Path): + mesh = read_mesh(mesh) + assert isinstance(mesh, o3d.geometry.TriangleMesh) + + vertices = np.asarray(mesh.vertices).astype(np.float32) + if mesh.has_vertex_colors(): + vertex_colors = np.asarray(mesh.vertex_colors).astype(np.float32) + else: + vertex_colors = np.random.rand(vertices.shape[0], 3).astype(np.float32) + triangles = np.asarray(mesh.triangles).astype(np.int32) + del mesh + + self.scene = rb.create_scene() + rb.add_triangle_mesh(self.scene, vertices, triangles) + self.geom = (triangles, vertices, vertex_colors) + + # automatically cleanup the object if release is not called explicitly + self._finalizer = weakref.finalize(self, self._release, self.scene) + + def render_from_capture(self, T_cam2w: Pose, camera: Camera, with_normals: bool = False, + ) -> Tuple[np.ndarray]: + T_w2cam = T_cam2w.inverse() + ray_origins, ray_directions = compute_rays(T_cam2w, camera) + + geom_ids, bcoords = rb.ray_scene_intersection( + self.scene, ray_origins, ray_directions) + *_, tri_ids, bcoords, valid = rbutils.filter_intersections(geom_ids, bcoords) + + rgb, depth = rbutils.interpolate_rgbd_from_geometry( + *self.geom, tri_ids, bcoords, valid, + T_w2cam.R, T_w2cam.t, camera.width, camera.height) + if not with_normals: + return rgb, depth + + tris = self.geom[0][tri_ids] + v = self.geom[1] + normals = np.cross(v[tris[:, 0]] - v[tris[:, 1]], v[tris[:, 0]] - v[tris[:, 2]]) + normals /= np.linalg.norm(normals, axis=1, keepdims=True).clip(min=1e-7) + inverted = np.einsum('nd,nd->n', normals, ray_directions[valid]) < 0 + normals[inverted] *= -1 + normals = normals @ T_cam2w.inv.R.T + normal_map = np.zeros((*depth.shape, 3)) + normal_map[valid.reshape(*depth.shape)] = normals + + return rgb, depth, normal_map + + + def compute_intersections(self, rays: Tuple) -> Tuple: + origins, directions = rays + origins = np.ascontiguousarray(origins, dtype=np.float32) + directions = np.ascontiguousarray(directions, dtype=np.float32) + + geom_ids, bcoords = rb.ray_scene_intersection(self.scene, origins, directions) + *_, tri_ids, bcoords, valid = rbutils.filter_intersections(geom_ids, bcoords) + locations = rb.barycentric_interpolator(tri_ids, bcoords, *self.geom[:2]) + return locations, valid + + @staticmethod + def _release(scene): + if scene is not None: + rb.release_scene(scene) + + def release(self): + if self.scene is None: + raise ValueError('Cannot release twice, create a new object.') + self._release(self.scene) + self.scene = Noneimport logging +import weakref +from typing import Tuple, Union +from pathlib import Path +import open3d as o3d +import numpy as np + +try: + import raybender as rb + import raybender.utils as rbutils +except ImportError as error: + logging.getLogger(__name__).error( + 'Could not find raybender; install it from https://github.com/cvg/raybender.') + raise error + +from ..capture import Pose, Camera +from ..utils.geometry import to_homogeneous +from ..utils.io import read_mesh + + +def compute_rays(T_cam2w: Pose, camera: Camera, stride: int = 1, p2d: np.ndarray = None): + center = T_cam2w.t + + # If p2d (2D points) is not provided, we compute rays for the entire image. + if p2d is None: + w, h = np.array((camera.width, camera.height)) // stride + p2d = np.mgrid[:h, :w].reshape(2, -1)[::-1].T.astype(np.float32) + + origins = np.tile(center.astype(np.float32)[None], (len(p2d), 1)) + p2d += 0.5 # to COLMAP coordinates + if stride != 1: + p2d *= stride + p2d_norm = camera.image2world(p2d) + R = T_cam2w.R + # It is much faster to perform the transformation in fp32 + directions = to_homogeneous(p2d_norm.astype(np.float32)) @ R.astype(np.float32).T + # directions = to_homogeneous(p2d_norm) @ R.T + + # Outputs must be contiguous. + origins = np.ascontiguousarray(origins, dtype=np.float32) + directions = np.ascontiguousarray(directions, dtype=np.float32) + return origins, directions class Renderer: @@ -60,17 +167,13 @@ def __init__(self, mesh: Union[Path, o3d.geometry.TriangleMesh]): vertex_colors = np.random.rand(vertices.shape[0], 3).astype(np.float32) triangles = np.asarray(mesh.triangles).astype(np.int32) del mesh - logging.info("Mesh converted to numpy - %d vertices and %d triangles", vertices.shape[0], triangles.shape[0]) - logging.info("Creating scene...") self.scene = rb.create_scene() rb.add_triangle_mesh(self.scene, vertices, triangles) self.geom = (triangles, vertices, vertex_colors) - logging.info("Renderer successfully created.") - # automatically cleanup the object if release is not called explicitly - self._finalizer = weakref.finalize(self, release_scene, self.scene) + self._finalizer = weakref.finalize(self, self._release, self.scene) def render_from_capture(self, T_cam2w: Pose, camera: Camera, with_normals: bool = False, ) -> Tuple[np.ndarray]: @@ -110,8 +213,13 @@ def compute_intersections(self, rays: Tuple) -> Tuple: locations = rb.barycentric_interpolator(tri_ids, bcoords, *self.geom[:2]) return locations, valid + @staticmethod + def _release(scene): + if scene is not None: + rb.release_scene(scene) + def release(self): if self.scene is None: raise ValueError('Cannot release twice, create a new object.') - release_scene(self.scene) + self._release(self.scene) self.scene = None diff --git a/scantools/utils/frustum.py b/scantools/utils/frustum.py index e481533..5ed8b1e 100644 --- a/scantools/utils/frustum.py +++ b/scantools/utils/frustum.py @@ -94,7 +94,7 @@ def _worker_fn(param): pyramid_points1[start_idx_N : end_idx_N]) intersects[start_idx_N : end_idx_N, start_idx_M : end_idx_M] = ~(does_not_intersect1 | does_not_intersect2.T) if len(params) < 4: - for p in tqdm(params): + for p in params: _worker_fn(p) else: thread_map(_worker_fn, params, max_workers=num_threads) @@ -130,7 +130,6 @@ def frustum_intersections(keys_q: List, session_q: Session, T_q: Optional[Trajec keys_r: Optional[List] = None, session_r: Optional[Session] = None, poses_r: Optional[Trajectories] = None, max_depth: float = 20. ) -> np.ndarray: - logger.info("Computing frustum overlaps between %d keys_q and %d keys_r", len(keys_q), len(key_r) if keys_r else 0) frustums_q = pyramids_from_trajectory(keys_q, session_q, poses=T_q, max_depth=max_depth) if keys_r is None: frustums_r = frustums_q From 332d45fb66c76986c6cada36b98c476bc15c6a70 Mon Sep 17 00:00:00 2001 From: Mihai Dusmanu Date: Wed, 13 Nov 2024 09:53:37 +0100 Subject: [PATCH 5/8] CR. --- scantools/proc/rendering.py | 112 ------------------------------------ 1 file changed, 112 deletions(-) diff --git a/scantools/proc/rendering.py b/scantools/proc/rendering.py index e47fcbe..d99119d 100644 --- a/scantools/proc/rendering.py +++ b/scantools/proc/rendering.py @@ -18,118 +18,6 @@ from ..utils.io import read_mesh -def compute_rays(T_cam2w: Pose, camera: Camera, stride: int = 1, p2d: np.ndarray = None): - center = T_cam2w.t - - # If p2d (2D points) is not provided, we compute rays for the entire image. - if p2d is None: - w, h = np.array((camera.width, camera.height)) // stride - p2d = np.mgrid[:h, :w].reshape(2, -1)[::-1].T.astype(np.float32) - - origins = np.tile(center.astype(np.float32)[None], (len(p2d), 1)) - p2d += 0.5 # to COLMAP coordinates - if stride != 1: - p2d *= stride - p2d_norm = camera.image2world(p2d) - R = T_cam2w.R - # It is much faster to perform the transformation in fp32 - directions = to_homogeneous(p2d_norm.astype(np.float32)) @ R.astype(np.float32).T - # directions = to_homogeneous(p2d_norm) @ R.T - - # Outputs must be contiguous. - origins = np.ascontiguousarray(origins, dtype=np.float32) - directions = np.ascontiguousarray(directions, dtype=np.float32) - return origins, directions - - -class Renderer: - def __init__(self, mesh: Union[Path, o3d.geometry.TriangleMesh]): - if isinstance(mesh, Path): - mesh = read_mesh(mesh) - assert isinstance(mesh, o3d.geometry.TriangleMesh) - - vertices = np.asarray(mesh.vertices).astype(np.float32) - if mesh.has_vertex_colors(): - vertex_colors = np.asarray(mesh.vertex_colors).astype(np.float32) - else: - vertex_colors = np.random.rand(vertices.shape[0], 3).astype(np.float32) - triangles = np.asarray(mesh.triangles).astype(np.int32) - del mesh - - self.scene = rb.create_scene() - rb.add_triangle_mesh(self.scene, vertices, triangles) - self.geom = (triangles, vertices, vertex_colors) - - # automatically cleanup the object if release is not called explicitly - self._finalizer = weakref.finalize(self, self._release, self.scene) - - def render_from_capture(self, T_cam2w: Pose, camera: Camera, with_normals: bool = False, - ) -> Tuple[np.ndarray]: - T_w2cam = T_cam2w.inverse() - ray_origins, ray_directions = compute_rays(T_cam2w, camera) - - geom_ids, bcoords = rb.ray_scene_intersection( - self.scene, ray_origins, ray_directions) - *_, tri_ids, bcoords, valid = rbutils.filter_intersections(geom_ids, bcoords) - - rgb, depth = rbutils.interpolate_rgbd_from_geometry( - *self.geom, tri_ids, bcoords, valid, - T_w2cam.R, T_w2cam.t, camera.width, camera.height) - if not with_normals: - return rgb, depth - - tris = self.geom[0][tri_ids] - v = self.geom[1] - normals = np.cross(v[tris[:, 0]] - v[tris[:, 1]], v[tris[:, 0]] - v[tris[:, 2]]) - normals /= np.linalg.norm(normals, axis=1, keepdims=True).clip(min=1e-7) - inverted = np.einsum('nd,nd->n', normals, ray_directions[valid]) < 0 - normals[inverted] *= -1 - normals = normals @ T_cam2w.inv.R.T - normal_map = np.zeros((*depth.shape, 3)) - normal_map[valid.reshape(*depth.shape)] = normals - - return rgb, depth, normal_map - - - def compute_intersections(self, rays: Tuple) -> Tuple: - origins, directions = rays - origins = np.ascontiguousarray(origins, dtype=np.float32) - directions = np.ascontiguousarray(directions, dtype=np.float32) - - geom_ids, bcoords = rb.ray_scene_intersection(self.scene, origins, directions) - *_, tri_ids, bcoords, valid = rbutils.filter_intersections(geom_ids, bcoords) - locations = rb.barycentric_interpolator(tri_ids, bcoords, *self.geom[:2]) - return locations, valid - - @staticmethod - def _release(scene): - if scene is not None: - rb.release_scene(scene) - - def release(self): - if self.scene is None: - raise ValueError('Cannot release twice, create a new object.') - self._release(self.scene) - self.scene = Noneimport logging -import weakref -from typing import Tuple, Union -from pathlib import Path -import open3d as o3d -import numpy as np - -try: - import raybender as rb - import raybender.utils as rbutils -except ImportError as error: - logging.getLogger(__name__).error( - 'Could not find raybender; install it from https://github.com/cvg/raybender.') - raise error - -from ..capture import Pose, Camera -from ..utils.geometry import to_homogeneous -from ..utils.io import read_mesh - - def compute_rays(T_cam2w: Pose, camera: Camera, stride: int = 1, p2d: np.ndarray = None): center = T_cam2w.t From 9a71e8d0162ee7d97357f0cc035bc22018509d8a Mon Sep 17 00:00:00 2001 From: Mihai Dusmanu Date: Wed, 13 Nov 2024 09:54:08 +0100 Subject: [PATCH 6/8] Fix. --- scantools/proc/overlap.py | 1 - 1 file changed, 1 deletion(-) diff --git a/scantools/proc/overlap.py b/scantools/proc/overlap.py index 9ff643b..0b42d7c 100644 --- a/scantools/proc/overlap.py +++ b/scantools/proc/overlap.py @@ -100,7 +100,6 @@ def trajectory_overlap(self, keys_q: List, session_q: Session, if is_self: keys_r, session_r, poses_r = keys_q, session_q, poses_q - logger.info("Ray tracing for trajectory overlap between %d keys_q and %d keys_r", len(keys_q), len(keys_r)) overlap_matrix = np.full((len(keys_q), len(keys_r)), -1, np.float32) overlap_matrix[discard] = 0 From 32238b14f7cd947e314019fe96b6509f4589dd51 Mon Sep 17 00:00:00 2001 From: Mihai Dusmanu Date: Wed, 13 Nov 2024 09:54:47 +0100 Subject: [PATCH 7/8] Fix. --- scantools/proc/overlap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scantools/proc/overlap.py b/scantools/proc/overlap.py index 0b42d7c..e47dcdf 100644 --- a/scantools/proc/overlap.py +++ b/scantools/proc/overlap.py @@ -100,7 +100,7 @@ def trajectory_overlap(self, keys_q: List, session_q: Session, if is_self: keys_r, session_r, poses_r = keys_q, session_q, poses_q - overlap_matrix = np.full((len(keys_q), len(keys_r)), -1, np.float32) + overlap_matrix = np.full((len(keys_q), len(keys_r)), -1, dtype=np.float32) overlap_matrix[discard] = 0 # cache the image poses as they might be compositions of rig poses From 4f42ef2375dd0c9df6416914ed50841b837501ad Mon Sep 17 00:00:00 2001 From: Mihai Dusmanu Date: Wed, 13 Nov 2024 10:12:52 +0100 Subject: [PATCH 8/8] fix. --- scantools/proc/overlap.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scantools/proc/overlap.py b/scantools/proc/overlap.py index e47dcdf..9796800 100644 --- a/scantools/proc/overlap.py +++ b/scantools/proc/overlap.py @@ -100,7 +100,7 @@ def trajectory_overlap(self, keys_q: List, session_q: Session, if is_self: keys_r, session_r, poses_r = keys_q, session_q, poses_q - overlap_matrix = np.full((len(keys_q), len(keys_r)), -1, dtype=np.float32) + overlap_matrix = np.full((len(keys_q), len(keys_r)), -1, dtype=np.float16) overlap_matrix[discard] = 0 # cache the image poses as they might be compositions of rig poses @@ -195,8 +195,8 @@ def compute_overlaps_for_sequence(capture: Capture, id_q: str, id_ref: str, valid_image_indices_list = [np.array(list(range(len(keys_ref))))] selected_keys_ref_list = [keys_ref] - ov_q2r = np.zeros([len(keys_q), len(keys_ref)], dtype=np.float32) - ov_r2q = np.zeros([len(keys_ref), len(keys_q)], dtype=np.float32) + ov_q2r = np.zeros([len(keys_q), len(keys_ref)], dtype=np.float16) + ov_r2q = np.zeros([len(keys_ref), len(keys_q)], dtype=np.float16) for sub_info in zip(sub_mesh_id_list, valid_image_indices_list, selected_keys_ref_list): sub_mesh_id, valid_image_indices, selected_keys_ref = sub_info sub_mesh_path = capture.proc_path(id_ref) / session_ref.proc.meshes[sub_mesh_id]