1import brl_init
2import boxm2_batch as batch
3dbvalue = brl_init.register_batch(batch)
4
5import os
6import re
7import shutil
8import sys
9from xml.etree.ElementTree import ElementTree
10from os.path import basename, splitext
11
12import boxm2_adaptor
13import boxm2_tools_adaptor
14import boxm2_filtering_adaptor
15import vil_adaptor_boxm2_batch as vil_adaptor
16import vpgl_adaptor_boxm2_batch as vpgl_adaptor
17
18
19#############################################################################
20# boxm2_scene_adaptor class offers super simple model manipulation syntax
21# you can always force the process to use CPP by just passing in "cpp" as the last
22# arg to any function in this class
23#############################################################################
24
25
26class boxm2_scene_adaptor(object):
27
28    # scene adaptor init
29    def __init__(self, scene_str, device_string="gpu",
30                 opencl_multi_scene_cache=False):
31
32        # init (list) self vars
33        self.scene = None
34        self.active_cache = None
35        self.device_string = None
36        self.cpu_cache = None
37        self.device = None
38        self.opencl_cache = None
39        self.str_cache = None
40        self.model_dir = None
41        self.bbox = None
42        self.lvcs = None
43
44        # if device_string is gpu, load up opencl
45        self.device_string = device_string
46        if device_string[0:3] == "gpu" or device_string[0:3] == "cpu":
47            self.scene, self.cpu_cache, self.device, self.opencl_cache = \
48                boxm2_adaptor.load_opencl(scene_str, device_string)
49            self.active_cache = self.opencl_cache
50        elif device_string[0:3] == "cpp":
51            self.scene, self.cpu_cache = boxm2_adaptor.load_cpp(scene_str)
52            self.active_cache = self.cpu_cache
53        else:
54            print "UNKNOWN device type: ", device_string
55            print "exiting."
56            exit(-1)
57        # store model directory for later use
58        self.bbox = boxm2_adaptor.scene_bbox(self.scene)
59        self.description = boxm2_adaptor.describe_scene(self.scene)
60        self.model_dir = self.description['dataPath']
61        # stores whether appearance model contains RGB - also includes view_dep
62        self.rgb = self.description['appType'] == "boxm2_gauss_rgb"
63        self.lvcs = boxm2_adaptor.scene_lvcs(self.scene)
64        self.view = ("view" in self.description['appType'])
65
66    def __del__(self):
67        if self.scene is not None:
68            batch.remove_data(self.scene.id)
69        if self.cpu_cache is not None:
70            batch.remove_data(self.cpu_cache.id)
71        if self.device is not None:
72            batch.remove_data(self.device.id)
73        if self.opencl_cache is not None:
74            batch.remove_data(self.opencl_cache.id)
75        if self.lvcs is not None:
76            batch.remove_data(self.lvcs.id)
77
78    # describe scene (returns data path)
79    def describe(self):
80        return self.description
81
82    def modify_appearance(self, app1, app2):
83        status = boxm2_adaptor.modify_scene_appearance(self.scene, app1, app2)
84        self.rgb = self.description['appType']
85        return status
86    # returns scene bounding box
87
88    def bounding_box(self):
89        return self.bbox
90
91    def lvcs(self):
92        return self.lvcs
93
94    def cache():
95        return self.cache
96    def _get_device_cache(self, device_string):
97        dev = self.device
98
99        if device_string:
100            # check if force gpu or cpu
101            if device_string[0:3] == "gpu" or device_string[0:3] == "cpu":
102                cache = self.opencl_cache
103            elif device_string == "cpp":
104                cache = self.cpu_cache
105                dev = None
106        else:
107            cache = self.active_cache
108
109        return (dev, cache)
110
111    def transform_to_scene(self, to_scene, trans, rot, scale):
112        if self.opencl_cache.type == "boxm2_opencl_cache_sptr":
113            print("transforming scene")
114            batch.init_process("boxm2VecfOclTransformSceneProcess")
115            batch.set_input_from_db(0, self.scene)
116            batch.set_input_from_db(1, to_scene)
117            batch.set_input_from_db(2, self.opencl_cache)
118            batch.set_input_double(3, trans[0])
119            batch.set_input_double(4, trans[1])
120            batch.set_input_double(5, trans[2])
121            batch.set_input_double(6,  rot[0][0])
122            batch.set_input_double(7,  rot[0][1])
123            batch.set_input_double(8,  rot[0][2])
124            batch.set_input_double(9,  rot[1][0])
125            batch.set_input_double(10, rot[1][1])
126            batch.set_input_double(11, rot[1][2])
127            batch.set_input_double(12, rot[2][0])
128            batch.set_input_double(13, rot[2][1])
129            batch.set_input_double(14, rot[2][2])
130            batch.set_input_double(15, scale[0])
131            batch.set_input_double(16, scale[1])
132            batch.set_input_double(17, scale[2])
133
134            return batch.run_process()
135        else:
136            print "ERROR: Cache type not recognized: ", self.opencl_cache.type
137            return False
138
139    def init_alpha(self, pinit=0.01, thresh=1.0):
140        cache = self.opencl_cache
141        dev = self.device
142        boxm2_adaptor.init_alpha(self.scene, cache, dev, pinit, thresh)
143
144    # update with alternate explaination prior and appearance density
145    def update_with_alt(self, cam, img, update_alpha=True,
146                        mask=None, var=-1.0, alt_prior=None, alt_density=None):
147        cache = self.opencl_cache
148        dev = self.device
149        boxm2_adaptor.update_grey_with_alt(self.scene, cache, cam, img, dev,
150                                           "", mask, update_alpha, var, alt_prior, alt_density)
151    # update wrapper, can pass in a Null device to use
152
153    def update(self, cam, img, update_alpha=True, update_app=True, mask=None,
154               device_string="", var=-1.0, ident_string="", tnear=100000.0, tfar=100000.0):
155        dev, cache = self._get_device_cache(device_string)
156
157        # run update grey or RGB
158        if self.rgb:
159            if self.view:
160                return boxm2_adaptor.update_rgb_view_dep(self.scene, cache, cam, img, dev,
161                                                         ident_string, mask, update_alpha, var)
162            else:
163                return boxm2_adaptor.update_rgb(self.scene, cache, cam,
164                                  img, dev, "", update_alpha)
165        else:
166            if self.view:
167                return boxm2_adaptor.update_grey_view_dep(self.scene, cache, cam, img, dev,
168                                            ident_string, mask, update_alpha, var)
169            else:
170                return boxm2_adaptor.update_grey(self.scene, cache, cam, img, dev, ident_string,
171                                   mask, update_alpha, var, update_app, tnear, tfar)
172
173    # update wrapper, can pass in a Null device to use
174    def update_app(self, cam, img, device_string="", force_grey=False):
175        if device_string and device_string[0:3] == "cpp":
176            print " Not  implemented in C++ yet "
177            return
178
179        dev, cache = self._get_device_cache(device_string)
180
181        if self.rgb and not force_grey:
182            boxm2_adaptor.update_rgb(self.scene, cache, cam, img, dev, "", False)
183        else:
184            boxm2_adaptor.update_app_grey(self.scene, cache, cam, img, dev)
185
186    # update skky wrapper, can pass in a Null device to use
187    def update_sky(self, cam, img, device_string=""):
188        if device_string and device_string[0:3] == "cpp":
189            print " Not  implemented in C++ yet "
190            return
191
192        dev, cache = self._get_device_cache(device_string)
193
194        boxm2_adaptor.update_sky(self.scene, cache, cam, img, dev)
195    # update skky wrapper, can pass in a Null device to use
196
197    def update_sky2(self, cam, img, step, device_string=""):
198        if device_string and device_string[0:3] == "cpp":
199            print " Not  implemented in C++ yet "
200            return
201
202        dev, cache = self._get_device_cache(device_string)
203
204        boxm2_adaptor.update_sky2(self.scene, cache, cam, img, step, dev)
205
206    # render wrapper, same as above
207    def render(self, cam, ni=1280, nj=720, device_string="", ident_string="",
208               tnear=1000000.0, tfar=1000000.0, ):
209        dev, cache = self._get_device_cache(device_string)
210        if self.rgb:
211            if self.view:
212                expimg = boxm2_adaptor.render_rgb_view_dep(self.scene, cache, cam,
213                                             ni, nj, dev, ident_string)
214            else:
215                expimg, vis_image, status = boxm2_adaptor.render_rgb(
216                    self.scene, cache, cam, ni, nj, dev, tnear, tfar)
217                batch.remove_data(vis_image.id)
218        else:
219            if self.view:
220                expimg = boxm2_adaptor.render_grey_view_dep(self.scene, cache, cam,
221                                              ni, nj, dev, ident_string)
222            else:
223                expimg = boxm2_adaptor.render_grey(self.scene, cache, cam,
224                                     ni, nj, dev, ident_string, tnear, tfar)
225        return expimg
226
227    # render wrapper, same as above
228    def render_vis(self, cam, ni=1280, nj=720, device_string="", ident=""):
229        dev, cache = self._get_device_cache(device_string)
230        if self.rgb:
231            expimg, vis_image, status = boxm2_adaptor.render_rgb(
232                self.scene, cache, cam, ni, nj, dev)
233        else:
234            expimg, vis_image = boxm2_adaptor.render_grey_and_vis(
235                self.scene, cache, cam, ni, nj, dev, ident)
236        return expimg, vis_image
237
238    # render depth image wrapper
239    def render_depth(self, cam, ni=1280, nj=720, device_string=""):
240        dev, cache = self._get_device_cache(device_string)
241        expimg, varimg, visimg = boxm2_adaptor.render_depth(
242            self.scene, cache, cam, ni, nj, dev)
243        return expimg, varimg, visimg
244
245    # render the depth of the surfaces with max probability of being the the
246    # first visible and occupied surface along the rays
247    def render_depth_of_max_prob_surface(
248          self, cam, ni=1280, nj=720, device_string=""):
249        dev, cache = self._get_device_cache(device_string)
250        expimg, probimg, visimg = boxm2_adaptor.render_depth_of_max_prob_surface(
251            self.scene, cache, cam, ni, nj, dev)
252        return expimg, probimg, visimg
253
254    # render depth image with loading given region wrapper
255    def render_depth_region(self, cam, lat, lon, elev,
256                            radius, ni=1280, nj=720, device_string=""):
257        dev, cache = self._get_device_cache(device_string)
258        expimg, varimg, visimg = boxm2_adaptor.render_depth_region(
259            self.scene, cache, cam, lat, lon, elev, radius, ni, nj, dev)
260        return expimg, varimg, visimg
261
262    # render z image wrapper
263    def render_z_image(self, cam, ni=1280, nj=720,
264                       normalize=False, device_string=""):
265        dev, cache = self._get_device_cache(device_string)
266        z_exp_img, z_var_img = boxm2_adaptor.render_z_image(
267            self.scene, cache, cam, ni, nj, normalize, dev)
268        return z_exp_img, z_var_img
269
270    # render heigh map render
271    def render_height_map(self, device_string=""):
272        dev, cache = self._get_device_cache(device_string)
273        z_image, var_image, x_image, y_image, prob_image = \
274            boxm2_adaptor.render_height_map(self.scene, cache, dev)
275        return z_image, var_image, x_image, y_image, prob_image
276
277    # ingest heigh map
278    def ingest_height_map(self, x_img, y_img, z_img,
279                          zero_out_alpha=True, device_string=""):
280        dev, cache = self._get_device_cache(device_string)
281        boxm2_adaptor.ingest_height_map(self.scene, cache, x_img, y_img,
282                                        z_img, zero_out_alpha, dev)
283        return
284
285    # ingest heigh map
286    def ingest_height_map_space(
287            self, x_img, y_img, z_img, crust_thickness, device_string=""):
288        dev, cache = self._get_device_cache(device_string)
289        boxm2_adaptor.ingest_height_map_space(self.scene, cache, x_img,
290                                              y_img, z_img, crust_thickness, dev)
291        return
292
293    # ingest to zero out alphas along the rays given by the input images
294    def ingest_to_zero_out_alpha(self, x_img, y_img, z_img, device_string=""):
295        dev, cache = self._get_device_cache(device_string)
296        boxm2_adaptor.ingest_to_zero_out_alpha(self.scene, cache, x_img, y_img,
297                                               z_img, dev)
298        return
299
300    # ingest label map
301    # def ingest_label_map(self,x_img,y_img,z_img,label_img,device_string="") :
302    def ingest_label_map(self, x_img, y_img, z_img,
303                         label_img, ident, device_string=""):
304        dev, cache = self._get_device_cache(device_string)
305        # ingest_label_map(self.scene, cache, x_img, y_img, z_img, label_img, dev);
306        boxm2_adaptor.ingest_label_map(self.scene, cache, x_img, y_img,
307                                       z_img, label_img, ident, dev)
308        return
309
310    # ingest label map
311    def ingest_osm_label_map(self, x_img, y_img, z_img,
312                             label_img, ident="land", device_string=""):
313        dev, cache = self._get_device_cache(device_string)
314        boxm2_adaptor.ingest_osm_label_map(self.scene, cache, x_img,
315                                           y_img, z_img, label_img, ident, dev)
316        return
317
318    # ingest buckeye-style dem
319    def ingest_buckeye_dem(self, first_ret_fname, last_ret_fname,
320                           geoid_height, geocam, device_string=""):
321        dev, cache = self._get_device_cache(device_string)
322        boxm2_adaptor.ingest_buckeye_dem(self.scene, cache, first_ret_fname,
323                                         last_ret_fname, geoid_height, geocam,
324                                         dev)
325        return
326
327    def probability_of(self, cam, image):
328        cache = self.active_cache
329        dev = self.device
330        outimg = boxm2_adaptor.compute_probability_of_image(
331            self.device, self.scene, self.opencl_cache, cam, image)
332        return outimg
333
334    def cubic_probability_of(self, cam, image, model_ident, img_ident):
335        cache = self.active_cache
336        dev = self.device
337        outimg = boxm2_adaptor.cubic_compute_probability_of_image(
338            self.device, self.scene, self.opencl_cache, cam, image, model_ident, img_ident)
339        return outimg
340
341    # detect change wrapper,
342    def change_detect(self, cam, img, exp_img, n=1, raybelief="",
343                      max_mode=False, rgb=False, device_string="", ident=""):
344        dev, cache = self._get_device_cache(device_string)
345        cd_img = boxm2_adaptor.change_detect(self.scene, cache, cam, img,
346                                             exp_img, dev, rgb, n, raybelief, max_mode, ident)
347        return cd_img
348
349    # detect change wrapper,
350    def change_detect2(self, cam, img, identifier="", max_mode=False,
351                       tnear=10000000, tfar=0.00001, device_string=""):
352        dev, cache = self._get_device_cache(device_string)
353        cd_img, vis_img = boxm2_adaptor.change_detect2(
354            self.scene, cache, cam, img, identifier, max_mode, tnear, tfar, dev)
355        return cd_img, vis_img
356
357    def refine(self, thresh=0.3, device_string=""):
358        dev, cache = self._get_device_cache(device_string)
359        return boxm2_adaptor.refine(self.scene, cache, thresh, dev)
360
361    def merge(self, thresh=0.3, device_string=""):
362        dev, cache = self._get_device_cache(device_string)
363        boxm2_adaptor.merge(self.scene, cache, thresh, dev)
364
365    def median_filter(self, device_string=""):
366        dev, cache = self._get_device_cache(device_string)
367        boxm2_adaptor.median_filter(self.scene, cache, dev)
368
369    # given the scene, chip the NITF and setup the camera
370    def roi_init(self, NITF_path, camera, convert_to_8bit,
371                 params_fname, margin=0, clip_width=-1, clip_height=-1):
372        return boxm2_adaptor.roi_init(NITF_path, camera, self.scene, convert_to_8bit,
373                                      params_fname, margin, clip_width, clip_height)
374
375    # Apply multiple filters to  scene
376    def kernel_vector_filter(self, filters):
377        return boxm2_filtering_adapto.apply_filters(self.scene, self.opencl_cache,
378                                                    self.device, filters)
379
380    # Interpolate normal from various responses
381    def interpolate_normals(self, filters):
382        return boxm2_filtering_adaptor.interpolate_normals(self.scene,
383                                                           self.opencl_cache, self.device, filters)
384
385    # Extract cell centers to XYZ for fast access
386    def extract_cell_centers(self, prob_thresh=0.0):
387        return boxm2_tools_adaptor.extract_cell_centers(self.scene,
388                                                        self.cpu_cache, prob_thresh=0.0)
389
390    #  Flip normals towards direction of maximum visibility
391    def flip_normals(self, use_sum=False):
392        return boxm2_filtering_adaptor.flip_normals(self.scene,
393                                                    self.opencl_cache, self.device, use_sum)
394
395    # Export points and normals to a .PLY file or XYZ. Points and normals need
396    # to be extracted first
397    def export_points_and_normals(self, file_out, save_aux=True,
398                                  prob_thresh=0.0, vis_thresh=0.0,
399                                  nmag_thresh=0.0, exp_thresh=0.0,
400                                  bbox_file=""):
401        return boxm2_tools_adaptor.export_points_and_normals(self.scene,
402                                                             self.cpu_cache, file_out, save_aux, prob_thresh, vis_thresh,
403                                                             nmag_thresh, exp_thresh, bbox_file)
404
405    # Adds auxiliary data to vertices in a .PLY
406    def add_aux_info_to_ply(self, file_in, file_out):
407        boxm2_tools_adaptor.add_aux_info_to_ply(self.scene, self.cpu_cache,
408                                                file_in, file_out)
409
410    # only write the cpu_cache to disk
411    def write_cache(self, do_clear=0):
412        boxm2_adaptor.write_cache(self.cpu_cache, do_clear)
413
414    # clear cache (both caches if OPENCL scene)
415    def clear_cache(self):
416        boxm2_adaptor.clear_cache(self.cpu_cache)
417        if self.opencl_cache:
418            boxm2_adaptor.clear_cache(self.opencl_cache)
419
420    ################################
421    # get info functions
422    def get_info_along_ray(self, cam, u, v, prefix, identifier=""):
423        return boxm2_tools_adaptor.get_info_along_ray(self.scene,
424                                                      self.cpu_cache, cam, u, v, prefix, identifier)
425
426    def query_cell_brdf(self, point, model_type):
427        return boxm2_tools_adaptor.query_cell_brdf(self.scene, self.cpu_cache,
428                                                   point, model_type)
429
430    #####################################################################
431    ######### BATCH UPDATE METHODS ######################################
432    #####################################################################
433    def create_stream_cache(self, imgs, interval=1, types="", max_gb=6.0):
434
435        # write image identifiers to file
436        # imgRange = range(0, len(imgs), interval);
437        # num_imgs = len(imgRange);
438        image_id_fname = self.model_dir + "/image_list.txt"
439        fd = open(image_id_fname, "w")
440        print >> fd, len(imgs)
441        # for i in imgRange:
442        #  print >>fd, "img_%05d"%i
443        for img in imgs:
444            fname, fextension = os.path.splitext(img)
445            bname = os.path.basename(fname)
446            print >> fd, bname
447        fd.close()
448
449        # write type identifiers into file
450        type_id_fname = self.model_dir + "/type_names_list.txt"
451        fd2 = open(type_id_fname, "w")
452        print >>fd2, 4
453        print >>fd2, "aux0"
454        print >>fd2, "aux1"
455        print >>fd2, "aux2"
456        print >>fd2, "aux3"
457        fd2.close()
458
459        # open the stream cache, this is a read-only cache
460        batch.init_process("boxm2CreateStreamCacheProcess")
461        batch.set_input_from_db(0, self.scene)
462        batch.set_input_string(1, type_id_fname)
463        batch.set_input_string(2, image_id_fname)
464        batch.set_input_float(3, max_gb)
465        batch.run_process()
466        (cache_id, cache_type) = batch.commit_output(0)
467        self.str_cache = dbvalue(cache_id, cache_type)
468
469    # remove stream cache object from database
470    def destroy_stream_cache(self):
471        if self.str_cache:
472            batch.remove_data(self.str_cache.id)
473            self.str_cache = None
474
475    # writes aux data for each image in imgs array
476    def write_aux_data(self, imgs, cams):
477        for idx in range(len(imgs)):
478            print '--------------------------'
479            print "processing image " + imgs[idx]
480
481            # load cam/img
482            img, ni, nj = vil_adaptor.load_image(imgs[idx])
483            pcam = vpgl_adaptor.load_perspective_camera(cams[idx])
484            gcam = vpgl_adaptor.persp2gen(pcam, ni, nj)
485
486            # update aux per view call
487            fname, fextension = os.path.splitext(imgs[idx])
488            imageID = os.path.basename(fname)
489            self.update_aux(img, gcam, imageID)
490
491    # create an imagewise aux buffer for cam/img
492    def update_aux(self, img, cam, imgId, device_string="", mask=None):
493        dev, cache = self._get_device_cache(device_string)
494        boxm2_adaptor.update_aux_per_view(self.scene, cache, img, cam, imgId,
495                                          dev, mask)
496
497    # create an imagewise aux buffer for batch update of normal-albedo-array
498    # appearance model
499    def update_aux_naa(self, img, cam, metadata, atm_params, imgId, alt_prior,
500                       alt_density):
501        boxm2_adaptor.update_aux_per_view_naa(self.scene, self.opencl_cache,
502                                              img, cam, metadata, atm_params, imgId, alt_prior, alt_density,
503                                              self.device)
504
505    # takes already created aux buffers (for each image) and fits a Mixture of 3
506    # Gaussians to each cell, saves the appearance
507    def batch_paint(self, imgs, cams, device_string=""):
508        # verify stream cache
509        if (self.str_cache is None):
510            self.create_stream_cache(imgs)
511
512        # sigma norm table?
513        under_estimation_probability = 0.2
514        batch.init_process("bstaSigmaNormTableProcess")
515        batch.set_input_float(0, under_estimation_probability)
516        batch.run_process()
517        (id, type) = batch.commit_output(0)
518        n_table = dbvalue(id, type)
519
520        # call batch paint process
521        if device_string == "":
522            batch.init_process("boxm2OclPaintBatchProcess")
523            batch.set_input_from_db(0, self.device)
524            batch.set_input_from_db(1, self.scene)
525            batch.set_input_from_db(2, self.opencl_cache)
526            batch.set_input_from_db(3, self.str_cache)
527            batch.set_input_from_db(4, n_table)
528            batch.run_process()
529        elif device_string == "cpu":
530            batch.init_process("boxm2CppBatchUpdateAppProcess")
531            batch.set_input_from_db(0, self.scene)
532            batch.set_input_from_db(1, self.cpu_cache)
533            batch.set_input_from_db(2, self.str_cache)
534            batch.set_input_from_db(3, n_table)
535            batch.run_process()
536
537        # close the files so that they can be reloaded after the next iteration
538        batch.init_process("boxm2StreamCacheCloseFilesProcess")
539        batch.set_input_from_db(0, self.str_cache)
540        batch.run_process()
541
542        # write out afterwards
543        self.write_cache()
544
545    def cpu_batch_paint(self, imgs, cams):
546        if (self.str_cache is None):
547            self.create_stream_cache(imgs)
548
549        # sigma norm table?
550        under_estimation_probability = 0.2
551        batch.init_process("bstaSigmaNormTableProcess")
552        batch.set_input_float(0, under_estimation_probability)
553        batch.run_process()
554        (id, type) = batch.commit_output(0)
555        n_table = dbvalue(id, type)
556
557        # loop over images creating aux data
558        for idx in range(0, len(imgs)):
559
560            # load cam/img
561            img, ni, nj = vil_adaptor.load_image(imgs[idx])
562            pcam = vpgl_adaptor.load_perspective_camera(cams[idx])
563            gcam = vpgl_adaptor.persp2gen(pcam, ni, nj)
564
565            # create norm intensity (num rays...)
566            batch.init_process("boxm2CppCreateNormIntensitiesProcess")
567            batch.set_input_from_db(0, self.scene)
568            batch.set_input_from_db(1, self.cpu_cache)
569            batch.set_input_from_db(2, gcam)
570            batch.set_input_from_db(3, img)
571            batch.set_input_string(4, "img_" + "%05d" % idx)
572            batch.run_process()
573
574            # create aux
575            batch.init_process("boxm2CppCreateAuxDataOPT2Process")
576            batch.set_input_from_db(0, self.scene)
577            batch.set_input_from_db(1, self.cpu_cache)
578            batch.set_input_from_db(2, gcam)
579            batch.set_input_from_db(3, img)
580            batch.set_input_string(4, "img_" + "%05d" % idx)
581            batch.run_process()
582            self.write_cache(True)
583
584        batch.init_process("boxm2CppBatchUpdateOPT2Process")
585        batch.set_input_from_db(0, self.scene)
586        batch.set_input_from_db(1, self.cpu_cache)
587        batch.set_input_from_db(2, self.str_cache)
588        batch.set_input_from_db(3, n_table)
589        batch.run_process()
590
591        # close the files so that they can be reloaded after the next iteration
592        batch.init_process("boxm2StreamCacheCloseFilesProcess")
593        batch.set_input_from_db(0, self.str_cache)
594        batch.run_process()
595
596        self.write_cache()
597
598    def cpu_batch_compute_normal_albedo(
599          self, metadata_filename_list, atmospheric_params_filename_list):
600        batch.init_process("boxm2CppBatchComputeNormalAlbedoProcess")
601        batch.set_input_from_db(0, self.scene)
602        batch.set_input_from_db(1, self.cpu_cache)
603        batch.set_input_from_db(2, self.str_cache)
604        batch.set_input_string(3, metadata_filename_list)
605        batch.set_input_string(4, atmospheric_params_filename_list)
606        batch.run_process()
607
608        # close the files so that they can be reloaded after the next iteration
609        batch.init_process("boxm2StreamCacheCloseFilesProcess")
610        batch.set_input_from_db(0, self.str_cache)
611        batch.run_process()
612
613    def ocl_batch_compute_normal_albedo(
614          self, img_id_list, metadata_filename_list, atmospheric_params_filename_list):
615        batch.init_process(
616            "boxm2OclBatchComputeNormalAlbedoArrayProcess")
617        batch.set_input_from_db(0, self.device)
618        batch.set_input_from_db(1, self.scene)
619        batch.set_input_from_db(2, self.opencl_cache)
620        batch.set_input_string(3, img_id_list)
621        batch.set_input_string(4, metadata_filename_list)
622        batch.set_input_string(5, atmospheric_params_filename_list)
623        batch.run_process()
624
625    def render_expected_image_naa(
626          self, camera, ni, nj, metadata, atmospheric_params):
627        batch.init_process("boxm2OclRenderExpectedImageNAAProcess")
628        batch.set_input_from_db(0, self.device)
629        batch.set_input_from_db(1, self.scene)
630        batch.set_input_from_db(2, self.opencl_cache)
631        batch.set_input_from_db(3, camera)
632        batch.set_input_unsigned(4, ni)
633        batch.set_input_unsigned(5, nj)
634        batch.set_input_from_db(6, metadata)
635        batch.set_input_from_db(7, atmospheric_params)
636        batch.run_process()
637        (id, type) = batch.commit_output(0)
638        exp_image = dbvalue(id, type)
639        (id, type) = batch.commit_output(1)
640        mask_image = dbvalue(id, type)
641        return(exp_image, mask_image)
642
643    def update_alpha_naa(self, image, camera, metadata,
644                         atmospheric_params, alt_prior, alt_density):
645        batch.init_process("boxm2OclUpdateAlphaNAAProcess")
646        batch.set_input_from_db(0, self.device)
647        batch.set_input_from_db(1, self.scene)
648        batch.set_input_from_db(2, self.opencl_cache)
649        batch.set_input_from_db(3, camera)
650        batch.set_input_from_db(4, image)
651        batch.set_input_from_db(5, metadata)
652        batch.set_input_from_db(6, atmospheric_params)
653        batch.set_input_from_db(7, alt_prior)
654        batch.set_input_from_db(8, alt_density)
655        if not (batch.run_process()):
656            print("ERROR: run_process() returned False")
657        return
658
659    def render_expected_albedo_normal(self, camera, ni, nj):
660        batch.init_process("boxm2OclRenderExpectedAlbedoNormalProcess")
661        batch.set_input_from_db(0, self.device)
662        batch.set_input_from_db(1, self.scene)
663        batch.set_input_from_db(2, self.opencl_cache)
664        batch.set_input_from_db(3, camera)
665        batch.set_input_unsigned(4, ni)
666        batch.set_input_unsigned(5, nj)
667        batch.run_process()
668        (id, type) = batch.commit_output(0)
669        exp_albedo = dbvalue(id, type)
670        (id, type) = batch.commit_output(1)
671        exp_normal = dbvalue(id, type)
672        (id, type) = batch.commit_output(2)
673        mask_image = dbvalue(id, type)
674        return(exp_albedo, exp_normal, mask_image)
675
676    def transform(self, tx, ty, tz, rx, ry, rz, scale):
677        batch.init_process("boxm2TransformModelProcess")
678        batch.set_input_from_db(0, self.scene)
679        batch.set_input_float(1, tx)
680        batch.set_input_float(2, ty)
681        batch.set_input_float(3, tz)
682        batch.set_input_float(4, rx)
683        batch.set_input_float(5, ry)
684        batch.set_input_float(6, rz)
685        batch.set_input_float(7, scale)
686        batch.run_process()
687        return
688
689    def compute_sun_affine_camera(self, sun_az, sun_el, astro_coords=True):
690        (camera, ni, nj) = boxm2_adaptor.compute_sun_affine_camera(
691            self.scene, sun_az, sun_el, astro_coords)
692        return (camera, ni, nj)
693
694    def update_sun_visibilities(self, sun_camera, ni, nj, prefix_name=""):
695        boxm2_adaptor.update_sun_visibilities(self.scene, self.device,
696                                              self.opencl_cache, self.cpu_cache, sun_camera, ni, nj, prefix_name)
697
698    def render_shadow_map(self, camera, ni, nj, prefix_name=''):
699        shadow_map = boxm2_adaptor.render_shadow_map(
700            self.scene, self.device, self.opencl_cache, camera, ni, nj,
701            prefix_name)
702        return shadow_map
703
704    def render_scene_mask(self, camera, ni, nj, ground_plane_only=False):
705        mask = boxm2_adaptor.create_mask_image(self.scene, camera, ni, nj,
706                                               ground_plane_only)
707        return mask
708
709    def normals_to_id(self):
710        print("Normals to id ")
711        batch.init_process("boxm2CppNormalsToIdProcess")
712        batch.set_input_from_db(0, self.scene)
713        batch.set_input_from_db(1, self.cpu_cache)
714        return batch.run_process()
715
716    def cache_neighbor_info(self):
717        batch.init_process("boxm2VecfOclCacheNeighborInfoProcess")
718        batch.set_input_from_db(0, self.scene)
719        batch.set_input_from_db(1, self.opencl_cache)
720        return batch.run_process()
721
722    def refine_scene_around_geometry(
723          self, filter_v, n_times, p_thresh, use_gpu):
724        if self.opencl_cache.type == "boxm2_opencl_cache_sptr":
725            print("Refining around surface geometry")
726            batch.init_process(
727                "boxm2_ocl_refine_scene_around_geometry_process")
728            batch.set_input_from_db(0, self.scene)
729            batch.set_input_from_db(1, self.opencl_cache)
730            batch.set_input_from_db(2, self.device)
731            batch.set_input_from_db(3, filter_v)
732            batch.set_input_int(4, n_times)
733            # use negative value to refine all
734            batch.set_input_float(5, p_thresh)
735            batch.set_input_bool(6, use_gpu)
736            return batch.run_process()
737        else:
738            print "ERROR: Cache type not recognized: ", self.opencl_cache.type
739            return False
740
741    def compute_pre_post(self, cam, img, view_identifier="",
742                         tnear=100000.0, tfar=100000.0):
743        dev = self.device
744        cache = self.opencl_cache
745        return boxm2_adaptor.boxm2_compute_pre_post(
746            self.scene, dev, cache, cam, img, view_identifier, tnear, tfar)
747
748    def update_if(self, does_add=True, view_identifier=""):
749        dev = self.device
750        cache = self.opencl_cache
751        return boxm2_adaptor.update_image_factor(
752            self.scene, dev, cache, does_add, view_identifier)
753
754    def fuse_factors(self, view_idents, weights):
755        dev = self.device
756        cache = self.opencl_cache
757        return boxm2_adaptor.boxm2_fuse_factors(self.scene, dev, cache, view_idents, weights)
758
759    def compute_hmapf(self, zimg, zvar, ximg, yimg, sradius=16):
760        dev = self.device
761        cache = self.opencl_cache
762        return boxm2_adaptor.compute_hmap_factor(
763            self.scene, dev, cache, zimg, zvar, ximg, yimg, sradius)
764
765    def update_hf(self, does_add=True):
766        dev = self.device
767        cache = self.opencl_cache
768        return boxm2_adaptor.update_hmap_factor(self.scene, dev, cache, does_add)
769
770    def init_uniform_prob(self):
771        return boxm2_adaptor.boxm2_init_uniform_prob(
772            self.scene, self.device, self.opencl_cache)
773
774    def remove_low_nobs(self, nobs_thresh_multiplier=3.0):
775        dev = self.device
776        cache = self.opencl_cache
777        return boxm2_adaptor.boxm2_remove_low_nobs(
778            self.scene, dev, cache, nobs_thresh_multiplier)
779
780
781def compactify_mog6_view_scene(boxm2_dir, save_dir=None):
782    if save_dir is None:
783        save_dir = os.path.join(boxm2_dir, "sav")
784    original_scene_file = os.path.join(boxm2_dir, 'scene.xml')
785    compact_scene_file = os.path.join(boxm2_dir, 'compact_scene.xml')
786
787    # load scene
788    scene = boxm2_scene_adaptor(original_scene_file)
789    boxm2_adaptor.compactify_mog6_view(scene.scene, scene.cpu_cache)
790    scene.write_cache()
791
792    # create new compact scene file with updated appearance model
793    tree = ElementTree()
794    tree.parse(original_scene_file)
795    root = tree.getroot()
796    for apm in root.iter('appearance'):
797        if "mog6" in apm.get('apm'):
798            apm.set('apm', 'boxm2_mog6_view_compact')
799        else:
800            root.remove(apm)
801    tree.write(compact_scene_file)
802
803    # remove un-compactified data files
804    old_data_files_pattern = r"boxm2_(mog6_view_id|num_obs|vis)"
805    for f in os.listdir(boxm2_dir):
806        if re.search(old_data_files_pattern, f):
807            os.remove(os.path.join(boxm2_dir, f))
808
809    # copy files to save directory
810    if not os.path.isdir(save_dir):
811        os.mkdir(save_dir)
812    else:
813        for f in os.listdir(save_dir):
814            if re.search(r".*\.bin", f):
815                os.remove(os.path.join(save_dir, f))
816
817    id_pat = [r'^id_', r'^boxm2_mog6_view_compact_id', r'^alpha_id_']
818    for pat in id_pat:
819        save_pattern(boxm2_dir, pat, save_dir)
820    shutil.copy(os.path.join(boxm2_dir, 'compact_scene.xml'), save_dir)
821    rewriteScenePath(save_dir, 'compact_scene.xml')
822
823
824def save_pattern(search_dir, pattern, save_dir):
825    """Copies all files in `search_dir` that match the given `pattern`
826    into `save_dir`. If `save_dir` does not exist then nothing is
827    done.
828
829    :param search_dir: Directory from which to copy files
830    :param pattern: Regex string to match files in `search_dir`
831    :param save_dir: Absolute path in which to save copied files from
832    `search_dir`
833    """
834    if not os.path.exists(save_dir):
835        return
836
837    for f in os.listdir(search_dir):
838        if re.search(pattern, f):
839            shutil.copy(os.path.join(search_dir, f), save_dir)
840
841
842def rewriteScenePath(boxm2_dir, scene_file):
843    """Rewrites a given scene XML file with a new scene_paths element
844    that points to its containing directory.
845
846    :param boxm2_dir: The directory containing the given scene file.
847    :param scene_file: Relative path from `boxm2_dir` to the given
848    XML file to modify.
849
850    """
851    abs_name = os.path.join(boxm2_dir, scene_file)
852    if os.path.isfile(abs_name):
853        tree = ElementTree()
854        tree.parse(abs_name)
855        root = tree.getroot()
856        for path in root.iter('scene_paths'):
857            path.set('path', boxm2_dir + '/')
858        tree.write(abs_name)
859