def test_smoothing(volume):
    ROUNDS = 3
    vertices, normals, faces = marching_cubes.march(volume, 0)
    smoothed_vertices, smoothed_normals, smoothed_faces = marching_cubes.march(volume, ROUNDS)

    # Compare with our reference implementation of laplacian smoothing.
    ref_smoothed_vertices = laplacian_smooth(vertices, faces, ROUNDS)
    np.allclose(smoothed_vertices, ref_smoothed_vertices, rtol=0.001)

    assert (faces == smoothed_faces).all(), \
        "Smoothing should not affect face definitions."

    assert not (normals == smoothed_normals).all(), \
        "Normals should not be the same after smoothing."
예제 #2
0
def test_c_and_f_order_agnostic(volume):
    # take a assymetric volume
    shape_z, shape_y, shape_x = volume.shape
    vol_c = np.ascontiguousarray(volume[0:shape_z // 2, 0:shape_y // 3,
                                        0:shape_x // 5])
    assert len(np.unique(vol_c.shape)) == len(vol_c.shape)
    assert vol_c.flags['C_CONTIGUOUS']
    vol_f = np.copy(vol_c, order="f")
    assert vol_f.flags['F_CONTIGUOUS']

    mesh_data_c = marching_cubes.march(vol_c, 0)
    mesh_data_h = marching_cubes.march(vol_f, 0)

    for a, b in zip(mesh_data_c, mesh_data_h):
        assert (a == b).all()
예제 #3
0
def calcMesh(stackname, labelStack, simplify):

	indices = np.where(labelStack>0)
	box, dimensions = findBBDimensions(indices)


	window = labelStack[box[0]:box[1], box[2]:box[3], box[4]:box[5]]
	localIndices = np.where(window > 0)

	paddedWindowSizeList = list(window.shape)
	paddedWindowSize = tuple([i+2 for i in paddedWindowSizeList])

	blankImg = np.zeros(paddedWindowSize, dtype=bool)

	blankImg[tuple(([i+1 for i in localIndices[0]], [i+1 for i in localIndices[1]], [i+1 for i in localIndices[2]]))] = 1
	print("Building mesh...")
	vertices, normals, faces = march(blankImg.transpose(), 3)  # zero smoothing rounds
	with open(stackname +".obj", 'w') as f:
		f.write("# OBJ file\n")

		for v in vertices:
			f.write("v %.2f %.2f %.2f \n" % ((box[0] * SCALEX) + (v[2] * SCALEX), (box[2] * SCALEY) + (v[1] * SCALEY), (box[4] * SCALEZ) + v[0] + totalZ))
		for n in normals:
			f.write("vn %.2f %.2f %.2f \n" % (n[2], n[1], n[0]))
		for face in faces:
			f.write("f %d %d %d \n" % (face[0]+1, face[1]+1, face[2]+1))
	print("Decimating Mesh...")
	largeZ = box[5]
	s = 'fq-mesh-simplify' + ' ./' + stackname +".obj ./" + stackname +".smooth.obj " + str(simplify)
	print(s)
	#subprocess.call(s, shell=True)
	return largeZ
예제 #4
0
def calcMesh(stackname, labelStack, location, simplify_ratio):
    tags = getTagDictionary(stackname)
    downsampleFactor = float(tags['downsample_interval_x'])
    xOffset = float(tags['dvid_offset_x'])
    yOffset = float(tags['dvid_offset_y'])
    zOffset = float(tags['dvid_offset_z'])
    labelStack = np.swapaxes(labelStack, 0, 2)
    print("Building mesh...")
    vertices, normals, faces = march(labelStack, 3)  # 3 smoothing rounds
    
    print('preparing vertices and faces...')
    vertStrings = ["v %.3f %.3f %.3f \n" % ((xOffset + i[0]) * downsampleFactor, (yOffset + i[1]) * downsampleFactor, (zOffset + i[2]) * downsampleFactor) for i in vertices]
    faceStrings = ["f %d %d %d \n" % (face[2]+1, face[1]+1, face[0]+1) for face in faces]
    with open(location + os.path.basename(stackname) +".obj", 'w') as f:
        f.write("# OBJ file\n")
        print("writing vertices...")
        f.write(''.join(vertStrings))
        #for n in normals:
        #    f.write("vn %.2f %.2f %.2f \n" % (n[2], n[1], n[0]))
        print("writing faces...")
        f.write(''.join(faceStrings))
    print("Decimating Mesh...")

    input_path = "./" + location + os.path.basename(stackname) +".obj"
    output_path = "./" + location + os.path.basename(stackname) +".smooth.obj"
    cmd = f'fq-mesh-simplify "{input_path}" "{output_path}" {simplify_ratio}'
    
    print(cmd)
    subprocess.call(cmd, shell=True)
예제 #5
0
파일: mesh.py 프로젝트: zheng980629/elf
def marching_cubes(obj, smoothing_iterations=0,
                   resolution=None, use_ilastik=False):
    """ Compute mesh via marching cubes.

    Arguments:
        obj [np.ndarray] - volume containing the object to be meshed
        smoothing_iterations [int] - number of mesh smoothing iterations (default: 0)
        resolution[listlike[int]] - resolution of the data (default: None)
        use_ilastik [bool] - whether to use the ilastk marching cubes implementation.
            Default is skimage (default: False)
    """
    resolution = (1., 1., 1.) if resolution is None else resolution
    if len(resolution) != 3:
        raise ValueError(f"Invalid resolution argument: {resolution}")
    resolution = tuple(resolution)

    if use_ilastik:
        if march is None:
            raise RuntimeError("Ilastik marching cubes implementation not found")
        if resolution is not None:
            raise RuntimeError("Ilastik marching cubes does not support resolution.")
        verts, normals, faces = march(obj.T, smoothing_iterations)
        verts = verts[:, ::-1]
    else:
        verts, faces, normals, _ = marching_cubes_lewiner(obj, spacing=resolution)
        if smoothing_iterations > 0:
            if nifty is None:
                raise RuntimeError("Need nifty to perform mesh smoothing")
            verts, normals = smooth_mesh(verts, normals, faces, smoothing_iterations)

    return verts, faces, normals
예제 #6
0
def calcMesh(stackname, labelStack, location, simplify, tags):
    labelStack = np.swapaxes(labelStack, 0, 2)
    print("Building mesh...")
    vertices, normals, faces = march(labelStack, 3)  # 3 smoothing rounds

    print('preparing vertices and faces...')
    newVerts = [[i[0], i[1], i[2]] for i in vertices]
    vertStrings = [
        "v %.3f %.3f %.3f \n" % (i[0], i[1], i[2]) for i in newVerts
    ]
    faceStrings = [
        "f %d %d %d \n" % (face[2] + 1, face[1] + 1, face[0] + 1)
        for face in faces
    ]
    with open(location + os.path.basename(stackname) + ".obj", 'w') as f:
        f.write("# OBJ file\n")
        print("writing vertices...")
        f.write(''.join(vertStrings))
        #for n in normals:
        #	f.write("vn %.2f %.2f %.2f \n" % (n[2], n[1], n[0]))
        print("writing faces...")
        f.write(''.join(faceStrings))
    print("Decimating Mesh...")
    s = 'fq-mesh-simplify' + ' ./' + location + os.path.basename(
        stackname) + ".obj ./" + location + os.path.basename(
            stackname) + ".smooth.obj " + str(simplify)
    print(s)
    subprocess.call(s, shell=True)
예제 #7
0
def calcMesh(stackname, labelStack, location, simplify):
    #code.interact(local=locals())
    labelStack = np.swapaxes(labelStack, 0, 2)
    print("Building mesh...")
    vertices, normals, faces = march(labelStack, 0)  # 3 smoothing rounds

    print('preparing vertices and faces...')
    #code.interact(local=locals())
    vertStrings = [
        "v %.3f %.3f %.3f \n" % (i[0] - 1, i[1] - 1, i[2] - 1)
        for i in vertices
    ]
    faceStrings = [
        "f %d %d %d \n" % (face[2] + 1, face[1] + 1, face[0] + 1)
        for face in faces
    ]
    with open(location + os.path.basename(stackname) + ".obj", 'w') as f:
        f.write("# OBJ file\n")

        print("writing vertices...")
        f.write(''.join(vertStrings))
        #for n in normals:
        #	f.write("vn %.2f %.2f %.2f \n" % (n[2], n[1], n[0]))
        print("writing faces...")
        f.write(''.join(faceStrings))
def test_regression(volume, mesh_loader, smoothing, reference_mesh_file):
    vertices, normals, faces = marching_cubes.march(volume, smoothing)

    ref_vertices, ref_normals, ref_faces = mesh_loader(reference_mesh_file)

    numpy.testing.assert_array_almost_equal(vertices, ref_vertices)
    numpy.testing.assert_array_almost_equal(normals, ref_normals)
    numpy.testing.assert_array_almost_equal(faces, ref_faces)
예제 #9
0
def test_regression(volume, mesh_loader, smoothing, reference_mesh_file):
    vertices, normals, faces = marching_cubes.march(volume, smoothing)

    ref_vertices, ref_normals, ref_faces = mesh_loader(reference_mesh_file)

    np.testing.assert_array_almost_equal(vertices, ref_vertices)
    np.testing.assert_array_almost_equal(normals, ref_normals)
    assert (faces == ref_faces).all()
예제 #10
0
def labeling_to_mesh(labeling, labels):

    for label in labels:
        vertices, normals, faces = march(where(labeling == label, 2, 0).astype(int).T, 4)
        data = MeshData(vertices, faces)
        if normals is not None:
            data._vertexNormals = normals

        yield label, data
예제 #11
0
    def GenerateStl(self, id):
        mask = (self.small_ids == id)
        vertices, normals, faces = march(mask, 2)
        print('Generated faces size: ', faces.shape)

        our_mesh = mesh.Mesh(np.zeros(faces.shape[0], dtype=mesh.Mesh.dtype))
        for i, f in enumerate(faces):
            for j in range(3):
                our_mesh.vectors[i][j] = vertices[f[j], :]

        return our_mesh
예제 #12
0
def calcMeshWithCrop(stackname, labelStack, location, simplify, tags):
    print(str(tags['downsample_interval_x']))
    SCALEX = tags['downsample_interval_x']
    SCALEY = tags['downsample_interval_x']
    SCALEZ = tags['downsample_interval_x']
    indices = np.where(labelStack > 0)
    box, dimensions = findBBDimensions(indices)

    window = labelStack[box[0]:box[1], box[2]:box[3], box[4]:box[5]]
    localIndices = np.where(window > 0)

    paddedWindowSizeList = list(window.shape)
    paddedWindowSize = tuple([i + 2 for i in paddedWindowSizeList])

    blankImg = np.zeros(paddedWindowSize, dtype=bool)

    blankImg[tuple(
        ([i + 1 for i in localIndices[0]], [i + 1 for i in localIndices[1]],
         [i + 1 for i in localIndices[2]]))] = 1
    print("Building mesh...")
    vertices, normals, faces = march(blankImg.transpose(),
                                     3)  # zero smoothing rounds
    with open(location + os.path.basename(stackname) + ".obj", 'w') as f:
        f.write("# OBJ file\n")

        for v in vertices:
            f.write("v %.2f %.2f %.2f \n" %
                    ((box[0] * SCALEX) +
                     ((float(tags['dvid_offset_x']) + v[0]) * SCALEX),
                     (box[2] * SCALEY) +
                     ((float(tags['dvid_offset_x']) + v[1]) * SCALEY),
                     (box[4] * SCALEZ) +
                     (float(tags['dvid_offset_x']) + v[2]) * SCALEZ))
        #for n in normals:
        #f.write("vn -1 -1 -1 \n")# % (n[2], n[1], n[0]))
        for face in faces:
            f.write("f %d %d %d \n" % (face[2] + 1, face[1] + 1, face[0] + 1))
    print("Decimating Mesh...")
    if os.name == 'nt':
        s = './binWindows/simplify ./' + location + os.path.basename(
            stackname) + ".obj ./" + location + os.path.basename(
                stackname) + ".smooth.obj " + str(simplify)
    else:
        if platform.system() == "Darwin":
            s = './binOSX/simplify ./' + location + os.path.basename(
                stackname) + ".obj ./" + location + os.path.basename(
                    stackname) + ".smooth.obj " + str(simplify)
        else:
            s = './binLinux/simplify ./' + location + os.path.basename(
                stackname) + ".obj ./" + location + os.path.basename(
                    stackname) + ".smooth.obj " + str(simplify)
    print(s)
    subprocess.call(s, shell=True)
예제 #13
0
def calcMeshWithOffsets(stackname, labelStack, location, simplify, tags):
    print(str(tags['downsample_interval_x']))
    downsampleFactor = float(tags['downsample_interval_x'])
    xOffset = float(tags['dvid_offset_x'])
    yOffset = float(tags['dvid_offset_y'])
    zOffset = float(tags['dvid_offset_z'])

    labelStack = np.swapaxes(labelStack, 0, 2)
    print("Building mesh...")
    try:
        vertices, normals, faces = march(labelStack, 3)  # 3 smoothing rounds
    except:
        return
    print('preparing vertices and faces...')
    newVerts = [[((xOffset + i[0]) * downsampleFactor),
                 ((yOffset + i[1]) * downsampleFactor),
                 ((zOffset + i[2]) * downsampleFactor)] for i in vertices]
    vertStrings = [
        "v %.3f %.3f %.3f \n" % (i[0], i[1], i[2]) for i in newVerts
    ]
    faceStrings = [
        "f %d %d %d \n" % (face[2] + 1, face[1] + 1, face[0] + 1)
        for face in faces
    ]
    with open(location + os.path.basename(stackname) + ".obj", 'w') as f:
        f.write("# OBJ file\n")

        print("writing vertices...")
        f.write(''.join(vertStrings))
        #for n in normals:
        #	f.write("vn %.2f %.2f %.2f \n" % (n[2], n[1], n[0]))
        print("writing faces...")
        f.write(''.join(faceStrings))
    print("Decimating Mesh...")
    if os.name == 'nt':
        s = 'binWindows\\simplify.exe ' + location[:-1] + '\\' + os.path.basename(
            stackname) + ".obj " + location[:-1] + '\\' + os.path.basename(
                stackname) + ".smooth.obj " + str(simplify)
        return
    else:
        if platform.system() == "Darwin":
            s = './binOSX/simplify ./' + location + os.path.basename(
                stackname) + ".obj ./" + location + os.path.basename(
                    stackname) + ".smooth.obj " + str(simplify)
        else:
            s = './binLinux/simplify ./' + location + os.path.basename(
                stackname) + ".obj ./" + location + os.path.basename(
                    stackname) + ".smooth.obj " + str(simplify)
    print(s)
    subprocess.call(s, shell=True)
예제 #14
0
def marching_cubes(obj, smoothing_iterations=0, use_ilastik=False):
    if use_ilastik:
        if march is None:
            raise RuntimeError(
                "Ilastik marching cubes implementation not found")
        verts, normals, faces = march(obj.T, smoothing_iterations)
        verts = verts[:, ::-1]
    else:
        verts, faces, normals, _ = marching_cubes_lewiner(obj)
        if smoothing_iterations > 0:
            verts, normals = smooth_mesh(verts, normals, faces,
                                         smoothing_iterations)

    return verts, faces, normals
예제 #15
0
 def GenerateStl(self, id):
     mask = (self.small_ids == id)
     try:
         vertices, normals, faces = march(mask, 2)
     except:
         print('Mesh was not generated.')
         return False
     print('Generated face number: ', faces.shape)
     our_mesh = mesh.Mesh(np.zeros(faces.shape[0], dtype=mesh.Mesh.dtype))
     for i, f in enumerate(faces):
         for j in range(3):
             our_mesh.vectors[i][j] = vertices[f[j], :]
     ###
     our_mesh.save(os.path.join(stldata_dir, 'i{0}.stl'.format(id)))
     return True
예제 #16
0
def calcMesh(stackname, labelStack, simplify):

	indices = np.where(labelStack>0)
	box, dimensions = findBBDimensions(indices)


	window = labelStack[box[0]:box[1], box[2]:box[3], box[4]:box[5]]
	localIndices = np.where(window > 0)

	paddedWindowSizeList = list(window.shape)
	paddedWindowSize = tuple([i+2 for i in paddedWindowSizeList])

	blankImg = np.zeros(paddedWindowSize, dtype=bool)

	blankImg[tuple(([i+1 for i in localIndices[0]], [i+1 for i in localIndices[1]], [i+1 for i in localIndices[2]]))] = 1
	print("Building mesh...")
	vertices, normals, faces = march(blankImg.transpose(), 3)  # zero smoothing rounds
	return (vertices, normals, faces, box)
예제 #17
0
def calcMeshWithOffsets(stackname, labelStack, location, simplify):
    tags = getTagDictionary(stackname)
    downsampleFactor = float(tags['downsample_interval_x'])
    xOffset = float(tags['dvid_offset_x'])
    yOffset = float(tags['dvid_offset_y'])
    zOffset = float(tags['dvid_offset_z'])

    labelStack = np.swapaxes(labelStack, 0, 2)
    print("Building mesh...")
    vertices, normals, faces = march(labelStack, 3)  # 3 smoothing rounds

    print('preparing vertices and faces...')
    newVerts = [[((xOffset + i[0]) * downsampleFactor),
                 ((yOffset + i[1]) * downsampleFactor),
                 ((zOffset + i[2]) * downsampleFactor)] for i in vertices]
    vertStrings = [
        "v %.3f %.3f %.3f \n" % (i[0] - 1.0, i[1] - 1.0, i[2] - 1.0)
        for i in newVerts
    ]
    faceStrings = [
        "f %d %d %d \n" % (face[2] + 1, face[1] + 1, face[0] + 1)
        for face in faces
    ]
    with open(location + os.path.basename(stackname) + ".obj", 'w') as f:
        f.write("# OBJ file\n")
        print("writing vertices...")
        f.write(''.join(vertStrings))
        #for n in normals:
        #	f.write("vn %.2f %.2f %.2f \n" % (n[2], n[1], n[0]))
        print("writing faces...")
        f.write(''.join(faceStrings))
    print("Decimating Mesh...")
    #if os.name == 'nt':
    #	s = 'fq-mesh-simplify' + location[:-1] + '\\' + os.path.basename(stackname) +".obj " + location[:-1] + '\\' + os.path.basename(stackname) +".smooth.obj " + str(simplify)
    #	return
    assert platform.system() in ("Darwin", "Linux"), "Windows not supported."
    s = 'fq-mesh-simplify' + ' ./' + location + os.path.basename(
        stackname) + ".obj ./" + location + os.path.basename(
            stackname) + ".smooth.obj " + str(simplify)
    print(s)
    subprocess.call(s, shell=True)
예제 #18
0
def calcMesh(stackname, labelStack, location, simplify, tags):
    labelStack = np.swapaxes(labelStack, 0, 2)
    print("Building mesh...")
    vertices, normals, faces = march(labelStack, 3)  # 3 smoothing rounds

    print('preparing vertices and faces...')
    newVerts = [[i[0], i[1], i[2]] for i in vertices]
    vertStrings = [
        "v %.3f %.3f %.3f \n" % (i[0], i[1], i[2]) for i in newVerts
    ]
    faceStrings = [
        "f %d %d %d \n" % (face[2] + 1, face[1] + 1, face[0] + 1)
        for face in faces
    ]
    with open(location + os.path.basename(stackname) + ".obj", 'w') as f:
        f.write("# OBJ file\n")
        print("writing vertices...")
        f.write(''.join(vertStrings))
        #for n in normals:
        #	f.write("vn %.2f %.2f %.2f \n" % (n[2], n[1], n[0]))
        print("writing faces...")
        f.write(''.join(faceStrings))
    print("Decimating Mesh...")
    if os.name == 'nt':
        s = 'binWindows\\simplify.exe ' + location[:-1] + '\\' + os.path.basename(
            stackname) + ".obj " + location[:-1] + '\\' + os.path.basename(
                stackname) + ".smooth.obj " + str(simplify)
        return
    else:
        if platform.system() == "Darwin":
            s = './binOSX/simplify ./' + location + os.path.basename(
                stackname) + ".obj ./" + location + os.path.basename(
                    stackname) + ".smooth.obj " + str(simplify)
        else:
            s = './binLinux/simplify ./' + location + os.path.basename(
                stackname) + ".obj ./" + location + os.path.basename(
                    stackname) + ".smooth.obj " + str(simplify)
    print(s)
    subprocess.call(s, shell=True)
예제 #19
0
from marching_cubes import march
from numpy import load
import os
import time

from pyqtgraph.opengl import GLViewWidget, MeshData
from pyqtgraph.opengl.items.GLMeshItem import GLMeshItem

from PyQt5.QtGui import QApplication

volume = load(os.path.join(
    os.path.split(__file__)[0], 'data/input/sample.npy'))

t0 = time.time()
vertices, normals, faces = march(volume, 0)  # zero smoothing rounds
smooth_vertices, smooth_normals, faces = march(volume, 4)  # 4 smoothing rounds
t1 = time.time()
print("took", t1 - t0, "sec")

app = QApplication([])
view = GLViewWidget()

mesh = MeshData(vertices / 100.0,
                faces)  # scale down - otherwise camera is misplaced
# or mesh = MeshData(smooth_vertices / 100, faces)
mesh._vertexNormals = normals
# or mesh._vertexNormals = smooth_normals

item = GLMeshItem(meshdata=mesh, color=[1, 0, 0, 1], shader="normalColor")

view.addItem(item)
예제 #20
0
    def Run(self):
        ###
        ###
        print('Export Stl Files.')

        ## Obtain biggest ID
        con = sqlite3.connect(self.u_info.segment_info_db_file)
        cur = con.cursor()
        cur.execute('select id, max(size) from segmentInfo;')
        maxid = cur.fetchone()[0]
        con.commit()
        con.close()

        #maxid = 15
        print('Obtain id: ', maxid)

        mask = (self.small_ids == maxid)

        # print('Mask was made.')
        # print('Mask Size: ', mask.shape)
        # print('Mask Type: ', mask.dtype)
        # print('Mask volume: ', np.sum(mask) )

        # plt.imshow(mask[:, :, 50])
        # plt.show()

        ## Generate mesh

        # volume = np.load( path.join(current_dir, "sample.npy")  )
        # iw = 1
        # volume = volume[::(2 ** iw), ::(2 ** iw), :]
        # print('Volume was loaded.')
        # print('Max Volme: ', np.max(volume))
        # print('Volme Size: ', volume.shape)
        # print('Volme Type: ', volume.dtype)
        # print('Volume volume: ', np.sum(volume))

        # plt.imshow(volume[:, :, 50])
        # plt.show()

        vertices, normals, faces = march(mask, 2)

        print('Faces size: ', faces.shape)

        # faces = np.array(faces)
        # vertices = np.array(vertices)

        # app = QApplication([])
        # view = GLViewWidget()
        # mesh = MeshData(vertices / 100, faces)
        # mesh._vertexNormals = normals

        # item = GLMeshItem(meshdata=mesh, color=[1, 0, 0, 1], shader="normalColor")
        # view.addItem(item)
        # view.show()
        # app.exec_()

        ##
        ##
        ##

        print('Mesh was made.')

        m.save_hdf5(path.join(pparent_dir, 'vertices.h5'), 'data', vertices)
        m.save_hdf5(path.join(pparent_dir, 'faces.h5'), 'data', normals)
        m.save_hdf5(path.join(pparent_dir, 'normals.h5'), 'data', faces)

        our_mesh = mesh.Mesh(np.zeros(faces.shape[0], dtype=mesh.Mesh.dtype))
        for i, f in enumerate(faces):
            # for j in range(3):
            #    our_mesh.vectors[i][j] = vertices[f[j], :]
            our_mesh.vectors[i][2] = vertices[f[0], :]
            our_mesh.vectors[i][1] = vertices[f[1], :]
            our_mesh.vectors[i][0] = vertices[f[2], :]
        #print('F shape: ', f.shape)
        #print('F shape: ',vertices[0, :])
        ## Export mesh

        volume, cog, inertia = our_mesh.get_mass_properties()

        our_mesh.x -= cog[0]
        our_mesh.y -= cog[1]
        our_mesh.z -= cog[2]

        our_mesh.save(path.join(pparent_dir, 'maxsize_obj.stl'))

        print('Stl was saved.')
예제 #21
0
#
#     view.addItem(item)
#     view.show()
#     app.exec_()



if __name__ == "__main__":

    # vertices, faces, normals, values = np.load("/export/home/amatskev/Bachelor/data/first_try/mesh_data.npy")

    volume=np.load("/mnt/localdata03/amatskev/neuraldata/test/difficult_volume.npy")
    print "loading finished"

    time1=time()
    vertices, normals, faces = march(volume, 0)
    time2=time()
    print time2-time1
    np.save("/mnt/localdata03/amatskev/neuraldata/test/marching_cubes1.npy",(vertices, normals, faces))



#    plot_mesh(vertices, faces)




#
# volume = np.load("/export/home/amatskev/Bachelor/data/first_try/first_try_Volume.npy")
# testvolume=np.load("/export/home/amatskev/Bachelor/marching_cubes/test/sample.npy")
# vertices, faces, normals, values = measure.marching_cubes_lewiner(volume,
예제 #22
0
def mesh_from_array(volume_zyx,
                    box_zyx,
                    downsample_factor=1,
                    simplify_ratio=None,
                    smoothing_rounds=3,
                    output_format='obj'):
    """
    Given a binary volume, convert it to a mesh in .obj format, optionally simplified.
    
    volume_zyx: Binary volume (ZYX order)
    box: Bounding box of the the volume data in global non-downsampled coordinates [(z0,y0,x0), (z1,y1,x1)]
    downsample_factor: Factor by which the given volume has been downsampled from its original size
    simplify_ratio: How much to simplify the generated mesh (or None to skip simplification)
    smoothing_rounds: Passed to marching_cubes.march()
    output_format: Either 'drc' or 'obj'
    """
    assert output_format in ('obj', 'drc'), \
        f"Unknown output format: {output_format}.  Expected one of ('obj', 'drc')"

    if simplify_ratio == 1.0:
        simplify_ratio = None

    volume_xyz = volume_zyx.transpose()
    box_xyz = np.asarray(box_zyx)[:, ::-1]

    vertices_xyz, _normals, faces = march(volume_xyz, smoothing_rounds)

    # Rescale and translate
    vertices_xyz[:] *= downsample_factor
    vertices_xyz[:] += box_xyz[0]

    # I don't understand why we write face vertices in reverse order...
    # ...does marching_cubes give clockwise order instead of counter-clockwise?
    # Is it because we passed a fortran-order array?
    faces = faces[:, ::-1]
    faces += 1

    mesh_stream = generate_obj(vertices_xyz, faces)

    child_processes = []

    try:
        if simplify_ratio is not None:
            simplify_input_pipe = TemporaryNamedPipe('input.obj')
            simplify_input_pipe.start_writing_stream(mesh_stream)

            simplify_output_pipe = TemporaryNamedPipe('output.obj')

            cmd = f'fq-mesh-simplify {simplify_input_pipe.path} {simplify_output_pipe.path} {simplify_ratio}'
            child_processes.append((cmd, subprocess.Popen(cmd, shell=True)))
            mesh_stream = simplify_output_pipe.open_stream('rb')

        if output_format == 'drc':
            # Sadly, draco is incapable of reading from non-seekable inputs.
            # It requires an actual input file, so we can't use a named pipe to avoid disk I/O.
            # But at least we can use a pipe for the output...
            mesh_dir = AutoDeleteDir(tempfile.mkdtemp())
            mesh_path = f'{mesh_dir}/mesh.obj'
            with open(mesh_path, 'wb') as mesh_file:
                copyfileobj(mesh_stream, mesh_file)
            draco_output_pipe = TemporaryNamedPipe('output.drc')

            cmd = f'draco_encoder -cl 5 -i {mesh_path} -o {draco_output_pipe.path}'
            child_processes.append((cmd, subprocess.Popen(cmd, shell=True)))
            mesh_stream = draco_output_pipe.open_stream('rb')

        return mesh_stream.read()

    finally:
        # Explicitly wait() for the child processes
        # (avoids a warning from subprocess.Popen.__del__)
        for cmd, proc in child_processes:
            proc.wait(timeout=1.0)
            if proc.returncode != 0:
                raise RuntimeError(
                    f"Child process returned an error code: {proc.returncode}.\n"
                    f"Command was: {cmd}")
예제 #23
0
from marching_cubes import march
from numpy import load
import os
import time

from pyqtgraph.opengl import GLViewWidget, MeshData
from pyqtgraph.opengl.items.GLMeshItem import GLMeshItem

from PyQt5.QtGui import QApplication


volume = load(os.path.join(os.path.split(__file__)[0], 'data/input/sample.npy'))


t0 = time.time()
vertices, normals, faces = march(volume, 0)  # zero smoothing rounds
smooth_vertices, smooth_normals, faces = march(volume, 4)  # 4 smoothing rounds
t1 = time.time()
print("took", t1 - t0, "sec")

app = QApplication([])
view = GLViewWidget()

mesh = MeshData(vertices / 100.0, faces)  # scale down - otherwise camera is misplaced
# or mesh = MeshData(smooth_vertices / 100, faces)
mesh._vertexNormals = normals
# or mesh._vertexNormals = smooth_normals

item = GLMeshItem(meshdata=mesh, color=[1, 0, 0, 1], shader="normalColor")

view.addItem(item)