Exemplo n.º 1
0
def compute_cutline(orthophoto_file, crop_area_file, destination, max_concurrency=1, tmpdir=None, scale=1):
    if io.file_exists(orthophoto_file) and io.file_exists(crop_area_file):
        from opendm.grass_engine import grass
        log.ODM_DEBUG("Computing cutline")

        if tmpdir and not io.dir_exists(tmpdir):
            system.mkdir_p(tmpdir)

        scale = max(0.0001, min(1, scale))
        scaled_orthophoto = None

        if scale < 1:
            log.ODM_DEBUG("Scaling orthophoto to %s%% to compute cutline" % (scale * 100))

            scaled_orthophoto = os.path.join(tmpdir, os.path.basename(io.related_file_path(orthophoto_file, postfix=".scaled")))
            # Scale orthophoto before computing cutline
            system.run("gdal_translate -outsize {}% 0 "
                "-co NUM_THREADS={} "
                "--config GDAL_CACHEMAX {}% "
                "{} {}".format(
                scale * 100,
                max_concurrency,
                concurrency.get_max_memory(),
                orthophoto_file,
                scaled_orthophoto
            ))
            orthophoto_file = scaled_orthophoto

        try:
            ortho_width,ortho_height = get_image_size.get_image_size(orthophoto_file, fallback_on_error=False)
            log.ODM_DEBUG("Orthophoto dimensions are %sx%s" % (ortho_width, ortho_height))
            number_lines = int(max(8, math.ceil(min(ortho_width, ortho_height) / 256.0)))
        except:
            log.ODM_DEBUG("Cannot compute orthophoto dimensions, setting arbitrary number of lines.")
            number_lines = 32
        
        log.ODM_DEBUG("Number of lines: %s" % number_lines)

        gctx = grass.create_context({'auto_cleanup' : False, 'tmpdir': tmpdir})
        gctx.add_param('orthophoto_file', orthophoto_file)
        gctx.add_param('crop_area_file', crop_area_file)
        gctx.add_param('number_lines', number_lines)
        gctx.add_param('max_concurrency', max_concurrency)
        gctx.add_param('memory', int(concurrency.get_max_memory_mb(300)))
        gctx.set_location(orthophoto_file)

        cutline_file = gctx.execute(os.path.join("opendm", "grass", "compute_cutline.grass"))
        if cutline_file != 'error':
            if io.file_exists(cutline_file):
                shutil.move(cutline_file, destination)
                log.ODM_INFO("Generated cutline file: %s --> %s" % (cutline_file, destination))
                gctx.cleanup()
                return destination
            else:
                log.ODM_WARNING("Unexpected script result: %s. No cutline file has been generated." % cutline_file)
        else:
            log.ODM_WARNING("Could not generate orthophoto cutline. An error occured when running GRASS. No orthophoto will be generated.")
    else:
        log.ODM_WARNING("We've been asked to compute cutline, but either %s or %s is missing. Skipping..." % (orthophoto_file, crop_area_file))
Exemplo n.º 2
0
            def monitor():
                class nonloc:
                    status_callback_calls = 0

                def status_callback(info):
                    # If a task switches from RUNNING to QUEUED, then we need to
                    # stop the process and re-add the task to the queue.
                    if info.status == TaskStatus.QUEUED:
                        log.ODM_WARNING(
                            "LRE: %s (%s) turned from RUNNING to QUEUED. Re-adding to back of the queue."
                            % (self, task.uuid))
                        raise NodeTaskLimitReachedException(
                            "Delayed task limit reached")
                    elif info.status == TaskStatus.RUNNING:
                        # Print a status message once in a while
                        nonloc.status_callback_calls += 1
                        if nonloc.status_callback_calls > 30:
                            log.ODM_DEBUG("LRE: %s (%s) is still running" %
                                          (self, task.uuid))
                            nonloc.status_callback_calls = 0

                try:

                    def print_progress(percentage):
                        if percentage % 10 == 0:
                            log.ODM_DEBUG("LRE: Download of %s at [%s%%]" %
                                          (self, int(percentage)))

                    task.wait_for_completion(status_callback=status_callback)
                    log.ODM_DEBUG("LRE: Downloading assets for %s" % self)
                    task.download_assets(self.project_path,
                                         progress_callback=print_progress)
                    log.ODM_DEBUG(
                        "LRE: Downloaded and extracted assets for %s" % self)
                    done()
                except exceptions.TaskFailedError as e:
                    # Try to get output
                    try:
                        output_lines = task.output()

                        # Save to file
                        error_log_path = self.path("error.log")
                        with open(error_log_path, 'w') as f:
                            f.write('\n'.join(output_lines) + '\n')

                        msg = "(%s) failed with task output: %s\nFull log saved at %s" % (
                            task.uuid, "\n".join(
                                output_lines[-10:]), error_log_path)
                        done(exceptions.TaskFailedError(msg))
                    except:
                        log.ODM_WARNING(
                            "LRE: Could not retrieve task output for %s (%s)" %
                            (self, task.uuid))
                        done(e)
                except Exception as e:
                    done(e)
Exemplo n.º 3
0
def compute_cutline(orthophoto_file,
                    crop_area_file,
                    destination,
                    max_concurrency=1,
                    tmpdir=None):
    if io.file_exists(orthophoto_file) and io.file_exists(crop_area_file):
        from opendm.grass_engine import grass
        log.ODM_DEBUG("Computing cutline")

        if tmpdir and not io.dir_exists(tmpdir):
            system.mkdir_p(tmpdir)

        try:
            ortho_width, ortho_height = get_image_size.get_image_size(
                orthophoto_file)
            log.ODM_DEBUG("Orthophoto dimensions are %sx%s" %
                          (ortho_width, ortho_height))
            number_lines = int(
                max(8, math.ceil(min(ortho_width, ortho_height) / 256.0)))
        except get_image_size.UnknownImageFormat:
            log.ODM_DEBUG(
                "Cannot compute orthophoto dimensions, setting arbitrary number of lines."
            )
            number_lines = 32

        log.ODM_DEBUG("Number of lines: %s" % number_lines)

        gctx = grass.create_context({'auto_cleanup': False, 'tmpdir': tmpdir})
        gctx.add_param('orthophoto_file', orthophoto_file)
        gctx.add_param('crop_area_file', crop_area_file)
        gctx.add_param('number_lines', number_lines)
        gctx.add_param('max_concurrency', max_concurrency)
        gctx.add_param('memory', int(concurrency.get_max_memory_mb(300)))
        gctx.set_location(orthophoto_file)

        cutline_file = gctx.execute(
            os.path.join("opendm", "grass", "compute_cutline.grass"))
        if cutline_file != 'error':
            if io.file_exists(cutline_file):
                shutil.move(cutline_file, destination)
                log.ODM_INFO("Generated cutline file: %s --> %s" %
                             (cutline_file, destination))
                gctx.cleanup()
                return destination
            else:
                log.ODM_WARNING(
                    "Unexpected script result: %s. No cutline file has been generated."
                    % cutline_file)
        else:
            log.ODM_WARNING(
                "Could not generate orthophoto cutline. An error occured when running GRASS. No orthophoto will be generated."
            )
    else:
        log.ODM_WARNING(
            "We've been asked to compute cutline, but either %s or %s is missing. Skipping..."
            % (orthophoto_file, crop_area_file))
Exemplo n.º 4
0
    def save_absolute_image_list_to(self, file):
        """
        Writes a copy of the image_list.txt file and makes sure that all paths
        written in it are absolute paths and not relative paths.
        """
        image_list_file = self.path("image_list.txt")

        if io.file_exists(image_list_file):
            with open(image_list_file, 'r') as f:
                content = f.read()

            lines = []
            for line in map(str.strip, content.split('\n')):
                if line and not line.startswith("/"):
                    line = os.path.abspath(
                        os.path.join(self.opensfm_project_path, line))
                lines.append(line)

            with open(file, 'w') as f:
                f.write("\n".join(lines))

            log.ODM_DEBUG("Wrote %s with absolute paths" % file)
        else:
            log.ODM_WARNING("No %s found, cannot create %s" %
                            (image_list_file, file))
Exemplo n.º 5
0
        def remote_worker():
            while True:
                # Block until a new queue item is available
                task = q.get()

                if task is None or nonloc.error is not None:
                    q.task_done()
                    break

                # Yield to local processing
                if not nonloc.local_processing:
                    log.ODM_DEBUG(
                        "LRE: Yielding to local processing, sending %s back to the queue"
                        % task)
                    q.put(task)
                    q.task_done()
                    time.sleep(0.05)
                    continue

                # If we've found an estimate of the limit on the maximum number of tasks
                # a node can process, we block until some tasks have completed
                if nonloc.max_remote_tasks is not None and remote_running_tasks.value >= nonloc.max_remote_tasks:
                    q.put(task)
                    q.task_done()
                    time.sleep(2)
                    continue

                # Process remote
                try:
                    remote_running_tasks.increment()
                    task.process(False, handle_result)
                except Exception as e:
                    handle_result(task, False, e)
Exemplo n.º 6
0
def no_resize(src_dir, target_dir, rerun_cell, photo):
    # define image paths
    path_file = photo.path_file
    new_path_file = io.join_paths(target_dir, photo.filename)
    # set raw image path in case we want to rerun cell
    if io.file_exists(new_path_file) and rerun_cell:
        path_file = io.join_paths(src_dir, photo.filename)

    if not io.file_exists(new_path_file) or rerun_cell:
        img = cv2.imread(path_file)
        io.copy(path_file, new_path_file)
        photo.path_file = new_path_file
        photo.width = img.shape[0]
        photo.height = img.shape[1]
        photo.update_focal()

        # log message
        log.ODM_DEBUG('Copied %s | dimensions: %s' %
                      (photo.filename, img.shape))
    else:
        # log message
        log.ODM_WARNING('Already copied %s | dimensions: %s x %s' %
                        (photo.filename, photo.width, photo.height))

    return photo
Exemplo n.º 7
0
def window_filter_2d(arr, nodata, window, kernel_size, filter):
    """
    Apply a filter to dem within a window, expects to work with kernal based filters

    :param geotiff_path: path to the geotiff to filter
    :param window: the window to apply the filter, should be a list contains row start, col_start, row_end, col_end
    :param kernel_size: the size of the kernel for the filter, works with odd numbers, need to test if it works with even numbers
    :param filter: the filter function which takes a 2d array as input and filter results as output.
    """
    shape = arr.shape[:2]
    if window[0] < 0 or window[1] < 0 or window[2] > shape[0] or window[
            3] > shape[1]:
        raise Exception('Window is out of bounds')
    expanded_window = [
        max(0, window[0] - kernel_size // 2),
        max(0, window[1] - kernel_size // 2),
        min(shape[0], window[2] + kernel_size // 2),
        min(shape[1], window[3] + kernel_size // 2)
    ]
    win_arr = arr[expanded_window[0]:expanded_window[2],
                  expanded_window[1]:expanded_window[3]]
    # Should have a better way to handle nodata, similar to the way the filter algorithms handle the border (reflection, nearest, interpolation, etc).
    # For now will follow the old approach to guarantee identical outputs
    nodata_locs = win_arr == nodata
    win_arr = filter(win_arr)
    win_arr[nodata_locs] = nodata
    win_arr = win_arr[window[0] - expanded_window[0]:window[2] -
                      expanded_window[0], window[1] -
                      expanded_window[1]:window[3] - expanded_window[1]]
    log.ODM_DEBUG("Filtered window: %s" % str(window))
    return win_arr
Exemplo n.º 8
0
 def cleanup_remote():
     if not partial and task.remote_task:
         log.ODM_DEBUG(
             "LRE: Cleaning up remote task (%s)... %s" %
             (task.remote_task.uuid,
              'OK' if remove_task_safe(task.remote_task) else 'NO'))
         self.params['tasks'].remove(task.remote_task)
         task.remote_task = None
Exemplo n.º 9
0
        def cleanup_remote_tasks():
            if self.params['tasks']:
                log.ODM_WARNING("LRE: Attempting to cleanup remote tasks")
            else:
                log.ODM_INFO("LRE: No remote tasks to cleanup")

            for task in self.params['tasks']:
                log.ODM_DEBUG("LRE: Removing remote task %s... %s" % (task.uuid, 'OK' if remove_task_safe(task) else 'NO'))
Exemplo n.º 10
0
def run(cmd):
    """Run a system command"""
    log.ODM_DEBUG('running %s' % cmd)
    retcode = subprocess.call(cmd, shell=True)

    if retcode < 0:
        raise Exception("Child was terminated by signal {}".format(-retcode))
    elif retcode > 0:
        raise Exception("Child returned {}".format(retcode))
Exemplo n.º 11
0
def build_overviews(orthophoto_file):
    log.ODM_DEBUG("Building Overviews")
    kwargs = {'orthophoto': orthophoto_file}
    
    # Run gdaladdo
    system.run('gdaladdo -ro -r average '
                '--config BIGTIFF_OVERVIEW IF_SAFER '
                '--config COMPRESS_OVERVIEW JPEG '
                '{orthophoto} 2 4 8 16'.format(**kwargs))
Exemplo n.º 12
0
def run(cmd):
    """Run a system command"""
    log.ODM_DEBUG('running %s' % cmd)
    returnCode = os.system(cmd)

    if (returnCode != 0):
        log.ODM_ERROR("quitting cause: \n\t" + cmd + "\nreturned with code " +
                 str(returnCode) + ".\n")
        sys.exit('An error occurred. Check stdout above or the logs.')
Exemplo n.º 13
0
    def process(self, inputs, outputs):

        # Benchmarking
        start_time = system.now_raw()

        log.ODM_INFO('Running ODM Meshing Cell')

        # get inputs
        args = self.inputs.args
        tree = self.inputs.tree
        verbose = '-verbose' if self.params.verbose else ''

        # define paths and create working directories
        system.mkdir_p(tree.odm_meshing)

        # check if we rerun cell or not
        rerun_cell = (args.rerun is not None and
                      args.rerun == 'odm_meshing') or \
                     (args.rerun_all) or \
                     (args.rerun_from is not None and
                      'odm_meshing' in args.rerun_from)

        if not io.file_exists(tree.odm_mesh) or rerun_cell:
            log.ODM_DEBUG('Writing ODM Mesh file in: %s' % tree.odm_mesh)

            kwargs = {
                'bin': context.odm_modules_path,
                'outfile': tree.odm_mesh,
                'log': tree.odm_meshing_log,
                'max_vertex': self.params.max_vertex,
                'oct_tree': self.params.oct_tree,
                'samples': self.params.samples,
                'solver': self.params.solver,
                'verbose': verbose
            }
            if not args.use_pmvs:
                kwargs['infile'] = tree.opensfm_model
            else:
                kwargs['infile'] = tree.pmvs_model

            # run meshing binary
            system.run(
                '{bin}/odm_meshing -inputFile {infile} '
                '-outputFile {outfile} -logFile {log} '
                '-maxVertexCount {max_vertex} -octreeDepth {oct_tree} {verbose} '
                '-samplesPerNode {samples} -solverDivide {solver}'.format(
                    **kwargs))
        else:
            log.ODM_WARNING('Found a valid ODM Mesh file in: %s' %
                            tree.odm_mesh)

        if args.time:
            system.benchmark(start_time, tree.benchmarking, 'Meshing')

        log.ODM_INFO('Running ODM Meshing Cell - Finished')
        return ecto.OK if args.end_with != 'odm_meshing' else ecto.QUIT
Exemplo n.º 14
0
 def update_config(self, cfg_dict):
     cfg_file = self.get_config_file_path()
     log.ODM_DEBUG("Updating %s" % cfg_file)
     if os.path.exists(cfg_file):
         try:
             with open(cfg_file) as fin:
                 cfg = yaml.safe_load(fin)
             for k, v in cfg_dict.items():
                 cfg[k] = v
                 log.ODM_DEBUG("%s: %s" % (k, v))
             with open(cfg_file, 'w') as fout:
                 fout.write(yaml.dump(cfg, default_flow_style=False))
         except Exception as e:
             log.ODM_WARNING("Cannot update configuration file %s: %s" %
                             (cfg_file, str(e)))
     else:
         log.ODM_WARNING(
             "Tried to update configuration, but %s does not exist." %
             cfg_file)
Exemplo n.º 15
0
 def get_images(in_dir):
     log.ODM_DEBUG(in_dir)
     entries = os.listdir(in_dir)
     valid, rejects = [], []
     for f in entries:
         if valid_image_filename(f):
             valid.append(f)
         else:
             rejects.append(f)
     return valid, rejects
Exemplo n.º 16
0
    def process(self, inputs, outputs):

        # Benchmarking
        start_time = system.now_raw()

        log.ODM_INFO('Running ODM Texturing Cell')

        # get inputs
        args = self.inputs.args
        tree = self.inputs.tree

        # define paths and create working directories
        system.mkdir_p(tree.odm_texturing)

        # check if we rerun cell or not
        rerun_cell = (args.rerun is not None and
                      args.rerun == 'odm_texturing') or \
                     (args.rerun_all) or \
                     (args.rerun_from is not None and
                      'odm_texturing' in args.rerun_from)

        if not io.file_exists(tree.odm_textured_model_obj) or rerun_cell:
            log.ODM_DEBUG('Writing ODM Textured file in: %s' %
                          tree.odm_textured_model_obj)

            # odm_texturing definitions
            kwargs = {
                'bin': context.odm_modules_path,
                'out_dir': tree.odm_texturing,
                'bundle': tree.opensfm_bundle,
                'imgs_path': tree.dataset_resize,
                'imgs_list': tree.opensfm_bundle_list,
                'model': tree.odm_mesh,
                'log': tree.odm_texuring_log,
                'resize': self.params.resize,
                'resolution': self.params.resolution,
                'size': self.params.size
            }

            # run texturing binary
            system.run(
                '{bin}/odm_texturing -bundleFile {bundle} '
                '-imagesPath {imgs_path} -imagesListPath {imgs_list} '
                '-inputModelPath {model} -outputFolder {out_dir}/ '
                '-textureResolution {resolution} -bundleResizedTo {resize} '
                '-textureWithSize {size} -logFile {log}'.format(**kwargs))
        else:
            log.ODM_WARNING('Found a valid ODM Texture file in: %s' %
                            tree.odm_textured_model_obj)

        if args.time:
            system.benchmark(start_time, tree.benchmarking, 'Texturing')

        log.ODM_INFO('Running ODM Texturing Cell - Finished')
        return ecto.OK if args.end_with != 'odm_texturing' else ecto.QUIT
Exemplo n.º 17
0
    def __init__(self, path_file):
        self.filename = os.path.basename(path_file)
        self.mask = None

        # Standard tags (virtually all photos have these)
        self.width = None
        self.height = None
        self.camera_make = ''
        self.camera_model = ''

        # Geo tags
        self.latitude = None
        self.longitude = None
        self.altitude = None

        # Multi-band fields
        self.band_name = 'RGB'
        self.band_index = 0
        self.capture_uuid = None  # DJI only

        # Multi-spectral fields
        self.fnumber = None
        self.radiometric_calibration = None
        self.black_level = None

        # Capture info
        self.exposure_time = None
        self.iso_speed = None
        self.bits_per_sample = None
        self.vignetting_center = None
        self.vignetting_polynomial = None
        self.spectral_irradiance = None
        self.horizontal_irradiance = None
        self.irradiance_scale_to_si = None
        self.utc_time = None

        # DLS
        self.sun_sensor = None
        self.dls_yaw = None
        self.dls_pitch = None
        self.dls_roll = None

        # self.center_wavelength = None
        # self.bandwidth = None

        # RTK
        self.gps_xy_stddev = None  # Dilution of Precision X/Y
        self.gps_z_stddev = None  # Dilution of Precision Z

        # parse values from metadata
        self.parse_exif_values(path_file)

        # print log message
        log.ODM_DEBUG('Loaded {}'.format(self))
Exemplo n.º 18
0
 def status_callback(info):
     # If a task switches from RUNNING to QUEUED, then we need to 
     # stop the process and re-add the task to the queue.
     if info.status == TaskStatus.QUEUED:
         log.ODM_WARNING("LRE: %s (%s) turned from RUNNING to QUEUED. Re-adding to back of the queue." % (self, task.uuid))
         raise NodeTaskLimitReachedException("Delayed task limit reached")
     elif info.status == TaskStatus.RUNNING:
         # Print a status message once in a while
         nonloc.status_callback_calls += 1
         if nonloc.status_callback_calls > 30:
             log.ODM_DEBUG("LRE: %s (%s) is still running" % (self, task.uuid))
             nonloc.status_callback_calls = 0
Exemplo n.º 19
0
    def process(self, inputs, outputs):

        # Benchmarking
        start_time = system.now_raw()

        log.ODM_INFO('Running ODM Resize Cell')

        # get inputs
        args = self.inputs.args
        tree = self.inputs.tree
        photos = self.inputs.photos

        if not photos:
            log.ODM_ERROR('Not enough photos in photos to resize')
            return ecto.QUIT

        if self.params.resize_to <= 0:
            log.ODM_ERROR('Resize parameter must be greater than 0')
            return ecto.QUIT

        # create working directory
        system.mkdir_p(tree.dataset_resize)

        log.ODM_DEBUG('Resizing dataset to: %s' % tree.dataset_resize)

        # check if we rerun cell or not
        rerun_cell = (args.rerun is not None and
                      args.rerun == 'resize') or \
                     (args.rerun_all) or \
                     (args.rerun_from is not None and
                      'resize' in args.rerun_from)

        # loop over photos
        if self.params.skip_resize:
            photos = Pool().map(
                partial(no_resize, tree.dataset_raw, tree.dataset_resize,
                        rerun_cell), photos)
            log.ODM_INFO('Copied %s images' % len(photos))
        else:
            photos = Pool().map(
                partial(resize, tree.dataset_raw, tree.dataset_resize,
                        self.params.resize_to, rerun_cell), photos)
            log.ODM_INFO('Resized %s images' % len(photos))

        # append photos to cell output
        self.outputs.photos = photos

        if args.time:
            system.benchmark(start_time, tree.benchmarking, 'Resizing')

        log.ODM_INFO('Running ODM Resize Cell - Finished')
        return ecto.OK if args.end_with != 'resize' else ecto.QUIT
Exemplo n.º 20
0
    def process(self, inputs, outputs):

        # Benchmarking
        start_time = system.now_raw()

        log.ODM_INFO('Running OMD PMVS Cell')

        # get inputs
        args = self.inputs.args
        tree = self.inputs.tree

        # check if we rerun cell or not
        rerun_cell = (args.rerun is not None and
                      args.rerun == 'pmvs') or \
                     (args.rerun_all) or \
                     (args.rerun_from is not None and
                      'pmvs' in args.rerun_from)

        if not io.file_exists(tree.pmvs_model) or rerun_cell:
            log.ODM_DEBUG('Creating dense pointcloud in: %s' % tree.pmvs_model)

            kwargs = {
                'bin': context.cmvs_opts_path,
                'prefix': tree.pmvs_rec_path,
                'level': self.params.level,
                'csize': self.params.csize,
                'thresh': self.params.thresh,
                'wsize': self.params.wsize,
                'min_imgs': self.params.min_imgs,
                'cores': self.params.cores
            }

            # generate pmvs2 options
            system.run('{bin} {prefix}/ {level} {csize} {thresh} {wsize} '
                       '{min_imgs} {cores}'.format(**kwargs))

            # run pmvs2
            system.run('%s %s/ option-0000' %
                       (context.pmvs2_path, tree.pmvs_rec_path))

        else:
            log.ODM_WARNING('Found a valid PMVS file in %s' % tree.pmvs_model)

        outputs.reconstruction = inputs.reconstruction
        
        if args.time:
            system.benchmark(start_time, tree.benchmarking, 'PMVS')

        log.ODM_INFO('Running ODM PMVS Cell - Finished')
        return ecto.OK if args.end_with != 'pmvs' else ecto.QUIT
Exemplo n.º 21
0
def merge_point_clouds(input_files, output_file, verbose=False):
    if len(input_files) == 0:
        log.ODM_WARNING("Cannot merge point clouds, no point clouds to merge.")
        return

    cmd = [
        'pdal',
        'merge',
        ' '.join(map(quote, input_files + [output_file])),
    ]

    if verbose:
        log.ODM_DEBUG(' '.join(cmd))

    system.run(' '.join(cmd))
Exemplo n.º 22
0
def run(cmd, env_paths=[]):
    """Run a system command"""
    log.ODM_DEBUG('running %s' % cmd)

    env = None
    if len(env_paths) > 0:
        env = os.environ.copy()
        env["PATH"] = env["PATH"] + ":" + ":".join(env_paths)

    retcode = subprocess.call(cmd, shell=True, env=env)

    if retcode < 0:
        raise Exception("Child was terminated by signal {}".format(-retcode))
    elif retcode > 0:
        raise Exception("Child returned {}".format(retcode))
Exemplo n.º 23
0
    def process(self, inputs, outputs):
        # check if the extension is sopported
        def supported_extension(file_name):
            (pathfn, ext) = os.path.splitext(file_name)
            return ext.lower() in context.supported_extensions

        log.ODM_INFO('Running ODM Load Dataset Cell')

        # get inputs
        tree = self.inputs.tree

        # set images directory
        images_dir = tree.dataset_resize

        if not io.dir_exists(images_dir):
            images_dir = tree.dataset_raw
            if not io.dir_exists(images_dir):
                log.ODM_ERROR(
                    "You must put your pictures into an <images> directory")
                return ecto.QUIT

        log.ODM_DEBUG('Loading dataset from: %s' % images_dir)

        # find files in the given directory
        files = io.get_files_list(images_dir)

        # filter images for its extension type
        files = [f for f in files if supported_extension(f)]

        if files:
            # create ODMPhoto list
            photos = []
            for f in files:
                path_file = io.join_paths(images_dir, f)
                photo = types.ODM_Photo(path_file, self.params.force_focal,
                                        self.params.force_ccd)
                photos.append(photo)

            log.ODM_INFO('Found %s usable images' % len(photos))
        else:
            log.ODM_ERROR('Not enough supported images in %s' % images_dir)
            return ecto.QUIT

        # append photos to cell output
        outputs.photos = photos

        log.ODM_INFO('Running ODM Load Dataset Cell - Finished')
        return ecto.OK
Exemplo n.º 24
0
def resize(src_dir, target_dir, resize_to, rerun_cell, photo):
    # define image paths
    path_file = photo.path_file
    new_path_file = io.join_paths(target_dir, photo.filename)
    # set raw image path in case we want to rerun cell
    if io.file_exists(new_path_file) and rerun_cell:
        path_file = io.join_paths(src_dir, photo.filename)

    if not io.file_exists(new_path_file) or rerun_cell:
        # open and resize image with opencv
        img = cv2.imread(path_file)
        # compute new size
        max_side = max(img.shape[0], img.shape[1])
        if max_side <= resize_to:
            log.ODM_WARNING(
                'Resize parameter is greater than or equal to the largest side of the image'
            )
        ratio = float(resize_to) / float(max_side)
        img_r = cv2.resize(img, None, fx=ratio, fy=ratio)
        # write image with opencv
        cv2.imwrite(new_path_file, img_r)
        # read metadata with pyexiv2
        old_meta = pyexiv2.ImageMetadata(path_file)
        new_meta = pyexiv2.ImageMetadata(new_path_file)
        old_meta.read()
        new_meta.read()
        # copy metadata
        old_meta.copy(new_meta)
        # update metadata size
        new_meta['Exif.Photo.PixelXDimension'] = img_r.shape[0]
        new_meta['Exif.Photo.PixelYDimension'] = img_r.shape[1]
        new_meta.write()
        # update photos array with new values
        photo.path_file = new_path_file
        photo.width = img_r.shape[0]
        photo.height = img_r.shape[1]
        photo.update_focal()

        # log message
        log.ODM_DEBUG('Resized %s | dimensions: %s' %
                      (photo.filename, img_r.shape))
    else:
        # log message
        log.ODM_WARNING('Already resized %s | dimensions: %s x %s' %
                        (photo.filename, photo.width, photo.height))

    return photo
Exemplo n.º 25
0
def extract_temperatures_dji(photo, image, dataset_tree):
    """Extracts the DJI-encoded thermal image as 2D floating-point numpy array with temperatures in degC.
        The raw sensor values are obtained using the sample binaries provided in the official Thermal SDK by DJI.
        The executable file is run and generates a 16 bit unsigned RAW image with Little Endian byte order.
        Link to DJI Forum post: https://forum.dji.com/forum.php?mod=redirect&goto=findpost&ptid=230321&pid=2389016
        """
    # Hardcoded metadata for mean of values
    # This is added to support the possibility of extracting RJPEG from DJI M2EA
    meta = {
        "Emissivity": 0.95,
        "ObjectDistance":
        50,  #This is mean value of flights for better results. Need to be changed later, or improved by bypassing options from task broker
        "AtmosphericTemperature": 20,
        "ReflectedApparentTemperature": 30,
        "IRWindowTemperature": 20,
        "IRWindowTransmission": 1,
        "RelativeHumidity": 40,
        "PlanckR1": 21106.77,
        "PlanckB": 1501,
        "PlanckF": 1,
        "PlanckO": -7340,
        "PlanckR2": 0.012545258,
    }

    if photo.camera_model == "MAVIC2-ENTERPRISE-ADVANCED":
        # Adding support for MAVIC2-ENTERPRISE-ADVANCED Camera images
        im = Image.open(f"{dataset_tree}/{photo.filename}")
        # concatenate APP3 chunks of data
        a = im.applist[3][1]
        for i in range(4, 14):
            a += im.applist[i][1]
        # create image from bytes
        try:
            img = Image.frombytes("I;16L", (640, 512), a)
        except ValueError as e:
            log.ODM_ERROR(
                "Error during extracting temperature values for file %s : %s" %
                photo.filename, e)
    else:
        log.ODM_DEBUG(
            "Only DJI M2EA currently supported, please wait for new updates")
        return image
    # Extract raw sensor values from generated image into numpy array
    raw_sensor_np = np.array(img)
    ## extracting the temperatures from thermal images
    thermal_np = sensor_vals_to_temp(raw_sensor_np, **meta)
    return thermal_np
Exemplo n.º 26
0
def run(cmd, env_paths=[context.superbuild_bin_path], env_vars={}):
    """Run a system command"""
    log.ODM_DEBUG('running %s' % cmd)

    env = os.environ.copy()
    if len(env_paths) > 0:
        env["PATH"] = env["PATH"] + ":" + ":".join(env_paths)

    for k in env_vars:
        env[k] = str(env_vars[k])

    retcode = subprocess.call(cmd, shell=True, env=env)

    if retcode < 0:
        raise Exception("Child was terminated by signal {}".format(-retcode))
    elif retcode > 0:
        raise Exception("Child returned {}".format(retcode))
Exemplo n.º 27
0
    def process(self, inputs, outputs):

        # Benchmarking
        start_time = system.now_raw()

        log.ODM_INFO('Running ODM CMVS Cell')

        # get inputs
        args = self.inputs.args
        tree = self.inputs.tree

        # check if we rerun cell or not
        rerun_cell = (args.rerun is not None and
                      args.rerun == 'cmvs') or \
                     (args.rerun_all) or \
                     (args.rerun_from is not None and
                      'cmvs' in args.rerun_from)

        if not io.file_exists(tree.pmvs_bundle) or rerun_cell:
            log.ODM_DEBUG('Writing CMVS vis in: %s' % tree.pmvs_bundle)

            # copy bundle file to pmvs dir
            from shutil import copyfile
            copyfile(tree.opensfm_bundle, tree.pmvs_bundle)

            kwargs = {
                'bin': context.cmvs_path,
                'prefix': self.inputs.tree.pmvs_rec_path,
                'max_images': self.params.max_images,
                'cores': self.params.cores
            }

            # run cmvs
            system.run('{bin} {prefix}/ {max_images} {cores}'.format(**kwargs))
        else:
            log.ODM_WARNING('Found a valid CMVS file in: %s' %
                            tree.pmvs_bundle)

        outputs.reconstruction = inputs.reconstruction

        if args.time:
            system.benchmark(start_time, tree.benchmarking, 'CMVS')

        log.ODM_INFO('Running ODM CMVS Cell - Finished')
        return ecto.OK if args.end_with != 'cmvs' else ecto.QUIT
Exemplo n.º 28
0
    def process(self, local, done):
        def handle_result(error = None, partial=False):
            done(self, local, error, partial)

        log.ODM_INFO("LRE: About to process %s %s" % (self, 'locally' if local else 'remotely'))
        
        if local:
            self._process_local(handle_result) # Block until complete
        else:
            now = datetime.datetime.now()
            if self.wait_until > now:
                wait_for = (self.wait_until - now).seconds + 1
                log.ODM_DEBUG("LRE: Waiting %s seconds before processing %s" % (wait_for, self))
                time.sleep(wait_for)

            # TODO: we could consider uploading multiple tasks
            # in parallel. But since we are using the same node
            # perhaps this wouldn't be a big speedup.
            self._process_remote(handle_result) # Block until upload is complete
Exemplo n.º 29
0
def parse_srs_header(header):
    """
    Parse a header coming from GCP or coordinate file
    :param header (str) line
    :return Proj object
    """
    log.ODM_DEBUG('Parsing SRS header: %s' % header)
    header = header.strip()
    ref = header.split(' ')
    try:
        if ref[0] == 'WGS84' and ref[1] == 'UTM':
            datum = ref[0]
            utm_pole = (ref[2][len(ref[2]) - 1]).upper()
            utm_zone = int(ref[2][:len(ref[2]) - 1])

            proj_args = {'zone': utm_zone, 'datum': datum}

            proj4 = '+proj=utm +zone={zone} +datum={datum} +units=m +no_defs=True'
            if utm_pole == 'S':
                proj4 += ' +south=True'

            srs = CRS.from_proj4(proj4.format(**proj_args))
        elif '+proj' in header:
            srs = CRS.from_proj4(header.strip('\''))
        elif header.lower().startswith("epsg:"):
            srs = CRS.from_epsg(header.lower()[5:])
        else:
            log.ODM_ERROR('Could not parse coordinates. Bad SRS supplied: %s' %
                          header)
    except RuntimeError as e:
        log.ODM_ERROR(
            'Uh oh! There seems to be a problem with your coordinates/GCP file.\n\n'
            'The line: %s\n\n'
            'Is not valid. Projections that are valid include:\n'
            ' - EPSG:*****\n'
            ' - WGS84 UTM **(N|S)\n'
            ' - Any valid proj4 string (for example, +proj=utm +zone=32 +north +ellps=WGS84 +datum=WGS84 +units=m +no_defs)\n\n'
            'Modify your input and try again.' % header)
        raise RuntimeError(e)

    return srs
Exemplo n.º 30
0
        def remote_worker():
            while True:
                had_semaphore = bool(nonloc.semaphore)

                # If we've found an estimate of the limit on the maximum number of tasks
                # a node can process, we block until some tasks have completed
                if nonloc.semaphore: nonloc.semaphore.acquire()

                # Block until a new queue item is available
                task = q.get()

                if task is None or nonloc.error is not None:
                    q.task_done()
                    if nonloc.semaphore: nonloc.semaphore.release()
                    break
                
                # Special case in which we've just created a semaphore
                if not had_semaphore and nonloc.semaphore:
                    log.ODM_INFO("LRE: Just found semaphore, sending %s back to the queue" % task)
                    q.put(task)
                    q.task_done()
                    continue

                # Yield to local processing
                if not nonloc.local_processing:
                    log.ODM_DEBUG("LRE: Yielding to local processing, sending %s back to the queue" % task)
                    q.put(task)
                    q.task_done()
                    if nonloc.semaphore: nonloc.semaphore.release()
                    time.sleep(0.05)
                    continue

                # Process remote
                try:
                    task.process(False, handle_result)
                except Exception as e:
                    handle_result(task, False, e)