FreeArt3D / eval_utils /neucon_eval_utils.py
MorPhLingXD's picture
Upload demo
bf912fe
# This file is derived from [Atlas](https://github.com/magicleap/Atlas).
# Originating Author: Zak Murez (zak.murez.com)
# Modified for [NeuralRecon](https://github.com/zju3dv/NeuralRecon) by Yiming Xie.
# Original header:
# Copyright 2020 Magic Leap, Inc.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import open3d as o3d
import numpy as np
def eval_mesh(mesh_pred, mesh_trgt, threshold=.05, down_sample=.02):
""" Compute Mesh metrics between prediction and target.
Opens the Meshs and runs the metrics
Args:
file_pred: file path of prediction
file_trgt: file path of target
threshold: distance threshold used to compute precision/recal
down_sample: use voxel_downsample to uniformly sample mesh points
Returns:
Dict of mesh metrics
"""
# pcd_pred = o3d.io.read_point_cloud(file_pred)
# pcd_trgt = o3d.io.read_point_cloud(file_trgt)
pcd_pred = o3d.geometry.PointCloud()
pcd_pred.points = o3d.utility.Vector3dVector(mesh_pred.sample(100000).astype(np.float32))
pcd_trgt = o3d.geometry.PointCloud()
pcd_trgt.points = o3d.utility.Vector3dVector(mesh_trgt.sample(100000).astype(np.float32))
if down_sample:
pcd_pred = pcd_pred.voxel_down_sample(down_sample)
pcd_trgt = pcd_trgt.voxel_down_sample(down_sample)
verts_pred = np.asarray(pcd_pred.points)
verts_trgt = np.asarray(pcd_trgt.points)
_, dist1 = nn_correspondance(verts_pred, verts_trgt)
_, dist2 = nn_correspondance(verts_trgt, verts_pred)
dist1 = np.array(dist1)
dist2 = np.array(dist2)
precision = np.mean((dist2 < threshold).astype('float'))
recal = np.mean((dist1 < threshold).astype('float'))
fscore = 2 * precision * recal / (precision + recal)
metrics = {'dist1': np.mean(dist2),
'dist2': np.mean(dist1),
'prec': precision,
'recal': recal,
'fscore': fscore,
}
return metrics
def nn_correspondance(verts1, verts2):
""" for each vertex in verts2 find the nearest vertex in verts1
Args:
nx3 np.array's
Returns:
([indices], [distances])
"""
indices = []
distances = []
if len(verts1) == 0 or len(verts2) == 0:
return indices, distances
pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(verts1)
kdtree = o3d.geometry.KDTreeFlann(pcd)
for vert in verts2:
_, inds, dist = kdtree.search_knn_vector_3d(vert, 1)
indices.append(inds[0])
distances.append(np.sqrt(dist[0]))
return indices, distances
def eval_depth(depth_pred, depth_trgt):
""" Computes 2d metrics between two depth maps
Args:
depth_pred: mxn np.array containing prediction
depth_trgt: mxn np.array containing ground truth
Returns:
Dict of metrics
"""
mask1 = depth_pred > 0 # ignore values where prediction is 0 (% complete)
mask = (depth_trgt < 10) * (depth_trgt > 0) * mask1
depth_pred = depth_pred[mask]
depth_trgt = depth_trgt[mask]
abs_diff = np.abs(depth_pred - depth_trgt)
abs_rel = abs_diff / depth_trgt
sq_diff = abs_diff ** 2
sq_rel = sq_diff / depth_trgt
sq_log_diff = (np.log(depth_pred) - np.log(depth_trgt)) ** 2
thresh = np.maximum((depth_trgt / depth_pred), (depth_pred / depth_trgt))
r1 = (thresh < 1.25).astype('float')
r2 = (thresh < 1.25 ** 2).astype('float')
r3 = (thresh < 1.25 ** 3).astype('float')
metrics = {}
metrics['AbsRel'] = np.mean(abs_rel)
metrics['AbsDiff'] = np.mean(abs_diff)
metrics['SqRel'] = np.mean(sq_rel)
metrics['RMSE'] = np.sqrt(np.mean(sq_diff))
metrics['LogRMSE'] = np.sqrt(np.mean(sq_log_diff))
metrics['r1'] = np.mean(r1)
metrics['r2'] = np.mean(r2)
metrics['r3'] = np.mean(r3)
metrics['complete'] = np.mean(mask1.astype('float'))
return metrics