Spaces:
Running
on
L40S
Running
on
L40S
# -*- coding: utf-8 -*- | |
# Max-Planck-Gesellschaft zur Förderung der Wissenschaften e.V. (MPG) is | |
# holder of all proprietary rights on this computer program. | |
# You can only use this computer program if you have closed | |
# a license agreement with MPG or you get the right to use the computer | |
# program from someone who is authorized to grant you that right. | |
# Any use of the computer program without a valid license is prohibited and | |
# liable to prosecution. | |
# | |
# Copyright©2019 Max-Planck-Gesellschaft zur Förderung | |
# der Wissenschaften e.V. (MPG). acting on behalf of its Max Planck Institute | |
# for Intelligent Systems. All rights reserved. | |
# | |
# Contact: ps-license@tuebingen.mpg.de | |
import numpy as np | |
from scipy.spatial import cKDTree | |
import trimesh | |
import logging | |
logging.getLogger("trimesh").setLevel(logging.ERROR) | |
def save_obj_mesh(mesh_path, verts, faces): | |
file = open(mesh_path, 'w') | |
for v in verts: | |
file.write('v %.4f %.4f %.4f\n' % (v[0], v[1], v[2])) | |
for f in faces: | |
f_plus = f + 1 | |
file.write('f %d %d %d\n' % (f_plus[0], f_plus[1], f_plus[2])) | |
file.close() | |
def save_obj_mesh_with_color(mesh_path, verts, faces, colors): | |
file = open(mesh_path, 'w') | |
for idx, v in enumerate(verts): | |
c = colors[idx] | |
file.write('v %.4f %.4f %.4f %.4f %.4f %.4f\n' % | |
(v[0], v[1], v[2], c[0], c[1], c[2])) | |
for f in faces: | |
f_plus = f + 1 | |
file.write('f %d %d %d\n' % (f_plus[0], f_plus[1], f_plus[2])) | |
file.close() | |
def save_ply(mesh_path, points, rgb): | |
''' | |
Save the visualization of sampling to a ply file. | |
Red points represent positive predictions. | |
Green points represent negative predictions. | |
:param mesh_path: File name to save | |
:param points: [N, 3] array of points | |
:param rgb: [N, 3] array of rgb values in the range [0~1] | |
:return: | |
''' | |
to_save = np.concatenate([points, rgb * 255], axis=-1) | |
return np.savetxt( | |
mesh_path, | |
to_save, | |
fmt='%.6f %.6f %.6f %d %d %d', | |
comments='', | |
header=( | |
'ply\nformat ascii 1.0\nelement vertex {:d}\n' + | |
'property float x\nproperty float y\nproperty float z\n' + | |
'property uchar red\nproperty uchar green\nproperty uchar blue\n' + | |
'end_header').format(points.shape[0])) | |
class HoppeMesh: | |
def __init__(self, verts, faces, vert_normals, face_normals): | |
''' | |
The HoppeSDF calculates signed distance towards a predefined oriented point cloud | |
http://hhoppe.com/recon.pdf | |
For clean and high-resolution pcl data, this is the fastest and accurate approximation of sdf | |
:param points: pts | |
:param normals: normals | |
''' | |
self.verts = verts # [n, 3] | |
self.faces = faces # [m, 3] | |
self.vert_normals = vert_normals # [n, 3] | |
self.face_normals = face_normals # [m, 3] | |
self.kd_tree = cKDTree(self.verts) | |
self.len = len(self.verts) | |
def query(self, points): | |
dists, idx = self.kd_tree.query(points, n_jobs=1) | |
# FIXME: because the eyebows are removed, cKDTree around eyebows | |
# are not accurate. Cause a few false-inside labels here. | |
dirs = points - self.verts[idx] | |
signs = (dirs * self.vert_normals[idx]).sum(axis=1) | |
signs = (signs > 0) * 2 - 1 | |
return signs * dists | |
def contains(self, points): | |
labels = trimesh.Trimesh(vertices=self.verts, | |
faces=self.faces).contains(points) | |
return labels | |
def export(self, path): | |
if self.colors is not None: | |
save_obj_mesh_with_color(path, self.verts, self.faces, | |
self.colors[:, 0:3] / 255.0) | |
else: | |
save_obj_mesh(path, self.verts, self.faces) | |
def export_ply(self, path): | |
save_ply(path, self.verts, self.colors[:, 0:3] / 255.0) | |
def triangles(self): | |
return self.verts[self.faces] # [n, 3, 3] | |