def cutMeshInHalf(mesh): half1 = msh.Mesh() half2 = msh.Mesh() half1.verts = mesh.verts half2.verts = mesh.verts mid = (np.max(mesh.verts[:, 0]) + np.min(mesh.verts[:, 0])) / 2. vertsMask = [v[0] < mid for v in mesh.verts] mask = [1 for i in range(len(mesh.tris))] for i, t in enumerate(mesh.tris): for v in t[:3]: mask[i] = vertsMask[v] half1.tris = np.array([t for i, t in enumerate(mesh.tris) if mask[i]]) half2.tris = np.array([t for i, t in enumerate(mesh.tris) if not mask[i]]) del mesh half1.discardUnused() half2.discardUnused() half2.verts[:, 0] = 1 - half2.verts[:, 0] half2.computeBBox() half1.applyMatrix(half1.toUnitMatrix()) half2.applyMatrix(half2.toUnitMatrix()) return half1, half2
def saveSubdivision(self, inds, outfile, point=None, wholeDomain=None): #Retaining the tetra of the considered subdivision tetraMesh = msh.Mesh(self.mesh.path) tetraMesh.readSol() for t in self.tetras[inds[0]][inds[1]][inds[2]]: tetraMesh.tets[t,-1]=10 for ind in range(10): tetraMesh.removeRef(ind) tetraMesh.tris = np.array([]) tetraMesh.discardUnused() #Creating a cube of the subdivision boundaries div = self.mesh.dims/8 mins = [self.mesh.xmin + inds[0]*div[0], self.mesh.ymin + inds[1]*div[1], self.mesh.zmin + inds[2]*div[2]] boundaryMesh=msh.Mesh(cube=[mins[0], mins[0]+div[0], mins[1], mins[1]+div[1], mins[2], mins[2]+div[2]]) boundaryMesh.replaceRef(0,2) tetraMesh.fondre(boundaryMesh) #Creating a cube around the point if point is not None: off = 0.01 point = msh.Mesh(cube=[point[0]-off, point[0]+off, point[1]-off, point[1]+off, point[2]-off, point[2]+off]) point.replaceRef(0,1) tetraMesh.fondre(point) #Creating a box of the whole domain if wholeDomain is not None: domain = msh.Mesh(cube=[self.mesh.xmin, self.mesh.xmax, self.mesh.ymin, self.mesh.ymax, self.mesh.zmin, self.mesh.zmax]) tetraMesh.fondre(domain) #Writing the file tetraMesh.write(outfile) tetraMesh.writeSol(outfile[:-5]+".sol")
def cleanMesh(f): mesh = msh.Mesh() mesh.get_infos(f) nV = mesh.numItems[0] nT = mesh.numItems[1] if nV > nT: mesh = msh.Mesh(f) mesh.discardDuplicateVertices() mesh.discardUnused() mesh.write(f)
def adapt_box_to(f, maxNb=30000): cube = msh.Mesh("/home/norgeot/box.mesh") mesh = msh.Mesh(f) step = 1 if len(mesh.verts)<maxNb else int(len(mesh.verts)/maxNumPoints)+1 dists, _ = nearest_neighbor(cube.verts[:,:3], mesh.verts[::step,:3]) cube.scalars = np.array(dists) cube.scaleSol(0.002, 1, absolute=True) cube.write("cube.mesh") cube.writeSol("cube.sol") err = os.system("mmg3d_O3 cube.mesh -o cube.o.mesh -hgrad 1.5") if err: raise IOError("mmg3d failure")
def adapt_box_to(f, maxNb=20000): shutil.copyfile(templates["box"], "box.mesh") cube = msh.Mesh("box.mesh") mesh = msh.Mesh(f) step = 1 if len(mesh.verts) < maxNb else int(len(mesh.verts) / maxNb) + 1 dists, _ = nearest_neighbor(cube.verts[:, :3], mesh.verts[::step, :3]) cube.scalars = np.array(dists) cube.scaleSol(0.001, 0.5, absolute=True) cube.write("box.1.mesh") cube.writeSol("box.1.sol") err = os.system("mmg3d_O3 box.1.mesh -hgrad 1.5 > /dev/null 2>&1") if err: raise FacileError("mmg3d failure")
def cut(f): mesh = msh.Mesh(os.path.join(directories["raw"], f)) MAT = mesh.toUnitMatrix() mesh.applyMatrix(MAT) newF = os.path.join(directories["muscles"], f[:-5] + ".scaled.mesh") mesh.write(newF) err = remesh(newF, hausd=0.001) mesh = msh.Mesh( os.path.join(directories["muscles"], f[:-5] + ".scaled.o.mesh")) half1, half2 = cutMeshInHalf(mesh) half1.write(os.path.join(directories["muscles"], f[:-5] + ".R.mesh")) half2.write(os.path.join(directories["muscles"], f[:-5] + ".L.mesh")) os.remove(os.path.join(directories["muscles"], f[:-5] + ".scaled.mesh")) os.remove(os.path.join(directories["muscles"], f[:-5] + ".scaled.o.mesh")) os.remove(os.path.join(directories["muscles"], f[:-5] + ".scaled.o.sol"))
def scale(g): faceFile = [f for f in g if "face" in f][0] boneFiles = [f for f in g if f != faceFile and "mass" not in f] bone = msh.Mesh(os.path.join(directories["raw"], boneFiles[0])) if len(boneFiles) > 1: for f in boneFiles[1:]: bone.fondre(msh.Mesh(os.path.join(directories["raw"], f))) center = bone.center scale = 0.0035 for f in g: mesh = msh.Mesh(os.path.join(directories["raw"], f)) mesh.verts[:, :3] -= center mesh.verts[:, :3] *= scale mesh.verts[:, :3] += [0.5, 0.5, 0.5] mesh.write(os.path.join(directories["scaled"], f))
def warp(f): num = f.split("/")[-1][:3] os.system("cp " + templates["sphere"] + " ./sphere.mesh") err = os.system(exe.warping + " " + f + " -p -nit 150 -load 40 > warping.txt") if err: raise FacileError("Warping failure") """ try: mesh = msh.Mesh(f) mesh.tris = np.array([ t for t in mesh.tris if np.max(t)<=len(mesh.verts) ]) mesh.discardUnused() mesh.write(f) err = os.system( exe.warping + " " + f + " -p -nit 150 -load 40 > warping.txt" ) if err: raise FacileError("cleaned warping failure") except: raise FacileError("warping failure") """ warped = msh.Mesh("sphere.d.mesh") ext_ref = 2 warped.tris = warped.tris[warped.tris[:, -1] != ext_ref] warped.tets = np.array([]) warped.discardUnused() warped.write( os.path.join(directories["warped"], f.split("/")[-1].split(".")[0] + ".warped.mesh")) return 0
def signedDistance(f): adapt = True if adapt: adapt_box_to(f) else: cube = msh.Mesh(cube=[0, 1, 0, 1, 0, 1]) cube.write("box.mesh") err = os.system(exe.tetgen + " -pgANEF box.mesh > /dev/null 2>&1") if err: raise FacileError('tetgen failure') err = os.system(exe.mmg3d + " box.1.mesh -hausd 0.04 -hmax 0.04 > /dev/null 2>&1") if err: raise FacileError('mmg3d failure') err = os.system(exe.mshdist + " -ncpu 16 -noscale box.1.o.mesh " + f + " > /dev/null 2>&1") if err: raise FacileError('mshdist failure') name = f.split("/")[-1].split(".")[0] os.system("mv box.1.o.mesh " + os.path.join(directories["signed"], name + ".mesh")) os.system("mv box.1.o.sol " + os.path.join(directories["signed"], name + ".sol")) return 0
def alignToTemplate(f): num = f.split("/")[-1][:3] err = 0 """ if "mass" in f: err = os.system(exe.align + " -i " + f + " " + templates["masseter"] + " -d 0.1 -o 0.95 > "+num+"_mass.txt")#/dev/null 2>&1") elif "mand" in f: err = os.system(exe.align + " -i " + f + " " + templates["mandible"] + " -d 0.1 -o 0.95 > "+num+"_mand.txt")#/dev/null 2>&1") if err: print "-- Error aligning " + boneFile """ mesh = msh.Mesh(f) #mesh.applyMatrix(matFile = "mat_Super4PCS.txt") #mesh.applyMatrix(matFile = "mat_ICP.txt") #mesh.write(f[:-5]+".aligned.mesh") todo = f #f[:-5]+".aligned.mesh" if "mass" in f: err = os.system(exe.pythonICP + " -s " + todo + " -t " + templates["masseter"] + " -m mat_pyICP.txt >> " + num + "_mass.txt") elif "mand" in f: err = os.system(exe.pythonICP + " -s " + todo + " -t " + templates["mandible"] + " -m mat_pyICP.txt >> " + num + "_mand.txt") if err: print "-- Error with ICP for " + f else: mesh.applyMatrix(matFile="mat_pyICP.txt") mesh.write(f) print "Successfully aligned " + f return 0
def cleanWithMeshlab(f, new=None): mesh = msh.Mesh(f) mesh.writeOBJ("tmp.obj") err = os.system("LC_ALL=C meshlabserver -i tmp.obj -o cleaned.obj -s " + intScript + " > /dev/null 2>&1") if err: raise FacileError("meshlab failure") mesh = obj2Mesh("cleaned.obj") if new is not None: mesh.write(new) else: mesh.write(f)
def obj2Mesh(file): with open(file, "r") as f: LINES = f.readlines() mesh = msh.Mesh() mesh.verts = np.array([[float(x) for x in l.split()[1:]] for l in LINES if l[0] == "v"]) mesh.tris = np.array([[int(x) - 1 for x in l.split()[1:]] for l in LINES if l[0] == "f"]) mesh.verts = np.insert(mesh.verts, 3, 0, axis=1) mesh.tris = np.insert(mesh.tris, 3, 0, axis=1) mesh.computeBBox() return mesh
def fondreAndScale(inputDir, outputDir, group): des = " ".join(group) # face + bone if "face" in des and "bone" in des and len(group) == 2: boneFile = None #Scale and remesh for f in group: infile = os.path.join(inputDir, f) outfile = os.path.join(outputDir, f) mesh = msh.Mesh(infile) mesh.verts[:, :3] -= mesh.center mesh.verts[:, :3] *= 0.0035 mesh.verts[:, :3] += [0.5, 0.5, 0.5] mesh.computeBBox() mesh.write(outfile) if "bone" in f: boneFile = os.path.join(outputDir, f[:-5] + ".o.mesh") command(exe.mmgs + " " + outfile + " -o " + outfile[:-5] + ".o.mesh -nr -hausd 0.007", displayOutput=True) #Align following the skull templateFile = "/home/norgeot/dev/own/FaciLe/OsTemplate.mesh" command(exe.align + " -i " + boneFile + " " + templateFile + " -d 0.1 -o 0.95", displayOutput=True) os.system("mv mat_Super4PCS.txt " + os.path.join(outputDir, f[:3] + "_mat_1_super4pcs.txt")) os.system("mv mat_ICP.txt " + os.path.join(outputDir, f[:3] + "_mat_2_cppICP.txt")) for f in group: mesh = msh.Mesh(os.path.join(outputDir, f[:-5] + ".o.mesh")) mesh.applyMatrix( matFile=os.path.join(outputDir, f[:3] + "_mat_1_super4pcs.txt")) mesh.applyMatrix(matFile=os.path.join(outputDir, f[:3] + "_mat_2_cppICP.txt")) mesh.write(f[:-5] + ".o.mesh")
def align(g): boneFile = [f for f in g if "bone" in f][0] faceFile = [f for f in g if "face" in f][0] massFile = [f for f in g if "mass" in f][0] if "mass" in "".join(g) else "" num = boneFile.split("/")[-1][:3] err = os.system(exe.align + " -i " + boneFile + " " + templates["bone"] + " -d 0.1 -o 0.95 > " + num + ".txt") #/dev/null 2>&1") if err: raise FacileError("alignement failure") bone = msh.Mesh(boneFile) bone.applyMatrix(matFile="mat_Super4PCS.txt") bone.applyMatrix(matFile="mat_ICP.txt") bone.write(os.path.join(directories["aligned"], num + "_bone.mesh")) err = os.system(exe.pythonICP + " -s " + os.path.join(directories["aligned"], num + "_bone.mesh") + " -t " + templates["bone"] + " -m mat_pyICP.txt >> " + num + ".txt") if err: pass # Cannot run python alignement... else: bone.applyMatrix(matFile="mat_pyICP.txt") bone.write(os.path.join(directories["aligned"], num + "_bone.mesh")) face = msh.Mesh(faceFile) face.applyMatrix(matFile="mat_Super4PCS.txt") face.applyMatrix(matFile="mat_ICP.txt") if not err: face.applyMatrix(matFile="mat_pyICP.txt") face.write(os.path.join(directories["aligned"], num + "_face.mesh")) if ".mesh" in massFile: mass = msh.Mesh(massFile) mass.applyMatrix(matFile="mat_Super4PCS.txt") mass.applyMatrix(matFile="mat_ICP.txt") if not err: mass.applyMatrix(matFile="mat_pyICP.txt") mass.write(os.path.join(directories["aligned"], num + "_mass.mesh")) return 0
def merge(g): newBone = os.path.join(directories["merged"], g[0][:3] + "_bone.mesh") newFace = os.path.join(directories["merged"], g[0][:3] + "_face.mesh") newMass = os.path.join(directories["merged"], g[0][:3] + "_mass.mesh") faceFile = [f for f in g if "face" in f][0] face = msh.Mesh(os.path.join(directories["remeshed"], faceFile)) boneFiles = [f for f in g if f != faceFile and "mass" not in f] if len(boneFiles) == 0: return 1 bone = msh.Mesh(os.path.join(directories["remeshed"], boneFiles[0])) if len(boneFiles) > 1: for f in boneFiles[1:]: bone.fondre(msh.Mesh(os.path.join(directories["remeshed"], f))) if "mass" in "".join(g): mass = msh.Mesh( os.path.join(directories["remeshed"], [f for f in g if "mass" in f][0])) mass.write(newMass) bone.write(newBone) face.write(newFace)
def morph(g, nit=400): """ g[0] = path to the signed distance g[1] = path to the template mesh """ signedDist = g[0] templateMesh = g[1] os.system("cp " + templateMesh + " template.mesh") dRef = [2] #Fixed surface inside the template elRef = [2] #Elements inside the fixed surface bRef = [] #Follower elements cmd = " ".join(( "morphing", " -dref " + str(len(dRef)) + " " + " ".join([str(d) for d in dRef]), " -elref " + str(len(elRef)) + " " + " ".join([str(d) for d in elRef]), #" -bref " + str(len(bRef)) + " " + " ".join([str(d) for d in bRef]), " -nit " + str(nit), " " + signedDist, " template.mesh", " > /dev/null 2>&1")) #print cmd if True: err = os.system(cmd) if err: raise FacileError("morphing failure") name = signedDist.split("/")[-1].split(".")[0] newMesh = os.path.join(directories["morphed"], name + ".mesh") newSol = os.path.join(directories["morphed"], name + ".sol") os.system("mv " + signedDist[:-5] + ".1.mesh " + newMesh) os.system("mv " + signedDist[:-5] + ".1.depl.sol " + newSol) mesh = msh.Mesh(newMesh) mesh.readSol(newSol) mesh.tets = np.array([]) mesh.discardUnused() mesh.write(newMesh) mesh.writeSol(newSol)
sys.exit() if not os.path.splitext(args.output)[1] == ".mesh": print "Output file must be in the .mesh format" sys.exit() if args.resolution < 11 or args.resolution > 301: print "The resolution must be in [11, 301]" sys.exit() if __name__ == "__main__": args = parse() checkArgs(args) print "1 - Converting .mesh to binary .xyz" print "- 1.1 - Opening the mesh file" mesh = msh.Mesh(args.input) print "- 1.2 - Converting to binary point data" binaryData, totalScale = ptsToXYZCubes(mesh.verts, args.resolution) print "2 - Creating the filled volume" print "- 2.1 - Space carving" newData = spaceCarve(binaryData) newData = nd.binary_closing(newData, structure=nd.generate_binary_structure(3, 3), iterations=3) print "- 2.2 - Marching cubes" verts, faces, _, _ = mea.marching_cubes_lewiner(volume=newData, level=0.5) recon = msh.Mesh() recon.verts = np.insert(np.array(verts), 3, 0, axis=1) recon.tris = np.insert(np.array(faces), 3, 0, axis=1) recon.computeBBox()
point.replaceRef(0,1) tetraMesh.fondre(point) #Creating a box of the whole domain if wholeDomain is not None: domain = msh.Mesh(cube=[self.mesh.xmin, self.mesh.xmax, self.mesh.ymin, self.mesh.ymax, self.mesh.zmin, self.mesh.zmax]) tetraMesh.fondre(domain) #Writing the file tetraMesh.write(outfile) tetraMesh.writeSol(outfile[:-5]+".sol") if __name__ == "__main__": print "1 - Opening the .mesh file and the corresponding .sol file" t = time.time() mesh = msh.Mesh("demo/snailbox3d1.mesh") mesh.readSol() print "Mesh reading in", time.time() - t,"s." print "2 - Creating the octree structure" t = time.time() octree = Octree(mesh, 3) print "Octree structure created in", time.time() - t,"s." print "3 - Computing the streamlines" t = time.time() #Parameters nPoints = 10 maxIt = 100 step = 0.02 #First points
required=True) parser.add_argument("-o", "--output", help="transformed .mesh file", type=str, required=True) return parser.parse_args() def checkArgs(args): if not os.path.isfile(args.input): print args.input + " is not a valid file" sys.exit() if not os.path.splitext(args.input)[1] == ".mesh": print args.input + " is not a .mesh file" sys.exit() if not os.path.isfile(args.matrix): print args.matrix + " is not a valid file" sys.exit() if not os.path.splitext(args.output)[1] == ".mesh": print "Output file must be in the .mesh format" sys.exit() if __name__ == "__main__": args = parse() checkArgs(args) mesh = msh.Mesh(args.input) mesh.applyMatrix(matFile=args.matrix) mesh.write(args.output)
if displayOutput: err = os.system(cmd) else: err = os.system(cmd + " > tmp_out.txt 2>tmp_err.txt") if err: print "An error happened while executing:\n" + cmd + "\nLook in tmp_out.txt or tmp_err.txt for info\nExiting..." sys.exit() else: os.system("rm tmp_out.txt tmp_err.txt >/dev/null 2>&1") if __name__ == "__main__": """ Suppose we are between 0 and 1 for a skull and take a wrapped mesh """ args = parse() checkArgs(args) #command("mmgs_O3 " + sys.argv[1] + " -nr -o out.mesh") #mesh = msh.Mesh("out.mesh") mesh = msh.Mesh(args.input) ico = msh.Mesh(ico=[args.center, args.radius]) ico.tris[:, -1] = 10 mesh.fondre(ico) mesh.write("out.mesh") command("tetgen -pgANEF out.mesh") command("mmg3d_O3 out.1.mesh -nosurf -o " + args.output) command("rm out.mesh out.1.mesh")
import msh import sys # Import, modify and save a .mesh as .vtk file if __name__ == "__main__": if len(sys.argv) != 2: print("The script takes a .mesh file as only argument!") sys.exit() mesh = msh.Mesh(sys.argv[1]) mesh.readSol() mesh.writeVTK(sys.argv[1][:-4] + "vtk") print("Paraview file written to " + sys.argv[1][:-4] + "vtk")
import msh if __name__ == "__main__": #Read the geometry .mesh file (triangles and tetrahedra) mesh = msh.Mesh("demo/Theatre.mesh") #Read the .sol file for associated solution fields mesh.readSol() #Prints the info about the mesh mesh.caracterize() #Exports the mesh in different formats mesh.verts += [100., 100., 100., 0] mesh.writeXYZ("demo/Theatre.xyz") mesh.writeSTL("demo/Theatre.stl") mesh.writeOBJ("demo/Theatre.obj") mesh.writeVTK("demo/Theatre.vtk")
if __name__ == "__main__": args = parse() checkArgs(args) # 3 - Align to the template full mandibule command(exe.align + " -i " + args.input + " " + args.template + " -d 50 -o 0.95", displayOutput=True) command(exe.pythonICP + " -s " + args.input + " -t " + args.template + " -m mat_PythonICP.txt") # 1 - Reading the input file fullMandible = msh.Mesh(args.input) fullMandible.applyMatrix(matFile="mat_Super4PCS.txt") fullMandible.applyMatrix(matFile="mat_PythonICP.txt") # 2 - Scale to [0,1] MAT = fullMandible.toUnitMatrix() np.savetxt("mat_toUnit.txt", MAT) fullMandible.applyMatrix(mat=MAT) fullMandible.write("mandible.mesh") # 4 - Cut the mandible in two rightMandible = deepcopy(fullMandible) leftMandible = fullMandible #Generate the mask mask = [1 for i in range(len(leftMandible.tris))] mid = np.mean(leftMandible.verts, axis=0)[0]
if not os.path.splitext(args.source)[1] == ".mesh": print args.source + " is not a .mesh file" sys.exit() if not os.path.isfile(args.target): print args.target + " is not a valid file" sys.exit() if not os.path.splitext(args.target)[1] == ".mesh": print args.target + " is not a .mesh file" sys.exit() if not os.path.splitext(args.matrix)[1] == ".txt": print "Output file must be in the .txt format" sys.exit() if __name__ == "__main__": args = parse() checkArgs(args) sourceMesh = msh.Mesh(args.source) targetMesh = msh.Mesh(args.target) sourceStep = len(sourceMesh.verts)/args.maxPoints+1 targetStep = len(targetMesh.verts)/args.maxPoints+1 sourceVerts = sourceMesh.verts[::sourceStep,:-1] targetVerts = targetMesh.verts[::targetStep,:-1] MAT, dist = icp(sourceVerts, targetVerts, max_iterations=args.maxIterations, tolerance=args.tolerance) writeMatrixToFile(MAT, args.matrix)
def command(cmd, displayOutput=False): err = os.system(cmd) if displayOutput else os.system(cmd + " > tmp_out.txt 2>tmp_err.txt") if err: print "An error happened while executing:\n"+cmd+"\nLook in tmp_out.txt or tmp_err.txt" sys.exit() else: os.system("rm tmp_out.txt tmp_err.txt >/dev/null 2>&1") if __name__=="__main__": #Parsing arguments root = sys.argv[1].split("/")[-1][:-5] print "1 - Converting .mesh to binary .xyz" print "- 1.1 - Opening the mesh file" mesh = msh.Mesh(sys.argv[1]) try: directory = "wrapping_"+root.split(".")[0] if not os.path.exists(directory): os.makedirs(directory) os.chdir(directory) for f in os.listdir("."): os.remove(f) except: print "Error while removing files" sys.exit() print "- 1.2 - Converting to binary point data" binaryData, totalScale = ptsToXYZCubes(mesh.verts,151) print "2 - Creating the filled volume"
def read(f): mesh = msh.Mesh(f) mesh.readSol() mesh.caracterize() return mesh
print args.input1 + " is not a .mesh file" sys.exit() if not os.path.isfile(args.input2): print args.input2 + " is not a valid file" sys.exit() if not os.path.splitext(args.input2)[1] == ".mesh": print args.input2 + " is not a .mesh file" sys.exit() if not os.path.splitext( args.output)[1] == ".mesh" and not os.path.splitext( args.output)[1] == ".sol": print "Output file must be in the .mesh format" sys.exit() if __name__ == "__main__": args = parse() checkArgs(args) mesh1 = msh.Mesh(args.input1) mesh2 = msh.Mesh(args.input2) if len(mesh1.verts) != len(mesh2.verts): print "Different number of verts for the two meshes" sys.exit() mesh1.scalars = np.linalg.norm(mesh1.verts[:, :3] - mesh2.verts[:, :3], axis=1) if os.path.splitext(args.output)[1] == ".mesh": mesh1.write(args.output) mesh1.writeSol(args.output[:-5] + ".sol") else: mesh1.writeSol(args.output)
def generateMask(f): num = f[0].split("/")[-1][:3] bone, face = None, None if intersects(f[0]): #cleanWithMeshlab(f[0],new="bone.mesh") #if intersects("bone.mesh"): raise FacileError("Bone intersect") #bone = msh.Mesh("bone.mesh") else: bone = msh.Mesh(f[0]) if intersects(f[1]): #cleanWithMeshlab(f[1],new="face.mesh") #if intersects("face.mesh"): raise FacileError("Face intersect") #face = msh.Mesh("face.mesh") else: face = msh.Mesh(f[1]) face.tris = face.tris[face.tris[:, -1] != 2] face.tris[:, 3] = 2 face.discardUnused() bone.tris[:, 3] = 1 bone.fondre(face) bone.write("mask.mesh") if intersects("mask.mesh"): #cleanWithMeshlab("mask.mesh") #if intersects("mask.mesh"): raise FacileError('Bone and Face intersect') err = os.system(exe.tetgen + " -pgaAYNEF mask.mesh > /dev/null 2>&1") if err: raise FacileError("tetgen error") mesh = msh.Mesh("mask.1.mesh") #Exterior point = closest to [0,0,0] ext_point_ind = np.argmin([np.linalg.norm(x) for x in mesh.verts[:, :3]]) ext_ref = None for t in mesh.tets: if ext_point_ind in t[:4]: ext_ref = t[-1] break mesh.tets = mesh.tets[mesh.tets[:, -1] == ext_ref] mesh.tets[:, 4] = 2 for t in mesh.tris: if ext_point_ind in t[:3]: ext_ref = t[-1] break mesh.tris = mesh.tris[mesh.tris[:, 3] > 0] M = mesh.tris[:, -1] == ext_ref mesh.tris[M == 1][:, 3] = 1 mesh.tris[M == 0][:, 3] = 0 mesh.discardUnused() for t in mesh.tris: if t[-1] == 1: for i in t[:3]: mesh.verts[i, -1] = 1 mesh.write(os.path.join(directories["masked"], num + "_mask.mesh")) err = os.system(exe.mmg3d + " " + os.path.join(directories["masked"], num + "_mask.mesh") + " -o " + os.path.join(directories["masked"], num + "_mask.o.mesh") + " -hausd 0.0005 -nosurf -hgrad 1.15 > /dev/null 2>&1") if err: raise FacileError("mmg3d error") os.system("rm " + os.path.join(directories["masked"], num + "_mask.o.sol")) template = msh.Mesh(templates["morphingSkull"]) template.tets = np.array([]) template.tris = template.tris[template.tris[:, -1] == 1] template.discardUnused() mesh = msh.Mesh(os.path.join(directories["masked"], num + "_mask.o.mesh")) n = len(mesh.verts) mesh.tris = mesh.tris[mesh.tris[:, -1] == 1] mesh.tets = np.array([]) mesh.discardUnused() mesh.vectors = np.zeros((n, 3)) mesh.vectors[:len( template.verts )] = mesh.verts[:, : 3] - template.verts[:, : 3] # A remplacer par le resultat du morphing mesh.writeSol(os.path.join(directories["masked"], num + "_mask.o.sol"))
if err: print "An error happened while executing:\n" + cmd + "\nLook in tmp_out.txt or tmp_err.txt for info\nExiting..." sys.exit() else: os.system("rm tmp_out.txt tmp_err.txt >/dev/null 2>&1") if __name__ == "__main__": args = parse() checkArgs(args) root = ".".join(args.input.split("/")[-1].split(".")[:-1]) print root #1 - Load the mesh skull = msh.Mesh(args.input) # 2 - Scale by a fixed factor and align to the template skull.verts[:, :3] -= skull.center skull.verts[:, :3] *= 0.0035 skull.verts[:, :3] += [0.5, 0.5, 0.5] skull.computeBBox() skull.write(root + ".scaled.mesh") # 3 - Remesh with two hausdorff distance factors command(exe.mmgs + " " + root + ".scaled.mesh -o " + root + ".o1.mesh -nr -hausd 0.007") command(exe.mmgs + " " + root + ".scaled.mesh -o " + root + ".o2.mesh -nr -hausd 0.0007") # 4 - Align to the template skull
# RECONSTRUCTION ############################################################################ """ The new skull has to be reconstructed against the database: 1 - Scale, align and warp it 2 - Run a PCA on the distance to get a linear combination 3 - Get the mean of the modified masks with a linear combination """ recon = True if recon: os.chdir(directories["reconstruction"]) unknownSkull = "/home/norgeot/unknownSkull.o2.mesh" #.mesh" skull = msh.Mesh(unknownSkull) #Scale if not os.path.exists("scaled.mesh"): scale = 0.0035 skull.verts[:, :3] -= skull.center skull.verts[:, :3] *= scale skull.verts[:, :3] += [0.5, 0.5, 0.5] skull.write("scaled.mesh") #Align if not os.path.exists("aligned.mesh"): err = os.system(exe.align + " -i scaled.mesh " + templates["bone"] + " -d 0.1 -o 0.95 > /dev/null 2>&1") if err: