meshlab_xml_writer.py 7.01 KB
Newer Older
Clement Pinard's avatar
Clement Pinard committed
1
2
3
import numpy as np
from lxml import etree
from path import Path
Clément Pinard's avatar
Clément Pinard committed
4
from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
Clement Pinard's avatar
Clement Pinard committed
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21


def create_project(mlp_path, model_paths, labels=None, transforms=None):
    if labels is not None:
        assert(len(model_paths) == len(labels))
    else:
        labels = [m.basename() for m in model_paths]

    if transforms is not None:
        assert(len(model_paths) == len(transforms))
    else:
        transforms = [np.eye(4) for _ in model_paths]
    base = etree.Element("MeshLabProject")
    group = etree.SubElement(base, "MeshGroup")
    for m, l, t in zip(model_paths, labels, transforms):
        mesh = etree.SubElement(group, "MLMesh")
        mesh.set("label", l)
Clément Pinard's avatar
Clément Pinard committed
22
23
        relative_path = m.relpath(mlp_path.parent)
        mesh.set("filename", relative_path)
Clement Pinard's avatar
Clement Pinard committed
24
        matrix = etree.SubElement(mesh, "MLMatrix44")
nicolas's avatar
nicolas committed
25
        matrix.text = "\n" + "\n".join(" ".join(str(element) for element in row) + " " for row in t) + "\n"
Clement Pinard's avatar
Clement Pinard committed
26
27
28
29
30
31
32
    tree = etree.ElementTree(base)
    tree.write(mlp_path, pretty_print=True)


def remove_mesh_from_project(input_mlp, output_mlp, index):
    with open(input_mlp, "r") as f:
        to_modify = etree.parse(f)
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
    meshgroup = to_modify.getroot()[0]
    if index < len(meshgroup):
        removed = meshgroup[index]
        meshgroup.remove(removed)
    to_modify.write(output_mlp, pretty_print=True)
    transform = np.fromstring(removed[0].text, sep=" ").reshape(4, 4)
    filepath = removed.get("label")
    return transform, filepath


def get_mesh(input_mlp, index):
    with open(input_mlp, "r") as f:
        to_modify = etree.parse(f)
    meshgroup = to_modify.getroot()[0]
    if index < len(meshgroup):
        removed = meshgroup[index]
    transform = np.fromstring(removed[0].text, sep=" ").reshape(4, 4)
    filepath = removed.get("label")
    return transform, filepath


Clément Pinard's avatar
Clément Pinard committed
54
55
56
57
58
59
60
61
62
63
64
65
def get_meshes(input_mlp):
    with open(input_mlp, "r") as f:
        to_read = etree.parse(f)
    meshgroup = to_read.getroot()[0]
    meshes = []
    for mesh in meshgroup:
        transform = np.fromstring(mesh[0].text, sep=" ").reshape(4, 4)
        filepath = mesh.get("label")
        meshes.append(transform, filepath)
    return meshes


Clément Pinard's avatar
Clément Pinard committed
66
def add_meshes_to_project(input_mlp, output_mlp, model_paths, labels=None, transforms=None, start_index=-1):
Clément Pinard's avatar
Clément Pinard committed
67
68
69
70
71
72
73
74
75
    if labels is not None:
        assert(len(model_paths) == len(labels))
    else:
        labels = [m.basename() for m in model_paths]

    if transforms is not None:
        assert(len(model_paths) == len(transforms))
    else:
        transforms = [np.eye(4) for _ in model_paths]
76
77
    with open(input_mlp, "r") as f:
        to_modify = etree.parse(f)
Clement Pinard's avatar
Clement Pinard committed
78
    root = to_modify.getroot()
79
    group = root[0]
Clément Pinard's avatar
Clément Pinard committed
80
81
82
83
84
    if start_index < 0:
        start_index = len(group)
    for i, (m, l, t) in enumerate(zip(model_paths, labels, transforms)):
        mesh = etree.Element("MLMesh")
        mesh.set("label", l)
Clément Pinard's avatar
Clément Pinard committed
85
86
        relative_path = m.relpath(output_mlp.parent)
        mesh.set("filename", relative_path)
Clément Pinard's avatar
Clément Pinard committed
87
88
        matrix = etree.SubElement(mesh, "MLMatrix44")
        matrix.text = "\n" + "\n".join(" ".join(str(element) for element in row) + " " for row in t) + "\n"
Clément Pinard's avatar
bug fix    
Clément Pinard committed
89
        group.insert(start_index, mesh)
Clement Pinard's avatar
Clement Pinard committed
90
91
92
    to_modify.write(output_mlp, pretty_print=True)


nicolas's avatar
nicolas committed
93
94
95
96
97
98
99
100
101
102
103
def apply_transform_to_project(input_mlp, output_mlp, transform):
    with open(input_mlp, "r") as f:
        to_modify = etree.parse(f)
    meshgroup = to_modify.getroot()[0]
    for mesh in meshgroup:
        former_transform = np.fromstring(mesh[0].text, sep=" ").reshape(4, 4)
        new_transform = transform @ former_transform
        mesh[0].text = "\n" + "\n".join(" ".join(str(element) for element in row) + " " for row in new_transform) + "\n"
    to_modify.write(output_mlp, pretty_print=True)


Clément Pinard's avatar
Clément Pinard committed
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
parser = ArgumentParser(description='Create a meshlab project with ply files and transformations',
                        formatter_class=ArgumentDefaultsHelpFormatter)

subparsers = parser.add_subparsers(dest="operation")
create_parser = subparsers.add_parser('create')
create_parser.add_argument('--input_models', metavar='PLY', type=Path, nargs="+")
create_parser.add_argument('--output_meshlab', metavar='MLP', type=Path, required=True)
create_parser.add_argument('--transforms', metavar='TXT', type=Path, nargs="+")
create_parser.add_argument('--labels', metavar='LABEL', nargs="*")

remove_parser = subparsers.add_parser('remove')
remove_parser.add_argument('--input_meshlab', metavar='MLP', type=Path, required=True)
remove_parser.add_argument('--output_meshlab', metavar='MLP', type=Path, required=True)
remove_parser.add_argument('--index', metavar="N", type=int, default=-1)

add_parser = subparsers.add_parser('add')
add_parser.add_argument('--input_models', metavar='PLY', type=Path, nargs="+")
add_parser.add_argument('--input_meshlab', metavar='MLP', type=Path, required=True)
add_parser.add_argument('--output_meshlab', metavar='MLP', type=Path, required=True)
add_parser.add_argument('--transforms', metavar='TXT', type=Path, nargs="+")
add_parser.add_argument('--labels', metavar='LABEL', nargs="*")
add_parser.add_argument('--start_index', metavar='N', default=-1, type=int)

transform_parser = subparsers.add_parser('transform')
transform_parser.add_argument('--input_meshlab', metavar='MLP', type=Path, required=True)
transform_parser.add_argument('--output_meshlab', metavar='MLP', type=Path, required=True)
transform_parser.add_argument('--transform', metavar='TXT', type=Path, required=True)
Clément Pinard's avatar
Clément Pinard committed
131
transform_parser.add_argument('--inverse', action='store_true')
Clément Pinard's avatar
Clément Pinard committed
132
133


Clement Pinard's avatar
Clement Pinard committed
134
if __name__ == '__main__':
Clément Pinard's avatar
Clément Pinard committed
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
    args = parser.parse_args()
    if args.operation in ["add", "create"]:
        n_models = len(args.input_models)
        if args.labels is not None:
            assert n_models == len(args.labels)

        if args.transforms is None:
            transforms = [np.eye(4, 4)] * n_models
        elif len(args.transforms) == 1:
            transform = np.fromfile(args.transforms[0], sep=" ").reshape(4, 4)
            transforms = [transform] * n_models
        else:
            assert n_models == len(transforms)
            transforms = [np.fromfile(t, sep=" ").reshape(4, 4) for t in args.transforms]
        if args.operation == "create":
            create_project(args.output_meshlab, args.input_models, args.labels, transforms)
        if args.operation == "add":
Clément Pinard's avatar
Clément Pinard committed
152
153
154
155
156
157
            add_meshes_to_project(args.input_meshlab,
                                  args.output_meshlab,
                                  args.input_models,
                                  args.labels,
                                  transforms,
                                  args.start_index)
Clément Pinard's avatar
Clément Pinard committed
158
159
160
161
162
    if args.operation == "remove":
        matrix, filename = remove_mesh_from_project(args.input_meshlab, args.output_meshlab, args.index)
        print("Removed model {} with transform\n {} \nfrom meshlab".format(filename, matrix))
    if args.operation == "transform":
        transform = np.fromfile(args.transform, sep=" ").reshape(4, 4)
Clément Pinard's avatar
Clément Pinard committed
163
164
        if args.inverse:
            transform = np.linalg.inverse(transform)
Clément Pinard's avatar
Clément Pinard committed
165
        apply_transform_to_project(args.input_meshlab, args.output_meshlab, transform)