amaazetools 0.1.2__tar.gz → 0.1.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. {amaazetools-0.1.2/amaazetools.egg-info → amaazetools-0.1.3}/PKG-INFO +1 -1
  2. {amaazetools-0.1.2 → amaazetools-0.1.3}/amaazetools/trimesh.py +131 -79
  3. {amaazetools-0.1.2 → amaazetools-0.1.3/amaazetools.egg-info}/PKG-INFO +1 -1
  4. {amaazetools-0.1.2 → amaazetools-0.1.3}/pyproject.toml +1 -1
  5. {amaazetools-0.1.2 → amaazetools-0.1.3}/LICENSE +0 -0
  6. {amaazetools-0.1.2 → amaazetools-0.1.3}/MANIFEST.in +0 -0
  7. {amaazetools-0.1.2 → amaazetools-0.1.3}/README.md +0 -0
  8. {amaazetools-0.1.2 → amaazetools-0.1.3}/amaazetools/__init__.py +0 -0
  9. {amaazetools-0.1.2 → amaazetools-0.1.3}/amaazetools/dicom.py +0 -0
  10. {amaazetools-0.1.2 → amaazetools-0.1.3}/amaazetools/edge_detection.py +0 -0
  11. {amaazetools-0.1.2 → amaazetools-0.1.3}/amaazetools/mesh_segmentation.py +0 -0
  12. {amaazetools-0.1.2 → amaazetools-0.1.3}/amaazetools/svi.py +0 -0
  13. {amaazetools-0.1.2 → amaazetools-0.1.3}/amaazetools.egg-info/SOURCES.txt +0 -0
  14. {amaazetools-0.1.2 → amaazetools-0.1.3}/amaazetools.egg-info/dependency_links.txt +0 -0
  15. {amaazetools-0.1.2 → amaazetools-0.1.3}/amaazetools.egg-info/requires.txt +0 -0
  16. {amaazetools-0.1.2 → amaazetools-0.1.3}/amaazetools.egg-info/top_level.txt +0 -0
  17. {amaazetools-0.1.2 → amaazetools-0.1.3}/setup.cfg +0 -0
  18. {amaazetools-0.1.2 → amaazetools-0.1.3}/setup.py +0 -0
  19. {amaazetools-0.1.2 → amaazetools-0.1.3}/src/cextensions.c +0 -0
  20. {amaazetools-0.1.2 → amaazetools-0.1.3}/src/memory_allocation.c +0 -0
  21. {amaazetools-0.1.2 → amaazetools-0.1.3}/src/memory_allocation.h +0 -0
  22. {amaazetools-0.1.2 → amaazetools-0.1.3}/src/mesh_operations.c +0 -0
  23. {amaazetools-0.1.2 → amaazetools-0.1.3}/src/mesh_operations.h +0 -0
  24. {amaazetools-0.1.2 → amaazetools-0.1.3}/src/svi_computations.c +0 -0
  25. {amaazetools-0.1.2 → amaazetools-0.1.3}/src/svi_computations.h +0 -0
  26. {amaazetools-0.1.2 → amaazetools-0.1.3}/src/vector_operations.h +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: amaazetools
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: Python package for mesh processing tools developed by AMAAZE
5
5
  Author-email: Jeff Calder <jwcalder@umn.edu>
6
6
  License: MIT
@@ -18,6 +18,58 @@ import urllib.request as url
18
18
 
19
19
  #Non-Class Specific Functions
20
20
 
21
+
22
+ def marching_cubes(volume,level=None,spacing=(1,1,1)):
23
+ """ SK-Image's marching cubes does not return a clean triangulations -
24
+ often has replicate points, self-triangles, etc. This fixes that.
25
+
26
+ Parameters
27
+ ----------
28
+ volume : (l,w,h) float array
29
+ A 3-D grid discretization of the function to be surfaced.
30
+ level : float
31
+ isolevel to extract surface at.
32
+ spacing : (3) float
33
+ denotes the dimensions of each voxel in the volume.
34
+
35
+
36
+ Returns
37
+ -------
38
+ p : (n,3) float
39
+ points of triangulation
40
+ t : (m,3) int
41
+ triangles of triangulation
42
+ """
43
+
44
+ p,t,n,val = measure.marching_cubes(volume,level=level,spacing=spacing)
45
+
46
+ #sometimes marching cubes produces... artifacts... so here's a very basic intro to mesh cleaning!
47
+ #first: eliminate repeated points:
48
+ p,index,inv = np.unique(p,axis=0, return_index=True,return_inverse=True)
49
+
50
+ #next: rid triangulation of non-triangles:
51
+ t = inv[t]
52
+ badt = (t[:,0]==t[:,1])+(t[:,1]==t[:,2])+(t[:,2]==t[:,0])
53
+ t = t[badt ==False,:]
54
+
55
+ #remove unreferenced points, if any
56
+ ind = -1*np.ones(p.shape[0],int)
57
+ uni = np.unique(t.flatten()) #these are already sorted for numpy
58
+ ind[uni] = np.arange(uni.shape[0])
59
+ p = p[ind>-1,:]
60
+ t = ind[t]
61
+
62
+ #finally, check right hand rule... this works for ~convex objects, anyway...
63
+ #m = tm.mesh(p,t)
64
+
65
+ #tc = m.face_centers()
66
+ #tn = m.face_normals()
67
+
68
+ #cent = m.points.mean(0)
69
+ #fliporder = np.sum(tn*(tc-cent),1)<0
70
+ #t[fliporder,1:3] = t[fliporder,2:0:-1]
71
+ return p,t
72
+
21
73
  def withiness(x):
22
74
  """ Computes withiness (how well 1-D data clusters into two groups).
23
75
 
@@ -25,7 +77,7 @@ def withiness(x):
25
77
  ----------
26
78
  x : (n,1) float array
27
79
  A 1-D collection of data.
28
-
80
+
29
81
  Returns
30
82
  -------
31
83
  w : float
@@ -56,7 +108,7 @@ def pca(P):
56
108
  ----------
57
109
  P : (n,d) float array
58
110
  A point cloud.
59
-
111
+
60
112
  Returns
61
113
  -------
62
114
  vals : (d,) float arrayy
@@ -64,13 +116,13 @@ def pca(P):
64
116
  vecs : (d,d) float array
65
117
  The principal component vectors.
66
118
  """
67
-
119
+
68
120
  P = P - np.mean(P,axis=0)
69
121
  vals,vecs = np.linalg.eig(P.T@P)
70
122
  idx = np.argsort(-vals)
71
123
 
72
124
  return vals[idx],vecs[:,idx]
73
-
125
+
74
126
  def weighted_pca(P,W):
75
127
  """ Computes weighted principal component analysis (PCA) on a point cloud P.
76
128
 
@@ -80,7 +132,7 @@ def weighted_pca(P,W):
80
132
  A point cloud.
81
133
  W : (n,) float array
82
134
  An array containing the weights of the points.
83
-
135
+
84
136
  Returns
85
137
  -------
86
138
  vals : (d,) float array
@@ -107,7 +159,7 @@ def power_method(A,tol=1e-12):
107
159
  A square matrix that one wishes to find the smallest (in absolute value) eigenvalue and corresponding eigenvector of.
108
160
  tol : float, default is 1e-12
109
161
  The desired tolerance threshold after which to stop iteration.
110
-
162
+
111
163
  Parameters
112
164
  ----------
113
165
  l : float
@@ -137,7 +189,7 @@ def pca_smallest_eig_powermethod(X,center=True):
137
189
  A point cloud.
138
190
  center : boolean, default is True
139
191
  Data is centered if True.
140
-
192
+
141
193
  Returns
142
194
  -------
143
195
  A float array of size (3,) containing the last principal component vector.
@@ -162,7 +214,7 @@ def pca_smallest_eig(X,center=True):
162
214
  A point cloud.
163
215
  center : boolean, default is True
164
216
  Data is centered if True.
165
-
217
+
166
218
  Returns
167
219
  -------
168
220
  A float array of size (3,) containing the last principal component vector.
@@ -187,7 +239,7 @@ def read_ply(fname):
187
239
  ----------
188
240
  fname: str
189
241
  Name of the file to read from.
190
-
242
+
191
243
  Returns
192
244
  -------
193
245
  P : (num_verts,3) float array
@@ -221,7 +273,7 @@ def load_ply(path):
221
273
  ----------
222
274
  path : str
223
275
  URL or file path at which to access .ply file.
224
-
276
+
225
277
  Returns
226
278
  -------
227
279
  A mesh object generated from a .ply file found at the file path location.
@@ -247,12 +299,12 @@ def synth_mesh(angle, num_pts):
247
299
 
248
300
  Parameters
249
301
  ----------
250
- angle: float
302
+ angle: float
251
303
  Intersection angle.
252
304
  num_pts : int
253
305
  Number of vertices in the mesh.
254
-
255
-
306
+
307
+
256
308
  Returns
257
309
  -------
258
310
  A mesh object.
@@ -279,7 +331,7 @@ def synth_mesh(angle, num_pts):
279
331
  verts[:,1] *= np.tan(angle*np.pi/180/2)
280
332
 
281
333
  #Create mesh and flip normals
282
- m = mesh(verts,faces)
334
+ m = mesh(verts,faces)
283
335
  m.flip_normals()
284
336
 
285
337
  return m
@@ -386,7 +438,7 @@ class mesh:
386
438
  #so F can be used to interplate from triangles to vertices
387
439
  def tri_vert_adj(self,normalize=False):
388
440
  """ Computes a sparse vertex-triangle adjacency matrix.
389
-
441
+
390
442
  Parameters
391
443
  ----------
392
444
  normalize : boolean, default is False
@@ -417,7 +469,7 @@ class mesh:
417
469
  #Returns unit normal vectors to vertices (averaging adjacent faces and normalizing)
418
470
  def vertex_normals(self):
419
471
  """ Computes normal vectors to vertices.
420
-
472
+
421
473
  Returns
422
474
  -------
423
475
  A (num_verts,3) float array containing the vertex normal vectors.
@@ -432,16 +484,16 @@ class mesh:
432
484
  norms[norms==0] = 1
433
485
 
434
486
  return vn/norms[:,np.newaxis]
435
-
487
+
436
488
  #Returns unit normal vectors
437
489
  def face_normals(self,normalize=True):
438
490
  """ Computes normal vectors to triangles (faces).
439
-
491
+
440
492
  Parameters
441
493
  ----------
442
494
  normalize: boolean, default is True
443
495
  Whether or not to normalize to unit vectors; if False, vector magnitude is twice the area of the corresponding triangle.
444
-
496
+
445
497
  Returns
446
498
  -------
447
499
  N : (num_tri,3) float array
@@ -460,7 +512,7 @@ class mesh:
460
512
  else:
461
513
  self.norms = N
462
514
  return N
463
-
515
+
464
516
  def flip_normals(self):
465
517
  """ Reverses the orientation of all normal vectors in the mesh
466
518
  """
@@ -470,7 +522,7 @@ class mesh:
470
522
  #Areas of all triangles in mesh
471
523
  def tri_areas(self):
472
524
  """ Computes areas of all triangles in the mesh.
473
-
525
+
474
526
  Returns
475
527
  -------
476
528
  A (num_tri,) float array containing the areas of each triangle (face).
@@ -483,18 +535,18 @@ class mesh:
483
535
  #Surface area of mesh
484
536
  def surf_area(self):
485
537
  """ Computes surface area of the mesh.
486
-
538
+
487
539
  Returns
488
540
  -------
489
541
  The surface area of the entire mesh as a float.
490
542
  """
491
543
 
492
544
  return np.sum(self.tri_areas())
493
-
545
+
494
546
  #Centers of each face
495
547
  def face_centers(self):
496
548
  """ Computes coordinates of the center of each triangle (face).
497
-
549
+
498
550
  Returns
499
551
  -------
500
552
  A (num_tri,3) float array containing the coordinates of the face centers.
@@ -507,11 +559,11 @@ class mesh:
507
559
  result = (P1 + P2 + P3)/3
508
560
  self.centers = result
509
561
  return result
510
-
562
+
511
563
  #Volume enclosed by mesh
512
564
  def volume(self):
513
565
  """ Computes the volume of the mesh.
514
-
566
+
515
567
  Returns
516
568
  -------
517
569
  The volume of the mesh as a float.
@@ -524,10 +576,10 @@ class mesh:
524
576
  if self.norms is None:
525
577
  self.face_normals(False)
526
578
  return np.sum(X*self.norms)/6
527
-
579
+
528
580
  def bbox(self):
529
581
  """ Computes the bounding box of the mesh.
530
-
582
+
531
583
  Returns
532
584
  -------
533
585
  A (3,) float array containing the dimensions of the bounding box.
@@ -547,10 +599,10 @@ class mesh:
547
599
 
548
600
  Y = X@vecs
549
601
  bb = np.max(Y,axis=0) - np.min(Y,axis=0)
550
-
602
+
551
603
  return bb
552
-
553
-
604
+
605
+
554
606
  #Plot triangulated surface
555
607
  def plotsurf(self,C=None):
556
608
  """ Plots the mesh as a surface using mayavi.
@@ -559,7 +611,7 @@ class mesh:
559
611
  ----------
560
612
  C : (num_verts,3) int array, default is None
561
613
  An optional per-vertex labeling scheme to use.
562
-
614
+
563
615
  Returns
564
616
  -------
565
617
  A visualization of the mesh.
@@ -578,7 +630,7 @@ class mesh:
578
630
  ----------
579
631
  C : (num_verts,3) int array, default is -1
580
632
  An optional per-vertex labeling scheme to use.
581
-
633
+
582
634
  Returns
583
635
  -------
584
636
  mesh : amaazetools.trimesh.mesh object
@@ -588,7 +640,7 @@ class mesh:
588
640
  from mayavi import mlab
589
641
  if C.any == -1: #if no C given
590
642
  C = np.ones((len(x),1))
591
-
643
+
592
644
  n = len(np.unique(C))
593
645
  C = C.astype(int)
594
646
  if n>20:
@@ -597,9 +649,9 @@ class mesh:
597
649
  col = (np.arange(1,n+1)) / n
598
650
  colors = col[C-1]
599
651
  mesh = mlab.triangular_mesh(self.points[:,0],self.points[:,1],self.points[:,2],self.triangles,scalars=colors)
600
-
652
+
601
653
  return mesh
602
-
654
+
603
655
  #Write a ply file
604
656
  def to_ply(self,fname):
605
657
  """ Writes the mesh to a .ply file.
@@ -635,7 +687,7 @@ class mesh:
635
687
 
636
688
  #close file
637
689
  f.close()
638
-
690
+
639
691
  #Write a ply file
640
692
  def write_color_ply(self,color,fname):
641
693
  """ Writes the colored mesh to a .ply file.
@@ -697,21 +749,21 @@ class mesh:
697
749
  histeq : boolean, default is True
698
750
  Performs histogram equalization on scalar color array; else should normalize prior to input.
699
751
  """
700
-
752
+
701
753
  from skimage import exposure
702
754
  from mayavi import mlab
703
755
  import moviepy.editor as mpy
704
756
  from pyface.api import GUI
705
-
757
+
706
758
  #Make copy of points
707
759
  X = self.points.copy()
708
-
760
+
709
761
  if np.shape(color)[0] == np.shape(X)[0]: #scalars for plot
710
762
  opt = 2
711
763
  if histeq:
712
764
  color = color - np.amin(color)
713
765
  color = 1-exposure.equalize_hist(color/np.max(color),nbins=1000)
714
-
766
+
715
767
  if np.shape(np.shape(color))[0]>1: #handle input
716
768
  color = color[:,0]
717
769
  elif max(np.shape(color)) == 3: #single rgb color
@@ -719,7 +771,7 @@ class mesh:
719
771
  else : #not input - default to single color
720
772
  color = (0.7,0.7,0.7)
721
773
  opt = 1
722
-
774
+
723
775
  #PCA
724
776
  Mean = np.mean(X,axis=0)
725
777
  cov_matrix = (X-Mean).T@(X-Mean)
@@ -754,14 +806,14 @@ class mesh:
754
806
 
755
807
  def svi(self,r,ID=None):
756
808
  """ Computes spherical volume invariant.
757
-
809
+
758
810
  Parameters
759
811
  ----------
760
812
  r : (k,1) float array
761
813
  List of radii to use.
762
814
  ID : (n,1) boolean array, default is None
763
- Spherical volume is only computed at points with True indices.
764
-
815
+ Spherical volume is only computed at points with True indices.
816
+
765
817
  Returns
766
818
  -------
767
819
  S : (n,1) float array
@@ -769,7 +821,7 @@ class mesh:
769
821
  G : (n,1) float array
770
822
  The gamma values corresponding to each point.
771
823
  """
772
-
824
+
773
825
  return svi.svi(self.points,self.triangles,r,ID=ID)
774
826
 
775
827
  def svipca(self,r):
@@ -789,7 +841,7 @@ class mesh:
789
841
  K2 : (n,1) float array
790
842
  The second principle curvature for each point.
791
843
  V1 : (n,3) float array
792
- The first principal direction for each point.
844
+ The first principal direction for each point.
793
845
  V2 : (n,3) float array
794
846
  The second principal direction for each point.
795
847
  V3 : (n,3) float array
@@ -800,7 +852,7 @@ class mesh:
800
852
 
801
853
  def edge_graph_detect(self,**kwargs):
802
854
  """ Detects edges using SVIPCA and principal direction metric.
803
-
855
+
804
856
  Parameters
805
857
  ----------
806
858
  M : amaazetools.trimesh.mesh object
@@ -828,7 +880,7 @@ class mesh:
828
880
  Edges : (n,1) boolean array
829
881
  A true value corresponds to that index being an edge point.
830
882
  """
831
-
883
+
832
884
  return edge_detection.edge_graph_detect(self,**kwargs)
833
885
 
834
886
  def graph_setup(self,n,r,p,seed=None):
@@ -844,7 +896,7 @@ class mesh:
844
896
  Weight matrix parameter.
845
897
  seed : int, default is None
846
898
  Optional seed for random number generator.
847
-
899
+
848
900
  Returns
849
901
  -------
850
902
  poisson_W_matrix : (n,n) scipy.sparse.lil_matrix
@@ -865,7 +917,7 @@ class mesh:
865
917
 
866
918
  v = self.vertex_normals()
867
919
  N = self.num_verts()
868
-
920
+
869
921
  #Random subsample
870
922
  ss_idx = np.matrix(rng.choice(self.points.shape[0],n,replace=False))
871
923
  y = np.squeeze(self.points[ss_idx,:])
@@ -875,7 +927,7 @@ class mesh:
875
927
  nn_idx = xTree.query_ball_point(y, r)
876
928
  yTree = spatial.cKDTree(y)
877
929
  nodes_idx = yTree.query_ball_point(y, r)
878
-
930
+
879
931
  bn = np.zeros((n,3))
880
932
  J = sparse.lil_matrix((N,n))
881
933
  for i in range(n):
@@ -883,16 +935,16 @@ class mesh:
883
935
  normal_diff = w[i] - vj
884
936
  weights = np.exp(-8 * np.sum(np.square(normal_diff),1,keepdims=True))
885
937
  bn[i] = np.sum(weights*vj,0) / np.sum(weights,0)
886
-
938
+
887
939
  #Set ith row of J
888
940
  normal_diff = bn[i]- vj
889
941
  weights = np.exp(-8 * np.sum(np.square(normal_diff),1))#,keepdims=True))
890
942
  J[nn_idx[i],i] = weights
891
-
943
+
892
944
  #Normalize rows of J
893
945
  RSM = sparse.spdiags((1 / np.sum(J,1)).ravel(),0,N,N)
894
946
  J = RSM @ J
895
-
947
+
896
948
  #Compute weight matrix W
897
949
  W = sparse.lil_matrix((n,n))
898
950
  for i in range(n):
@@ -900,7 +952,7 @@ class mesh:
900
952
  normal_diff = bn[i] - nj
901
953
  weights = np.exp(-32 * ((np.sqrt(np.sum(np.square(normal_diff),1)))/2)**p)
902
954
  W[i,nodes_idx[i]] = weights
903
-
955
+
904
956
  #Find nearest node to each vertex
905
957
  nbrs = NearestNeighbors(n_neighbors=1, algorithm='ball_tree').fit(y)
906
958
  instances, node_idx = nbrs.kneighbors(self.points)
@@ -908,8 +960,8 @@ class mesh:
908
960
  self.poisson_W_matrix = W
909
961
  self.poisson_J_matrix = J
910
962
  self.poisson_node_idx = node_idx
911
-
912
- return self.poisson_W_matrix, self.poisson_J_matrix, self.poisson_node_idx
963
+
964
+ return self.poisson_W_matrix, self.poisson_J_matrix, self.poisson_node_idx
913
965
 
914
966
  def poisson_label(self,g,I,n=5000,r=0.5,p=1,s=None,graph_setup=False):
915
967
  """ Performs poisson learning on the mesh.
@@ -930,13 +982,13 @@ class mesh:
930
982
  Weights for fine-tuning Poisson learning.
931
983
  graph_setup : boolean, default is False
932
984
  Force graph construction if True.
933
-
985
+
934
986
  Returns
935
987
  -------
936
988
  L : (num_verts,1) int array
937
989
  Poisson labelling of each point in mesh.
938
990
  """
939
-
991
+
940
992
  if graph_setup or (self.poisson_node_idx is None):
941
993
  self.graph_setup(n,r,p)
942
994
 
@@ -955,7 +1007,7 @@ class mesh:
955
1007
  self.poisson_labels = L
956
1008
 
957
1009
  return L
958
-
1010
+
959
1011
  def virtual_goniometer(self,point,r,k=7,SegParam=2,return_edge_points=False,
960
1012
  number_edge_points=None,return_euclidean_radius=False):
961
1013
  """ Runs a virtual goniometer to measure break angles.
@@ -977,7 +1029,7 @@ class mesh:
977
1029
  Specifies how many edge points to return.
978
1030
  return_euclidean_radius : boolean, default is False
979
1031
  If True, returns Euclidean radius of patch.
980
-
1032
+
981
1033
  Returns
982
1034
  -------
983
1035
  theta : float
@@ -1039,10 +1091,10 @@ def __virtual_goniometer__(P,N,SegParam=2,UsePCA=True,UsePower=False):
1039
1091
  SegParam : float, default is 2
1040
1092
  Segmentation parameter that encourages splitting patch in half as it increases in size.
1041
1093
  UsePCA: boolean, default is True
1042
- Uses PCA instead of averaged surface normals if True.
1094
+ Uses PCA instead of averaged surface normals if True.
1043
1095
  UsePower : boolean, default is False
1044
1096
  Uses the power method when doing PCA if True.
1045
-
1097
+
1046
1098
  Returns
1047
1099
  -------
1048
1100
  theta : float
@@ -1107,11 +1159,11 @@ def __virtual_goniometer__(P,N,SegParam=2,UsePCA=True,UsePower=False):
1107
1159
  n1 = n1/np.linalg.norm(n1)
1108
1160
  n2 = np.average(N[C==2,:],axis=0)
1109
1161
  n2 = n2/np.linalg.norm(n2)
1110
-
1162
+
1111
1163
  #Angle between
1112
1164
  theta = 180-np.arccos(np.dot(n1,n2))*180/np.pi
1113
1165
  return theta,n1,n2,C
1114
-
1166
+
1115
1167
  def conjgrad(A,b,x,T,tol):
1116
1168
  """ Performs conjugate gradient descent.
1117
1169
 
@@ -1119,19 +1171,19 @@ def conjgrad(A,b,x,T,tol):
1119
1171
  ----------
1120
1172
  A : matrix multiplying x
1121
1173
  b : vector equal to product of A and x
1122
- x : initial estimate for x
1174
+ x : initial estimate for x
1123
1175
  T : int
1124
1176
  Number of time steps allowed.
1125
1177
  Tol : float
1126
1178
  Desired convergence tolerance of result.
1127
-
1179
+
1128
1180
  Returns
1129
1181
  -------
1130
1182
  x : calculated value for x
1131
1183
  i : int
1132
1184
  Number of iterations required for convergence.
1133
1185
  """
1134
-
1186
+
1135
1187
  r = b - A@x
1136
1188
  p = r
1137
1189
  rsold = np.sum(r * r,0)
@@ -1158,13 +1210,13 @@ def poisson_learning(W,g,I):
1158
1210
  Labels to assign to selected vertices.
1159
1211
  I : (m,1) int array
1160
1212
  Indices of user-selected vertices.
1161
-
1213
+
1162
1214
  Returns
1163
1215
  -------
1164
1216
  u : (num_verts,1) int array
1165
1217
  Poisson labels for each vertex in the mesh.
1166
1218
  """
1167
-
1219
+
1168
1220
  k = len(np.unique(g))
1169
1221
  n = W.shape[0]
1170
1222
  m = len(I)
@@ -1176,19 +1228,19 @@ def poisson_learning(W,g,I):
1176
1228
  F[I[i],g[i]] = 1
1177
1229
  c = np.ones((1,n)) @ F / len(g)
1178
1230
  F[I] -= c
1179
-
1231
+
1180
1232
  deg = np.sum(W,1)
1181
1233
  D = sparse.spdiags(deg.T,0,n,n)
1182
1234
  L = D-W #Unnormalized graph laplacian matrix
1183
-
1235
+
1184
1236
  #Preconditioning
1185
- Dinv2 = sparse.spdiags(np.power(np.sum(W,1),-1/2).T,0,n,n)
1237
+ Dinv2 = sparse.spdiags(np.power(np.sum(W,1),-1/2).T,0,n,n)
1186
1238
  Lnorm = Dinv2 @ L @ Dinv2
1187
1239
  F = Dinv2 @ F
1188
-
1240
+
1189
1241
  #Conjugate Gradient Solver
1190
1242
  u,i = conjgrad(Lnorm,F,np.zeros((n,k)),1e5, np.sqrt(n)*1e-10)
1191
-
1243
+
1192
1244
  #Undo preconditioning
1193
1245
  u = Dinv2 @ u
1194
1246
  return u
@@ -1200,18 +1252,18 @@ def canonical_labels(u):
1200
1252
  ----------
1201
1253
  u : (num_verts,1) int array
1202
1254
  A label vector.
1203
-
1255
+
1204
1256
  Returns
1205
1257
  -------
1206
1258
  u : (num_verts,1) int array
1207
1259
  A reodered label vector.
1208
1260
  """
1209
-
1261
+
1210
1262
  n = len(u)
1211
1263
  k = len(np.unique(u))
1212
1264
  label_set = np.zeros((k,1))
1213
1265
  label = 0
1214
-
1266
+
1215
1267
  for i in range(n):
1216
1268
  if u[i] > label:
1217
1269
  label += 1
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: amaazetools
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: Python package for mesh processing tools developed by AMAAZE
5
5
  Author-email: Jeff Calder <jwcalder@umn.edu>
6
6
  License: MIT
@@ -9,7 +9,7 @@ packages = ['amaazetools']
9
9
 
10
10
  [project]
11
11
  name = "amaazetools"
12
- version = "0.1.2"
12
+ version = "0.1.3"
13
13
  authors = [
14
14
  { name="Jeff Calder", email="jwcalder@umn.edu" },
15
15
  ]
File without changes
File without changes
File without changes
File without changes
File without changes