def zernike_moments(points, faces, order=10, scale_input=True, decimate_fraction=0, decimate_smooth=0, verbose=False): """ Compute the Zernike moments of a surface patch of points and faces. Optionally decimate the input mesh. Note:: Decimation sometimes leads to an error of "Segmentation fault: 11" (Twins-2-1 left label 14 gives such an error only when decimated.) Parameters ---------- points : list of lists of 3 floats x,y,z coordinates for each vertex faces : list of lists of 3 integers each list contains indices to vertices that form a triangle on a mesh order : integer order of the moments being calculated scale_input : bool translate and scale each object so it is bounded by a unit sphere? (this is the expected input to zernike_moments()) decimate_fraction : float fraction of mesh faces to remove for decimation (0 for no decimation) decimate_smooth : integer number of smoothing steps for decimation verbose : bool print statements? Returns ------- descriptors : list of floats Zernike descriptors Examples -------- >>> # Example 1: simple cube (decimation results in a Segmentation Fault): >>> import numpy as np >>> from mindboggle.shapes.zernike.zernike import zernike_moments >>> points = [[0,0,0], [1,0,0], [0,0,1], [0,1,1], ... [1,0,1], [0,1,0], [1,1,1], [1,1,0]] >>> faces = [[0,2,4], [0,1,4], [2,3,4], [3,4,5], [3,5,6], [0,1,7]] >>> order = 3 >>> scale_input = True >>> decimate_fraction = 0 >>> decimate_smooth = 0 >>> verbose = False >>> descriptors = zernike_moments(points, faces, order, scale_input, ... decimate_fraction, decimate_smooth, verbose) >>> print(np.array_str(np.array(descriptors), ... precision=5, suppress_small=True)) [ 0.09189 0.09357 0.04309 0.06466 0.0382 0.04138] Example 2: Twins-2-1 left postcentral pial surface -- NO decimation: (zernike_moments took 142 seconds for order = 3 with no decimation) >>> from mindboggle.shapes.zernike.zernike import zernike_moments >>> from mindboggle.mio.vtks import read_vtk >>> from mindboggle.guts.mesh import keep_faces >>> from mindboggle.mio.fetch_data import prep_tests >>> urls, fetch_data = prep_tests() >>> label_file = fetch_data(urls['left_freesurfer_labels'], '', '.vtk') >>> points, f1,f2, faces, labels, f3,f4,f5 = read_vtk(label_file) >>> I22 = [i for i,x in enumerate(labels) if x==1022] # postcentral >>> faces = keep_faces(faces, I22) >>> order = 3 >>> scale_input = True >>> decimate_fraction = 0 >>> decimate_smooth = 0 >>> verbose = False >>> descriptors = zernike_moments(points, faces, order, scale_input, ... decimate_fraction, decimate_smooth, verbose) >>> print(np.array_str(np.array(descriptors), ... precision=5, suppress_small=True)) [ 0.00471 0.0084 0.00295 0.00762 0.0014 0.00076] Example 3: left postcentral + pars triangularis pial surfaces: >>> from mindboggle.mio.vtks import read_vtk, write_vtk >>> points, f1,f2, faces, labels, f3,f4,f5 = read_vtk(label_file) >>> I20 = [i for i,x in enumerate(labels) if x==1020] # pars triangularis >>> I22 = [i for i,x in enumerate(labels) if x==1022] # postcentral >>> I22.extend(I20) >>> faces = keep_faces(faces, I22) >>> order = 3 >>> scale_input = True >>> decimate_fraction = 0 >>> decimate_smooth = 0 >>> verbose = False >>> descriptors = zernike_moments(points, faces, order, scale_input, ... decimate_fraction, decimate_smooth, verbose) >>> print(np.array_str(np.array(descriptors), ... precision=5, suppress_small=True)) [ 0.00586 0.00973 0.00322 0.00818 0.0013 0.00131] View both segments (skip test): >>> from mindboggle.mio.plots import plot_surfaces # doctest: +SKIP >>> from mindboggle.mio.vtks import rewrite_scalars # doctest: +SKIP >>> scalars = -1 * np.ones(np.shape(labels)) # doctest: +SKIP >>> scalars[I22] = 1 # doctest: +SKIP >>> rewrite_scalars(label_file, 'test_two_labels.vtk', scalars, ... 'two_labels', scalars) # doctest: +SKIP >>> plot_surfaces(vtk_file) # doctest: +SKIP """ import numpy as np from mindboggle.guts.mesh import reindex_faces_0to1 from mindboggle.guts.mesh import decimate from mindboggle.shapes.zernike.pipelines import DefaultPipeline as Pipeline # Convert 0-indices (Python) to 1-indices (Matlab) for all face indices: index1 = False # already done elsewhere in the code if index1: faces = reindex_faces_0to1(faces) # Convert lists to numpy arrays: if isinstance(points, list): points = np.array(points) if isinstance(faces, list): faces = np.array(faces) # ------------------------------------------------------------------------ # Translate all points so that they are centered at their mean, # and scale them so that they are bounded by a unit sphere: # ------------------------------------------------------------------------ if scale_input: center = np.mean(points, axis=0) points = points - center maxd = np.max(np.sqrt(np.sum(points**2, axis=1))) points /= maxd # ------------------------------------------------------------------------ # Decimate surface: # ------------------------------------------------------------------------ if 0 < decimate_fraction < 1: points, faces, u1, u2 = decimate(points, faces, decimate_fraction, decimate_smooth, [], save_vtk=False) # Convert lists to numpy arrays: points = np.array(points) faces = np.array(faces) # ------------------------------------------------------------------------ # Multiprocessor pipeline: # ------------------------------------------------------------------------ pl = Pipeline() # ------------------------------------------------------------------------ # Geometric moments: # ------------------------------------------------------------------------ G = pl.geometric_moments_exact(points, faces, order) # ------------------------------------------------------------------------ # ------------------------------------------------------------------------ Z = pl.zernike(G, order) # ------------------------------------------------------------------------ # Extract Zernike descriptors: # ------------------------------------------------------------------------ descriptors = pl.feature_extraction(Z, order).tolist() if verbose: print("Zernike moments: {0}".format(descriptors)) return descriptors
def zernike_moments(points, faces, order=10, scale_input=True, decimate_fraction=0, decimate_smooth=0, verbose=False): """ Compute the Zernike moments of a surface patch of points and faces. Optionally decimate the input mesh. Note:: Decimation sometimes leads to an error of "Segmentation fault: 11" (Twins-2-1 left label 14 gives such an error only when decimated.) Parameters ---------- points : list of lists of 3 floats x,y,z coordinates for each vertex faces : list of lists of 3 integers each list contains indices to vertices that form a triangle on a mesh order : integer order of the moments being calculated scale_input : bool translate and scale each object so it is bounded by a unit sphere? (this is the expected input to zernike_moments()) decimate_fraction : float fraction of mesh faces to remove for decimation (0 for no decimation) decimate_smooth : integer number of smoothing steps for decimation verbose : bool print statements? Returns ------- descriptors : list of floats Zernike descriptors Examples -------- >>> # Example 1: simple cube (decimation results in a Segmentation Fault): >>> import numpy as np >>> from mindboggle.shapes.zernike.zernike import zernike_moments >>> points = [[0,0,0], [1,0,0], [0,0,1], [0,1,1], ... [1,0,1], [0,1,0], [1,1,1], [1,1,0]] >>> faces = [[0,2,4], [0,1,4], [2,3,4], [3,4,5], [3,5,6], [0,1,7]] >>> order = 3 >>> scale_input = True >>> verbose = False >>> descriptors = zernike_moments(points, faces, order, scale_input, ... verbose) >>> print(np.array_str(np.array(descriptors), ... precision=5, suppress_small=True)) [ 0.09189 0.09357 0.04309 0.06466 0.0382 0.04138] Example 2: Twins-2-1 left postcentral pial surface -- NO decimation: (zernike_moments took 142 seconds for order = 3 with no decimation) >>> from mindboggle.mio.vtks import read_vtk >>> from mindboggle.guts.mesh import keep_faces >>> from mindboggle.mio.fetch_data import prep_tests >>> urls, fetch_data = prep_tests() >>> label_file = fetch_data(urls['left_freesurfer_labels']) >>> points, f1,f2, faces, labels, f3,f4,f5 = read_vtk(label_file) >>> I22 = [i for i,x in enumerate(labels) if x==1022] # postcentral >>> faces = keep_faces(faces, I22) >>> order = 3 >>> scale_input = True >>> verbose = False >>> descriptors = zernike_moments(points, faces, order, scale_input, ... verbose) >>> print(np.array_str(np.array(descriptors), ... precision=5, suppress_small=True)) [ 0.00471 0.0084 0.00295 0.00762 0.0014 0.00076] Example 3: left postcentral + pars triangularis pial surfaces: >>> from mindboggle.mio.vtks import read_vtk, write_vtk >>> points, f1,f2, faces, labels, f3,f4,f5 = read_vtk(label_file) >>> I20 = [i for i,x in enumerate(labels) if x==1020] # pars triangularis >>> I22 = [i for i,x in enumerate(labels) if x==1022] # postcentral >>> I22.extend(I20) >>> faces = keep_faces(faces, I22) >>> order = 3 >>> scale_input = True >>> verbose = False >>> descriptors = zernike_moments(points, faces, order, scale_input, ... verbose) >>> print(np.array_str(np.array(descriptors), ... precision=5, suppress_small=True)) [ 0.00586 0.00973 0.00322 0.00818 0.0013 0.00131] View both segments (skip test): >>> from mindboggle.mio.plots import plot_surfaces >>> scalars = -1 * np.ones(np.shape(labels)) >>> scalars[I22] = 1 >>> vtk_file = 'test_two_labels.vtk' >>> # Note: mismatch in the following command: >>> write_vtk(vtk_file, points, [],[], faces, scalars, 'scalars', 'int') >>> plot_surfaces(vtk_file) # doctest: +SKIP """ import numpy as np from mindboggle.guts.mesh import reindex_faces_0to1 from mindboggle.guts.mesh import decimate from .pipelines import DefaultPipeline as ZernikePipeline # Convert 0-indices (Python) to 1-indices (Matlab) for all face indices: index1 = False # already done elsewhere in the code if index1: faces = reindex_faces_0to1(faces) # Convert lists to numpy arrays: if isinstance(points, list): points = np.array(points) if isinstance(faces, list): faces = np.array(faces) #------------------------------------------------------------------------- # Translate all points so that they are centered at their mean, # and scale them so that they are bounded by a unit sphere: #------------------------------------------------------------------------- if scale_input: center = np.mean(points, axis=0) points = points - center maxd = np.max(np.sqrt(np.sum(points**2, axis=1))) points = points / maxd #------------------------------------------------------------------------- # Decimate surface: #------------------------------------------------------------------------- if 0 < decimate_fraction < 1: points, faces, u1,u2 = decimate(points, faces, decimate_fraction, decimate_smooth, [], save_vtk=False) # Convert lists to numpy arrays: points = np.array(points) faces = np.array(faces) #------------------------------------------------------------------------- # Multiprocessor pipeline: #------------------------------------------------------------------------- pl = ZernikePipeline() #------------------------------------------------------------------------- # Geometric moments: #------------------------------------------------------------------------- G = pl.geometric_moments_exact(points, faces, order) # Z = pl.zernike(G, order) #------------------------------------------------------------------------- # Extract Zernike descriptors: #------------------------------------------------------------------------- descriptors = pl.feature_extraction(Z, order).tolist() if verbose: print("Zernike moments: {0}".format(descriptors)) return descriptors
def zernike_moments(points, faces, order=10, scale_input=True, decimate_fraction=0, decimate_smooth=0, pl_cls=None): """ Compute the Zernike moments of a surface patch of points and faces. Optionally decimate the input mesh. Note:: Decimation sometimes leads to an error of "Segmentation fault: 11" (Twins-2-1 left label 14 gives such an error only when decimated.) Parameters ---------- points : list of lists of 3 floats x,y,z coordinates for each vertex faces : list of lists of 3 integers each list contains indices to vertices that form a triangle on a mesh order : integer order of the moments being calculated scale_input : Boolean translate and scale each object so it is bounded by a unit sphere? (this is the expected input to zernike_moments()) decimate_fraction : float fraction of mesh faces to remove for decimation (0 for no decimation) decimate_smooth : integer number of smoothing steps for decimation Returns ------- descriptors : list of floats Zernike descriptors Examples -------- >>> # Example 1: simple cube (decimation results in a Segmentation Fault): >>> from mindboggle.shapes.zernike.zernike import zernike_moments >>> points = [[0,0,0], [1,0,0], [0,0,1], [0,1,1], [1,0,1], [0,1,0], [1,1,1], [1,1,0]] >>> faces = [[0,2,4], [0,1,4], [2,3,4], [3,4,5], [3,5,6], [0,1,7]] >>> order = 3 >>> scale_input = True >>> zernike_moments(points, faces, order, scale_input) [0.0918881492369654, 0.09357431096617608, 0.04309029164656885, 0.06466432586854755, 0.03820155248327533, 0.04138011726544602] >>> # Example 2: simple cube (with inner diagonal plane): >>> # (decimation doesn't have any effect) >>> import os >>> from mindboggle.mio.vtks import read_vtk >>> from mindboggle.shapes.zernike.zernike import zernike_moments >>> path = os.environ['MINDBOGGLE_DATA'] >>> vtk_file = os.path.join(path, 'cube.vtk') >>> faces, u1,u2, points, u3,u4,u5,u6 = read_vtk(vtk_file) >>> order = 3 >>> scale_input = True >>> zernike_moments(points, faces, order, scale_input) [0.0, 1.5444366221695725e-21, 0.0, 2.081366518964347e-21, 5.735003646768394e-05, 2.433866250546253e-21] Arthur Mikhno's result: 0 0 0.2831 10.6997 2.1352 11.8542 >>> # Example 2.5: Parallelepiped.vtk: >>> import os >>> from mindboggle.mio.vtks import read_vtk >>> from mindboggle.shapes.zernike.zernike import zernike_moments >>> path = os.environ['MINDBOGGLE_DATA'] >>> vtk_file = os.path.join(path, 'Parallelepiped.vtk') >>> faces, u1,u2, points, u3,u4,u5,u6 = read_vtk(vtk_file) >>> order = 3 >>> scale_input = True >>> zernike_moments(points, faces, order, scale_input) [0.2652000150907399, 0.27006648207389017, 6.902814314591948e-09, 7.901431343883835e-09, 0.12685697496878662, 5.560135951999606e-09] Arthur Mikhno's result: 0.0251 0.0310 0.0255 0.0451 0.0189 0.0133 >>> # Example 3: Twins-2-1 left postcentral pial surface -- NO decimation: >>> # (zernike_moments took 142 seconds for order = 3 with no decimation) >>> import os >>> from mindboggle.mio.vtks import read_vtk >>> from mindboggle.guts.mesh import remove_faces >>> from mindboggle.shapes.zernike.zernike import zernike_moments >>> path = os.environ['MINDBOGGLE_DATA'] >>> label_file = os.path.join(path, 'arno', 'labels', 'lh.labels.DKT31.manual.vtk') >>> faces, u1,u2, points, u3, labels, u4,u5 = read_vtk(label_file) >>> I22 = [i for i,x in enumerate(labels) if x==22] # postcentral >>> faces = remove_faces(faces, I22) >>> order = 3 >>> scale_input = True >>> zernike_moments(points, faces, order, scale_input) [0.005558794553842859, 0.009838755429501177, 0.003512500896236744, 0.00899042745665395, 0.001672289910738449, 0.000919469614081582] >>> # Example 5: left postcentral + pars triangularis pial surfaces: >>> import os >>> from mindboggle.mio.vtks import read_vtk, write_vtk >>> from mindboggle.guts.mesh import remove_faces >>> from mindboggle.shapes.zernike.zernike import zernike_moments >>> path = os.environ['MINDBOGGLE_DATA'] >>> label_file = os.path.join(path, 'arno', 'labels', 'lh.labels.DKT31.manual.vtk') >>> faces, u1,u2, points, u3, labels, u4,u5 = read_vtk(label_file) >>> I20 = [i for i,x in enumerate(labels) if x==20] # pars triangularis >>> I22 = [i for i,x in enumerate(labels) if x==22] # postcentral >>> I22.extend(I20) >>> faces = remove_faces(faces, I22) >>> order = 3 >>> scale_input = True >>> zernike_moments(points, faces, order, scale_input) [0.006591540793309832, 0.010749937070447451, 0.0034900573103799214, 0.008972460360983864, 0.0018220183025464518, 0.0016893113500293917] >>> # View both segments: >>> from mindboggle.mio.plots import plot_surfaces >>> scalars = -1*np.ones(np.shape(labels)) >>> scalars[I22] = 1 >>> vtk_file = 'test_two_labels.vtk' >>> write_vtk(vtk_file, points, [],[], faces, scalars, scalar_names='scalars', scalar_type='int') >>> plot_surfaces(vtk_file) """ import numpy as np from mindboggle.guts.mesh import reindex_faces_0to1 from mindboggle.guts.mesh import decimate if pl_cls is None: from .pipelines import DefaultPipeline as ZernikePipeline else: ZernikePipeline = pl_cls # Convert 0-indices (Python) to 1-indices (Matlab) for all face indices: index1 = False # already done elsewhere in the code if index1: faces = reindex_faces_0to1(faces) # Convert lists to numpy arrays: if isinstance(points, list): points = np.array(points) if isinstance(faces, list): faces = np.array(faces) #------------------------------------------------------------------------- # Translate all points so that they are centered at their mean, # and scale them so that they are bounded by a unit sphere: #------------------------------------------------------------------------- if scale_input: center = np.mean(points, axis=0) points = points - center maxd = np.max(np.sqrt(np.sum(points**2, axis=1))) points = points / maxd #------------------------------------------------------------------------- # Decimate surface: #------------------------------------------------------------------------- if 0 < decimate_fraction < 1: points, faces, u1, u2 = decimate(points, faces, decimate_fraction, decimate_smooth, [], save_vtk=False) # Convert lists to numpy arrays: points = np.array(points) faces = np.array(faces) #------------------------------------------------------------------------- # Multiprocessor pipeline: #------------------------------------------------------------------------- pl = ZernikePipeline() #------------------------------------------------------------------------- # Geometric moments: #------------------------------------------------------------------------- G = pl.geometric_moments_exact(points, faces, order) # Z = pl.zernike(G, order) #------------------------------------------------------------------------- # Extract Zernike descriptors: #------------------------------------------------------------------------- descriptors = pl.feature_extraction(Z, order).tolist() return descriptors
def zernike_moments(points, faces, order=10, scale_input=True, decimate_fraction=0, decimate_smooth=0, pl_cls=None): """ Compute the Zernike moments of a surface patch of points and faces. Optionally decimate the input mesh. Note:: Decimation sometimes leads to an error of "Segmentation fault: 11" (Twins-2-1 left label 14 gives such an error only when decimated.) Parameters ---------- points : list of lists of 3 floats x,y,z coordinates for each vertex faces : list of lists of 3 integers each list contains indices to vertices that form a triangle on a mesh order : integer order of the moments being calculated scale_input : Boolean translate and scale each object so it is bounded by a unit sphere? (this is the expected input to zernike_moments()) decimate_fraction : float fraction of mesh faces to remove for decimation (0 for no decimation) decimate_smooth : integer number of smoothing steps for decimation Returns ------- descriptors : list of floats Zernike descriptors Examples -------- >>> # Example 1: simple cube (decimation results in a Segmentation Fault): >>> from mindboggle.shapes.zernike.zernike import zernike_moments >>> points = [[0,0,0], [1,0,0], [0,0,1], [0,1,1], [1,0,1], [0,1,0], [1,1,1], [1,1,0]] >>> faces = [[0,2,4], [0,1,4], [2,3,4], [3,4,5], [3,5,6], [0,1,7]] >>> order = 3 >>> scale_input = True >>> zernike_moments(points, faces, order, scale_input) [0.0918881492369654, 0.09357431096617608, 0.04309029164656885, 0.06466432586854755, 0.03820155248327533, 0.04138011726544602] >>> # Example 2: simple cube (with inner diagonal plane): >>> # (decimation doesn't have any effect) >>> import os >>> from mindboggle.mio.vtks import read_vtk >>> from mindboggle.shapes.zernike.zernike import zernike_moments >>> path = os.environ['MINDBOGGLE_DATA'] >>> vtk_file = os.path.join(path, 'cube.vtk') >>> faces, u1,u2, points, u3,u4,u5,u6 = read_vtk(vtk_file) >>> order = 3 >>> scale_input = True >>> zernike_moments(points, faces, order, scale_input) [0.0, 1.5444366221695725e-21, 0.0, 2.081366518964347e-21, 5.735003646768394e-05, 2.433866250546253e-21] Arthur Mikhno's result: 0 0 0.2831 10.6997 2.1352 11.8542 >>> # Example 2.5: Parallelepiped.vtk: >>> import os >>> from mindboggle.mio.vtks import read_vtk >>> from mindboggle.shapes.zernike.zernike import zernike_moments >>> path = os.environ['MINDBOGGLE_DATA'] >>> vtk_file = os.path.join(path, 'Parallelepiped.vtk') >>> faces, u1,u2, points, u3,u4,u5,u6 = read_vtk(vtk_file) >>> order = 3 >>> scale_input = True >>> zernike_moments(points, faces, order, scale_input) [0.2652000150907399, 0.27006648207389017, 6.902814314591948e-09, 7.901431343883835e-09, 0.12685697496878662, 5.560135951999606e-09] Arthur Mikhno's result: 0.0251 0.0310 0.0255 0.0451 0.0189 0.0133 >>> # Example 3: Twins-2-1 left postcentral pial surface -- NO decimation: >>> # (zernike_moments took 142 seconds for order = 3 with no decimation) >>> import os >>> from mindboggle.mio.vtks import read_vtk >>> from mindboggle.guts.mesh import remove_faces >>> from mindboggle.shapes.zernike.zernike import zernike_moments >>> path = os.environ['MINDBOGGLE_DATA'] >>> label_file = os.path.join(path, 'arno', 'labels', 'lh.labels.DKT31.manual.vtk') >>> faces, u1,u2, points, u3, labels, u4,u5 = read_vtk(label_file) >>> I22 = [i for i,x in enumerate(labels) if x==22] # postcentral >>> faces = remove_faces(faces, I22) >>> order = 3 >>> scale_input = True >>> zernike_moments(points, faces, order, scale_input) [0.005558794553842859, 0.009838755429501177, 0.003512500896236744, 0.00899042745665395, 0.001672289910738449, 0.000919469614081582] >>> # Example 5: left postcentral + pars triangularis pial surfaces: >>> import os >>> from mindboggle.mio.vtks import read_vtk, write_vtk >>> from mindboggle.guts.mesh import remove_faces >>> from mindboggle.shapes.zernike.zernike import zernike_moments >>> path = os.environ['MINDBOGGLE_DATA'] >>> label_file = os.path.join(path, 'arno', 'labels', 'lh.labels.DKT31.manual.vtk') >>> faces, u1,u2, points, u3, labels, u4,u5 = read_vtk(label_file) >>> I20 = [i for i,x in enumerate(labels) if x==20] # pars triangularis >>> I22 = [i for i,x in enumerate(labels) if x==22] # postcentral >>> I22.extend(I20) >>> faces = remove_faces(faces, I22) >>> order = 3 >>> scale_input = True >>> zernike_moments(points, faces, order, scale_input) [0.006591540793309832, 0.010749937070447451, 0.0034900573103799214, 0.008972460360983864, 0.0018220183025464518, 0.0016893113500293917] >>> # View both segments: >>> from mindboggle.mio.plots import plot_surfaces >>> scalars = -1*np.ones(np.shape(labels)) >>> scalars[I22] = 1 >>> vtk_file = 'test_two_labels.vtk' >>> write_vtk(vtk_file, points, [],[], faces, scalars, scalar_names='scalars', scalar_type='int') >>> plot_surfaces(vtk_file) """ import numpy as np from mindboggle.guts.mesh import reindex_faces_0to1 from mindboggle.guts.mesh import decimate if pl_cls is None: from .pipelines import DefaultPipeline as ZernikePipeline else: ZernikePipeline = pl_cls # Convert 0-indices (Python) to 1-indices (Matlab) for all face indices: index1 = False # already done elsewhere in the code if index1: faces = reindex_faces_0to1(faces) # Convert lists to numpy arrays: if isinstance(points, list): points = np.array(points) if isinstance(faces, list): faces = np.array(faces) #------------------------------------------------------------------------- # Translate all points so that they are centered at their mean, # and scale them so that they are bounded by a unit sphere: #------------------------------------------------------------------------- if scale_input: center = np.mean(points, axis=0) points = points - center maxd = np.max(np.sqrt(np.sum(points**2, axis=1))) points = points / maxd #------------------------------------------------------------------------- # Decimate surface: #------------------------------------------------------------------------- if 0 < decimate_fraction < 1: points, faces, u1,u2 = decimate(points, faces, decimate_fraction, decimate_smooth, [], save_vtk=False) # Convert lists to numpy arrays: points = np.array(points) faces = np.array(faces) #------------------------------------------------------------------------- # Multiprocessor pipeline: #------------------------------------------------------------------------- pl = ZernikePipeline() #------------------------------------------------------------------------- # Geometric moments: #------------------------------------------------------------------------- G = pl.geometric_moments_exact(points, faces, order) # Z = pl.zernike(G, order) #------------------------------------------------------------------------- # Extract Zernike descriptors: #------------------------------------------------------------------------- descriptors = pl.feature_extraction(Z, order).tolist() return descriptors
def zernike_moments(points, faces, order=10, scale_input=True, decimate_fraction=0, decimate_smooth=0, verbose=False): """ Compute the Zernike moments of a surface patch of points and faces. Optionally decimate the input mesh. Note:: Decimation sometimes leads to an error of "Segmentation fault: 11" (Twins-2-1 left label 14 gives such an error only when decimated.) Parameters ---------- points : list of lists of 3 floats x,y,z coordinates for each vertex faces : list of lists of 3 integers each list contains indices to vertices that form a triangle on a mesh order : integer order of the moments being calculated scale_input : bool translate and scale each object so it is bounded by a unit sphere? (this is the expected input to zernike_moments()) decimate_fraction : float fraction of mesh faces to remove for decimation (0 for no decimation) decimate_smooth : integer number of smoothing steps for decimation verbose : bool print statements? Returns ------- descriptors : list of floats Zernike descriptors """ import numpy as np from mindboggle.guts.mesh import reindex_faces_0to1 from mindboggle.guts.mesh import decimate from mindboggle.shapes.zernike.pipelines import DefaultPipeline as Pipeline # Convert 0-indices (Python) to 1-indices (Matlab) for all face indices: index1 = False # already done elsewhere in the code if index1: faces = reindex_faces_0to1(faces) # Convert lists to numpy arrays: if isinstance(points, list): points = np.array(points) if isinstance(faces, list): faces = np.array(faces) # ------------------------------------------------------------------------ # Translate all points so that they are centered at their mean, # and scale them so that they are bounded by a unit sphere: # ------------------------------------------------------------------------ if scale_input: center = np.mean(points, axis=0) points = points - center maxd = np.max(np.sqrt(np.sum(points ** 2, axis=1))) points /= maxd # ------------------------------------------------------------------------ # Decimate surface: # ------------------------------------------------------------------------ if 0 < decimate_fraction < 1: points, faces, u1, u2 = decimate(points, faces, decimate_fraction, decimate_smooth, [], save_vtk=False) # Convert lists to numpy arrays: points = np.array(points) faces = np.array(faces) # ------------------------------------------------------------------------ # Multiprocessor pipeline: # ------------------------------------------------------------------------ pl = Pipeline() # ------------------------------------------------------------------------ # Geometric moments: # ------------------------------------------------------------------------ G = pl.geometric_moments_exact(points, faces, order) # ------------------------------------------------------------------------ # ------------------------------------------------------------------------ Z = pl.zernike(G, order) # ------------------------------------------------------------------------ # Extract Zernike descriptors: # ------------------------------------------------------------------------ descriptors = pl.feature_extraction(Z, order).tolist() if verbose: print("Zernike moments: {0}".format(descriptors)) return descriptors