demoSegmentation.py
1 ## @package python.demo.demoSegmentation
2 #
3 # example script showing how to use opalsSegmentation
4 # and access its results based on the segment manager.
5 # If the parameter alphaRadius is used, segment alpha shapes can be accessed and visualized.
6 # For both segmentation methods (conditional clustering and plane extraction), example parameters are set.
7 #
8 
9 from __future__ import print_function
10 import matplotlib
11 matplotlib.use('Agg') # use matplotlib without DISPLAY
12 import scipy
13 import numpy as np
14 
15 import matplotlib.pyplot as plt
16 from mpl_toolkits.mplot3d import Axes3D
17 
18 import opals
19 from opals import pyDM
20 from opals import Segmentation, Import, Normals
21 
22 
23 def set_axes_radius(ax, origin, radius):
24  ax.set_xlim3d([origin[0] - radius, origin[0] + radius])
25  ax.set_ylim3d([origin[1] - radius, origin[1] + radius])
26  ax.set_zlim3d([origin[2] - radius, origin[2] + radius])
27 
28 ##
29 # Make axes of 3D plot have equal scale so that spheres appear as spheres,
30 # cubes as cubes, etc.. This is one possible solution to Matplotlib's
31 # ax.set_aspect('equal') and ax.axis('equal') not working for 3D.
32 #
33 # Input
34 # ax: a matplotlib axis, e.g., as output from plt.gca().
35 #
36 def set_axes_equal(ax):
37 
38  limits = np.array([
39  ax.get_xlim3d(),
40  ax.get_ylim3d(),
41  ax.get_zlim3d(),
42  ])
43 
44  origin = np.mean(limits, axis=1)
45  radius = 0.5 * np.max(np.abs(limits[:, 1] - limits[:, 0]))
46  set_axes_radius(ax, origin, radius)
47 
48 
49 ##
50 # output all attribute values within an addinfo object
51 def output_addinfo(info):
52  print(" attributes: ",end="")
53  if info.columns() == 0:
54  print("NONE")
55  else:
56  for i in range(info.columns()):
57  if i > 0:
58  print(", ", end="")
59 
60  print(info.name(i)+"=", end="")
61  if info.isNull(i):
62  print("NULL", end="")
63  else:
64  print(info.get(i), end="")
65 
66  print() #line feed
67 
68 
69 ##
70 # Run necessary preprocessing steps for the point cloud
71 # e.g. Import point cloud into OPALS Datamanager (odm) with opalsImport,
72 # Compute normal vectors with opalsNormals
73 #
74 def preprocessing_steps(name):
75  imp = Import.Import(inFile=name+".laz",tileSize=100,filter="generic[z>265]")
76  imp.run()
77 
78  normals = Normals.Normals(inFile=name+".odm", normalsAlg=opals.Types.NormalsAlgorithm.simplePlane, neighbours=8, searchMode=opals.Types.SearchMode.d2, searchRadius=1)
79  normals.run()
80 
81 
82 # ATTENTION: programm needs to be excecuted within the opals demo directory or
83 # copy strip21.laz in your current directory
84 
85 # necessary preprocessing steps
86 filename_stem = "strip21"
87 preprocessing_steps(filename_stem)
88 
89 # Select SegmentationMethod here:
90 # mode = opals.Types.SegmentationMethod.planeExtraction
91 # or
92 mode = opals.Types.SegmentationMethod.condClustering
93 
94 # perform segmentation using plane extraction mode and alpha shape computation
95 mod = Segmentation.Segmentation()
96 
97 filename = filename_stem+".odm"
98 if mode == opals.Types.SegmentationMethod.planeExtraction:
99  mod.inFile = filename
100  mod.searchRadius = 1
101  mod.minSegSize = 50
102  mod.method = opals.Types.SegmentationMethod.planeExtraction
103  mod.planeExtraction.maxDist = 0.2
104  mod.planeExtraction.maxSigma = 0.15
105  mod.planeExtraction.seedCalculator = "NormalSigma0<0.02 AND Z > 275 ? NormalSigma0 : invalid"
106  mod.filter = ["Region[529568.8 5338773.5 529863 5338773.9 529862.6 5338642.4 529706 5338685.4 529569.1 5338753.8]"]
107  mod.alphaRadius = 1
108  mod.sort = opals.Types.SegmentSort.descendingPSize
109 elif mode == opals.Types.SegmentationMethod.condClustering:
110  mod.inFile = filename
111  mod.searchRadius = 1
112  mod.minSegSize = 50
113  mod.method = opals.Types.SegmentationMethod.condClustering
114  mod.condClustering.criterion = "normalX*n[0].normalX+normalY*n[0].normalY+normalZ*n[0].normalZ>0.996"
115  # mod.condClustering.alphaShapeRefPlane = [0, 0, 1]
116  mod.alphaRadius = 1
117  mod.sort = opals.Types.SegmentSort.descendingPSize
118 mod.run()
119 
120 # get segmentation manager (gives access to the segment objects)
121 segManager = mod.segments
122 
123 # pyDM.Datamanager.load parameter: filename(string), readOnly(bool) threadSafety(bool)
124 odm = pyDM.Datamanager.load(filename, True, False)
125 pi = odm.getPointIndex() # get point index object of odm
126 
127 print("The segmentation process has found "+str(segManager.sizeSegments())+" segment(s)")
128 
129 max_pt_output = 5
130 fig = plt.figure()
131 ax = fig.add_subplot(111, projection='3d')
132 
133 # iterate over all segments and output relevant segments properties
134 for seg in segManager.getSegments():
135  # print basic segment information
136  print("Segment-Nr %d:\t %d points; COG (%.3f / %.3f / %.3f)" % (seg.getID(), seg.sizePoints(), seg.getCoG().x, seg.getCoG().y, seg.getCoG().z ) )
137 
138  # get plane parameters
139  try:
140  planeParams = seg.getPlaneParams()
141  assert len(planeParams) == 5
142  print("\tplane parameters: a=%.4f b=%.4f c=%.4f d=%.4f (sigma0=%.3f)" % tuple(planeParams) )
143  except:
144  print("No plane params")
145 
146  # get alpha shape (can be empty in case the computation failed)
147  alphaShape = seg.getAlphaShape()
148  if alphaShape:
149  print("\talpha shape consists of %d parts:" % alphaShape.sizePart())
150  # get random color for segment alpha shape
151  col = matplotlib.colors.rgb2hex(scipy.rand(3))
152  for idx, part in enumerate(alphaShape.parts()):
153  print("\t\t%d part has %3d points" % (idx,part.sizePoint()), end="")
154  vtx_x = []
155  vtx_y = []
156  vtx_z = []
157  for pt in part.points():
158  vtx_x.append(pt.x)
159  vtx_y.append(pt.y)
160  vtx_z.append(pt.z)
161  if len(vtx_x) < 3:
162  print("Len < 3")
163  # plot alpha shape
164  tri = ax.plot3D(vtx_x, vtx_y, vtx_z, color=col)
165 
166  output_addinfo(part.info())
167 
168  # get segment point ids and print the first "max_pt_output" points
169  print("\touput the first %d points: " % max_pt_output)
170  ptIds = seg.getPoints()
171  for idx, id in enumerate(ptIds):
172  pt = pi.getPoint(id)
173  print("\t\t%2d.point (%.3f / %.3f / %.3f)" % (idx, pt.x, pt.y, pt.z) )
174  if idx+1 >= max_pt_output:
175  break
176 
177 set_axes_equal(ax)
178 plt.axis('off')
179 
180 #plt.show() # use this command to display 3d graphic view
181 plt.savefig(filename_stem+"_alphaShapes.svg") # write figure as svg graph