File: scan_register.py

package info (click to toggle)
trimesh 4.5.1-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 33,416 kB
  • sloc: python: 35,596; makefile: 96; javascript: 85; sh: 38
file content (102 lines) | stat: -rw-r--r-- 2,812 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
"""
scan_register.py
-------------

Create some simulated 3D scan data and register
it to a "truth" mesh.
"""

import numpy as np

import trimesh


def simulated_brick(face_count, extents, noise, max_iter=10):
    """
    Produce a mesh that is a rectangular solid with noise
    with a random transform.

    Parameters
    -------------
    face_count : int
      Approximate number of faces desired
    extents : (n,3) float
      Dimensions of brick
    noise : float
      Magnitude of vertex noise to apply
    """

    # create the mesh as a simple box
    mesh = trimesh.creation.box(extents=extents)

    # add some systematic error pre- tessellation
    mesh.vertices[0] += mesh.vertex_normals[0] + (noise * 2)

    # subdivide until we have more faces than we want
    for _i in range(max_iter):
        if len(mesh.vertices) > face_count:
            break
        mesh = mesh.subdivide()

    # apply tessellation and random noise
    mesh = mesh.permutate.noise(noise)

    # randomly rotation with translation
    transform = trimesh.transformations.random_rotation_matrix()
    transform[:3, 3] = (np.random.random(3) - 0.5) * 1000

    mesh.apply_transform(transform)

    return mesh


if __name__ == "__main__":
    # print log messages to terminal
    trimesh.util.attach_to_log()
    log = trimesh.util.log

    # the size of our boxes
    extents = [6, 12, 2]

    # create a simulated brick with noise and random transform
    scan = simulated_brick(face_count=5000, extents=extents, noise=0.05)

    # create a "true" mesh
    truth = trimesh.creation.box(extents=extents)

    # (4, 4) float homogeneous transform from truth to scan
    # this will do an ICP refinement with initial transforms
    # seeded by the principal components of inertia
    truth_to_scan, cost = truth.register(scan)

    log.debug(
        "centroid distance pre-registration:",
        np.linalg.norm(truth.centroid - scan.centroid),
    )

    # apply the registration transform
    truth.apply_transform(truth_to_scan)

    log.debug(
        "centroid distance post-registration:",
        np.linalg.norm(truth.centroid - scan.centroid),
    )

    # find the distance from the truth mesh to each scan vertex
    distance = truth.nearest.on_surface(scan.vertices)[1]

    # color the mesh by distance from truth
    # linear interpolation between two colors
    # scaled between distance.min() and distance.max()
    scan.visual.vertex_colors = trimesh.visual.interpolate(distance)

    # print some quick statistics about the mesh
    log.debug("distance max:", distance.max())
    log.debug("distance mean:", distance.mean())
    log.debug("distance STD:", distance.std())

    # export result with vertex colors for meshlab
    scan.export("scan_new.ply")

    # show in a pyglet window
    scan.show()