DM_spatial_processing.py
1 ## @package python.demo.DM_spatial_processing
2 # "
3 # example script showing how to spatially process an ODM.
4 # based on a generic neighborhood definition statistical features
5 # are extracted and attached as attributes to each point
6 # (script works in python 2 and 3)
7 #
8 
9 from __future__ import print_function # print function syntax as in python 3
10 import sys
11 import datetime
12 
13 from opals import pyDM
14 
15 
16 ##
17 # callback object computing an user-defined attribute '_dummy'
18 class Kernel(pyDM.PointKernelEx):
19 
20  def __init__(self):
21  # initialize the base class (mandatory!)
22  if sys.version_info >= (3, 0):
23  super().__init__()
24  else:
25  super(Kernel, self).__init__()
26  return
27 
28  ##
29  # callback notifies about a changed leaf
30  def leafChanged(self, leaf, localTree):
31  print("process tile with id = %d" % leaf.id() )
32  return
33 
34  ##
35  # callback for processing a point
36  def process(self, pt, neighbours):
37 
38  # add neighbour count (_pcount) and z mean of neighbours (_zmean) to the current point
39  zsum = 0
40  for n in neighbours.points():
41  zsum += n.z
42 
43  # numpyDict = neighbours.asNumpyDict() # get neighbours as numpy dict
44 
45  pt.info().set(0, neighbours.sizePoint())
46  if neighbours.sizePoint() > 0:
47  zmean = zsum / float(neighbours.sizePoint())
48  pt.info().set(1, zmean)
49 
50  # return True if the point was changed otherwise False
51  # this internally marks the current point leaf as changed (=needs to be written to disk)
52  return True
53 
54 
55 def DM_spatial_processing(filename, maxOutput=1000):
56  # pyDM.Datamanager.load parameter: filename(string), readOnly(bool) threadSafety(bool)
57  dm = pyDM.Datamanager.load(filename, False, False)
58  if not dm:
59  print("Unable to open ODM '" + odm + "'")
60  sys.exit(1)
61 
62  # creates the appropriate attribute layout for processing
63  lf = pyDM.AddInfoLayoutFactory()
64  lf.addColumn(pyDM.ColumnType.int32, "_pcount") # column 0
65  lf.addColumn(pyDM.ColumnType.float_, "_zmean") # column 1
66  layout = lf.getLayout()
67  kernelLayout = lf.getLayout()
68 
69 
70  # create spatial selection
71  query = pyDM.QueryDescriptor("sphere(r=1)") # use a sphere with radius 1m as neighbourhood definition (textual description)
72  # sphere = pyDM.QuerySphere(r=1) # sphere with radius 1m (class based description)
73  # knn = pyDM.QueryKnn(k=12,dim=3) # 3d knn with 12 neighbours (class based description)
74  # query = pyDM.QueryDescriptor(sphere) # create actual neighbourhood definition: fixed distance
75  # query = pyDM.QueryDescriptor(knn & sphere) # create actual neighbourhood definition: knn with a maximum search radius
76 
77  print("Ready to append attribute '_pcount' to '%s'" % filename)
78 
79  print("Number of tiles to process = %d" % dm.getPointIndex().sizeLeaf())
80 
81  # create kernel object
82  k = Kernel()
83 
84  start = datetime.datetime.now()
85  # create processor
86  # pyDM.ProcessorEx parameter: dm(datamnager), query(QueryDescriptor),
87  # processFilter, processLayout, processLayoutReadOnly,
88  # neighbourFilter, neighbourLayout, neighbourLayoutReadOnly
89  processor = pyDM.ProcessorEx(dm, query, None, layout, False, None, None, False)
90  processor.run(k) # perform computation
91 
92  diff = datetime.datetime.now() - start
93  print("Processing took %.2f [s]" % diff.total_seconds() )
94 
95  # save manager object
96  print("Save manager")
97  dm.save()
98 
99  print("done")
100 
101 if len(sys.argv) == 1:
102  print("ODM parameter missing")
103  sys.exit(-1)
104 
105 DM_spatial_processing(sys.argv[1])