예제 #1
0
    def save_mesh(self, mesh, out_file, digits=10):
        '''
        Saving meshes to OFF file

        '''
        digits = int(digits)
        # prepend a 3 (face count) to each face
        if mesh.visual.face_colors is None:
            faces_stacked = np.column_stack((
                np.ones(len(mesh.faces)) * 3,
                mesh.faces)).astype(np.int64)
        else:
            assert(mesh.visual.face_colors.shape[0] == mesh.faces.shape[0])
            faces_stacked = np.column_stack((
                np.ones(len(mesh.faces)) * 3,
                mesh.faces, mesh.visual.face_colors[:, :3])).astype(np.int64)
        export = 'OFF\n'
        # the header is vertex count, face count, edge number
        export += str(len(mesh.vertices)) + ' ' + str(len(mesh.faces)) + ' 0\n'
        export += array_to_string(
            mesh.vertices, col_delim=' ', row_delim='\n', digits=digits) + '\n'
        export += array_to_string(faces_stacked, col_delim=' ', row_delim='\n')

        with open(out_file, 'w') as f:
            f.write(export)

        return mesh
예제 #2
0
def export_clusterwavefront(mesh_,
                            dest,
                            fs_clust,
                            num_clust,
                            colors,
                            name="mesh"):
    '''
        Export obj file of mesh segmentation assigning a color per instance
        Args:
            mesh_       : the raw mesh (trimesh module)
            dest        : folder path to export obj file
            fs_clust    : instance indices per face
            num_clust   : number of instances in the mesh
            colors      : list of RGB colors
            name        : name of obj file
    '''
    ## assign color per instance
    all_colors = []
    times = int(num_clust / 180) + 1
    for i in range(times):
        if i == 0:
            all_colors = colors
        else:
            all_colors = np.concatenate((all_colors, colors), axis=0)
    ## translate this into materials and export an MTL file
    materials = {}
    materials['name'] = []
    materials['color'] = []
    un_clusts = list(set(fs_clust))
    for i, v in enumerate(un_clusts):
        if v == -1:
            materials['name'].append("empty")
            materials['color'].append([255, 255, 255])
        else:
            materials['name'].append(str(v))
            materials['color'].append(all_colors[i + 1])
    export_mtl(materials, os.path.join(dest, name + ".mtl"))
    ## export OBJ file
    file = open(os.path.join(dest, name + ".obj"), "w")
    file.write("mtllib " + name + ".mtl\n")
    # save vertices
    v_ = 'v '
    v_ += util.array_to_string(
        mesh_.vertices, col_delim=' ', row_delim='\nv ', digits=8) + '\n'
    file.write(v_)
    # save faces
    file.write("g Mesh\n")
    uniq_clust = np.unique(fs_clust)
    for clust_ in uniq_clust:
        locs = np.transpose(np.array(np.where(fs_clust == clust_)[0]))
        if clust_ == -1:
            continue
        file.write("usemtl " + str(clust_) + "\n")
        for loc_ in locs:
            face = mesh_.faces[loc_, :]
            file.write("f ")
            for f in face:
                file.write(str(f + 1) + " ")
            file.write("\n")
    file.close()
예제 #3
0
def export_wavefront(mesh_,
                     dest,
                     fs_class,
                     classes,
                     cat2ind,
                     ind2cat,
                     class2col,
                     colors,
                     name="mesh"):
    '''
        Export obj file of mesh segmentation assigning a color per object class
        Args:
            mesh_       : the raw mesh (trimesh module)
            dest        : folder path to export obj file
            fs_class    : object labels per face
            classes     : list of classes in the mesh
            cat2ind     : maps object labels (string) to unique IDs
            ind2cat     : maps object class IDs to unique labels (string)
            class2col   : maps object classes to a unique color ID
            colors      : list of RGB colors
            name        : name of obj file
    '''
    ## get materials and export MTL files
    material = get_materials(classes, colors)
    name = name + "_class"
    export_mtl(material, os.path.join(dest, name + ".mtl"))
    ## export OBJ file
    file = open(os.path.join(dest, name + ".obj"), "w")
    file.write("mtllib " + name + ".mtl\n")
    # save vertices
    v_ = 'v '
    v_ += util.array_to_string(
        mesh_.vertices, col_delim=' ', row_delim='\nv ', digits=8) + '\n'
    file.write(v_)
    # save faces
    file.write("g Mesh\n")
    uniq_class = np.unique(fs_class)
    for class_ in uniq_class:
        locs = np.transpose(np.array(np.where(fs_class == class_)[0]))
        if class_ == -1:
            file.write("usemtl empty" + "\n")
        else:
            file.write("usemtl " + ind2cat[class_] + "\n")
        for loc_ in locs:
            face = mesh_.faces[loc_, :]
            file.write("f ")
            for f in face:
                file.write(str(f + 1) + " ")
            file.write("\n")
    file.close()
예제 #4
0
def export_ply(mesh,
               faces_labels=None,
               vertex_labels=None,
               label_field_name='label',
               label_type='ushort',
               encoding='binary',
               vertex_normal=None):
    """
    Export a mesh to the PLY format including labels.

    Parameters
    ----------
    mesh : Trimesh object
    encoding : ['ascii'|'binary_little_endian']
    vertex_normal : include vertex normals

    Returns
    -------
    export : bytes of result


    Notes
    -----
    Based on `trimesh.exchange.ply.export_ply`
    https://github.com/mikedh/trimesh/blob/master/trimesh/exchange/ply.py

    """
    # evaluate input args
    # allow a shortcut for binary
    if encoding == 'binary':
        encoding = 'binary_little_endian'
    elif encoding not in ['binary_little_endian', 'ascii']:
        raise ValueError('encoding must be binary or ascii')
    # if vertex normals aren't specifically asked for
    # only export them if they are stored in cache
    if vertex_normal is None:
        vertex_normal = 'vertex_normal' in mesh._cache

    is_multilabels = isinstance(label_field_name, list) or isinstance(
        label_field_name, tuple)

    # custom numpy dtypes for exporting
    dtype_face = [('count', '<u1'), ('index', '<i4', (3))]
    dtype_vertex = [('vertex', '<f4', (3))]
    # will be appended to main dtype if needed
    dtype_vertex_normal = ('normals', '<f4', (3))
    dtype_color = ('rgba', '<u1', (4))

    if label_type == 'char':
        dtype_label = ('label', '<i1')
        dtype_label_numpy = np.int8  # TODO: check it
    elif label_type == 'ushort':
        if is_multilabels:
            dtype_label = []
            for i, lfn in enumerate(label_field_name):
                dtype_label.append(('label_' + str(i), '<u2'))
            dtype_label_numpy = np.uint16
        else:
            dtype_label = ('label', '<u2')
            dtype_label_numpy = np.uint16

    if faces_labels is not None:
        assert faces_labels.dtype == dtype_label_numpy, faces_labels.dtype
    if vertex_labels is not None:
        assert vertex_labels.dtype == dtype_label_numpy, vertex_labels.dtype

    # get template strings in dict
    templates = json.loads(get_resource('ply.template'))
    # append labels in template
    if is_multilabels:
        for i, lfn in enumerate(label_field_name):
            templates['label_' + str(i)] = 'property {} {}\n'.format(
                label_type, lfn)
    else:
        templates['label'] = 'property {} {}\n'.format(label_type,
                                                       label_field_name)

    # start collecting elements into a string for the header
    header = templates['intro']
    header += templates['vertex']

    # if we're exporting vertex normals add them
    # to the header and dtype
    if vertex_normal:
        header += templates['vertex_normal']
        dtype_vertex.append(dtype_vertex_normal)

    # if mesh has a vertex coloradd it to the header
    if mesh.visual.kind == 'vertex' and encoding != 'ascii':
        header += templates['color']
        dtype_vertex.append(dtype_color)
    if vertex_labels is not None and encoding != 'ascii':
        if is_multilabels:
            for i, lfn in enumerate(label_field_name):
                header += templates['label_' + str(i)]
                dtype_vertex.append(dtype_label[i])
        else:
            header += templates['label']
            dtype_vertex.append(dtype_label)

    # create and populate the custom dtype for vertices
    vertex = np.zeros(len(mesh.vertices), dtype=dtype_vertex)
    vertex['vertex'] = mesh.vertices
    if vertex_normal:
        vertex['normals'] = mesh.vertex_normals
    if mesh.visual.kind == 'vertex':
        vertex['rgba'] = mesh.visual.vertex_colors
    if vertex_labels is not None and encoding != 'ascii':
        if is_multilabels:
            for i, lfn in enumerate(label_field_name):
                vertex['label_' + str(i)] = vertex_labels[:, i]
        else:
            vertex['label'] = vertex_labels

    header += templates['face']
    if mesh.visual.kind == 'face' and encoding != 'ascii':
        header += templates['color']
        dtype_face.append(dtype_color)

    if faces_labels is not None and encoding != 'ascii':
        header += templates['label']
        dtype_face.append(dtype_label)

    # put mesh face data into custom dtype to export
    faces = np.zeros(len(mesh.faces), dtype=dtype_face)
    faces['count'] = 3
    faces['index'] = mesh.faces
    if mesh.visual.kind == 'face' and encoding != 'ascii':
        faces['rgba'] = mesh.visual.face_colors
    if faces_labels is not None and encoding != 'ascii':
        faces['label'] = faces_labels

    header += templates['outro']

    header_params = {
        'vertex_count': len(mesh.vertices),
        'face_count': len(mesh.faces),
        'encoding': encoding
    }

    export = Template(header).substitute(header_params).encode('utf-8')

    if encoding == 'binary_little_endian':
        export += vertex.tostring()
        export += faces.tostring()
    elif encoding == 'ascii':
        raise NotImplementedError()
        # ply format is: (face count, v0, v1, v2)
        fstack = np.column_stack(
            (np.ones(len(mesh.faces), dtype=np.int64) * 3, mesh.faces))

        # if we're exporting vertex normals they get stacked
        if vertex_normal:
            vstack = np.column_stack((mesh.vertices, mesh.vertex_normals))
        else:
            vstack = mesh.vertices

        # add the string formatted vertices and faces
        _s = util.array_to_string(vstack, col_delim=' ', row_delim='\n')
        _s += '\n'
        _s += util.array_to_string(fstack, col_delim=' ', row_delim='\n')
        export += _s.encode('utf-8')
    else:
        raise ValueError('encoding must be ascii or binary!')

    return export