def test_apply_im2im_filter(self): serie = SerieOfArraysFromFiles(path_src, "2:") result = apply_im2im_filter(serie) assert len(result) == 3 result = apply_im2im_filter(serie, Im2ImExample, args_init=(1, 2)) assert len(result) == 3
def __init__(self, params): self.cpt = 0 self.params = params self.works_surface_tracking = [] self.nameFrame = None self.path = params.images.path self.path_ref = params.images.path_ref self.verify_process = False self.ref_film = None self.filmName = None self.save_png = True # self.treshold = 0.16 self.xmin = self.params.surface_tracking.xmin self.xmax = self.params.surface_tracking.xmax self.ymin = self.params.surface_tracking.ymin self.ymax = self.params.surface_tracking.ymax self.distance_lens = self.params.surface_tracking.distance_lens self.distance_object = self.params.surface_tracking.distance_object self.pix_size = self.params.surface_tracking.pix_size self.startref_frame = self.params.surface_tracking.startref_frame self.lastref_frame = self.params.surface_tracking.lastref_frame self.sur = self.params.surface_tracking.sur self.k_x = self.params.surface_tracking.k_x self.k_y = self.params.surface_tracking.k_y self.slicer = self.params.surface_tracking.slicer self.red_factor = self.params.surface_tracking.red_factor self.n_frames_stock = self.params.surface_tracking.n_frames_stock self.plot_reduction_factor = 10 self.l_x = self.xmax - self.xmin self.l_y = self.ymax - self.ymin self.wave_proj = 1 / (self.k_x / self.l_x / self.pix_size) # wave_proj_pix = self.wave_proj / self.pix_size self.kslicer = 2 * self.k_x self.kx = np.arange(-self.l_x / 2, self.l_x / 2) / self.l_x self.ky = np.arange(-self.l_y / 2, self.l_y / 2) / self.l_y refserie = SerieOfArraysFromFiles(params.images.path_ref, params.images.str_slice_ref) k_x = self.compute_kx(refserie) logger.warning("Value of kx computed = " + str(k_x)) self.kxx = self.kx / self.pix_size self.gain, self.filt = self.set_gain_filter(k_x, self.l_y, self.l_x, self.slicer) self.a1_tmp = None
def __init__(self, params, logging_level="info", nb_max_workers=None): self.params = params if params.im2im is None: raise ValueError("params.im2im has to be set.") self.serie = SerieOfArraysFromFiles(params.images.path, params.images.str_slice) path_dir = self.serie.path_dir path_dir_result, self.how_saving = prepare_path_dir_result( path_dir, params.saving.path, params.saving.postfix, params.saving.how) self.path_dir_result = path_dir_result self.path_dir_src = Path(path_dir) super().__init__( path_dir_result=path_dir_result, logging_level=logging_level, nb_max_workers=nb_max_workers, ) self.queue_paths = self.add_queue("paths") self.queue_arrays = self.add_queue("arrays") self.queue_results = self.add_queue("results") self.add_work( "fill_path", self.fill_queue_paths, output_queue=self.queue_paths, kind="one shot", ) self.add_work( "read_array", self.imread, input_queue=self.queue_paths, output_queue=self.queue_arrays, kind="io", ) im2im_func = self.init_im2im(params) self.add_work( "im2im", im2im_func, input_queue=self.queue_arrays, output_queue=self.queue_results, ) self.add_work("save", self.save_image, input_queue=self.queue_results, kind="io")
def _make_processes(self): nb_process = multiprocessing.cpu_count() # splitting series serie_arrays = SerieOfArraysFromFiles(path=self.images_path) if (self.params.series.ind_stop - self.params.series.ind_start ) / self.params.series.ind_step < nb_process: nb_process = (self.params.series.ind_stop - self.params.series.ind_start) + 1 self._make_partition(serie_arrays, nb_process) # making and starting processes for i in range(nb_process): async_piv = self.async_process_class(self.params, self.work, self.series[i]) self.processes.append( multiprocessing.Process(target=async_piv.main))
class TopologySurfaceTracking(TopologyBase): """Topology for SurfaceTracking. Parameters ---------- params : None A ParamContainer containing the parameters for the computation. logging_level : str, {'warning', 'info', 'debug', ...} Logging level. nb_max_workers : None, int Maximum numbers of "workers". If None, a number is computed from the number of cores detected. If there are memory errors, you can try to decrease the number of workers. """ @classmethod def create_default_params(cls): """Class method returning the default parameters. For developers: cf. fluidsim.base.params """ params = ParamContainer(tag="params") WorkSurfaceTracking._complete_params_with_default(params) params._set_child( "images", attribs={ "path": "", "path_ref": "", "str_slice_ref": None, "str_slice": None, }, ) params.images._set_doc(""" Parameters indicating the input image set. path : str, {''} String indicating the input images (can be a full path towards an image file or a string given to `glob`). path_ref : str, {''} String indicating the reference input images (can be a full path towards an image file or a string given to `glob`). str_slice_ref : None String indicating as a Python slicing how to select reference images from the serie of reference images on the disk (in order to compute k_x value necessary for gain and filter). If None, no selection so all images are going to be processed. str_slice : None String indicating as a Python slicing how to select images from the serie of images on the disk. If None, no selection so all images are going to be processed. """) params._set_child("saving", attribs={ "path": None, "how": "ask", "postfix": "pre" }) params.saving._set_doc("""Saving of the results. path : None or str Path of the directory where the data will be saved. If None, the path is obtained from the input path and the parameter `postfix`. how : str {'ask'} 'ask', 'new_dir', 'complete' or 'recompute'. postfix : str Postfix from which the output file is computed. """) params._set_internal_attr( "_value_text", json.dumps({ "program": "fluidimage", "module": "fluidimage.topologies.surface_tracking", "class": "TopologySurfaceTracking", }), ) return params def __init__(self, params, logging_level="info", nb_max_workers=None): self.params = params if params.surface_tracking is None: raise ValueError("params.surface_tracking has to be set.") self.serie = SerieOfArraysFromFiles(params.images.path, params.images.str_slice) self.series = SeriesOfArrays( params.images.path, "i:i+" + str(self.serie.get_index_slices()[0][2] + 1) + ":" + str(self.serie.get_index_slices()[0][2]), ind_start=self.serie.get_index_slices()[0][0], ind_stop=self.serie.get_index_slices()[0][1] - 1, ind_step=self.serie.get_index_slices()[0][2], ) path_dir = self.serie.path_dir path_dir_result, self.how_saving = prepare_path_dir_result( path_dir, params.saving.path, params.saving.postfix, params.saving.how) self.path_dir_result = path_dir_result self.path_dir_src = Path(path_dir) self.surface_tracking_work = WorkSurfaceTracking(params) super().__init__( path_dir_result=path_dir_result, logging_level=logging_level, nb_max_workers=nb_max_workers, ) queue_paths = self.add_queue("paths") queue_couples_of_names = self.add_queue("couples of names") queue_arrays = self.add_queue("arrays") queue_angles = self.add_queue("angles") queue_couples_of_arrays = self.add_queue( "couples of corrected angles and angles") queuemod0_angles = self.add_queue("corrected angles copy") queuemod_angles = self.add_queue("corrected angles") queue_heights = self.add_queue("heights") self.add_work( "fill_path", self.fill_queue_paths, output_queue=(queue_paths, queue_couples_of_names), kind="one shot", ) self.add_work( "read_array", self.imread, input_queue=queue_paths, output_queue=queue_arrays, kind="io", ) self.add_work( "process_frame", self.surface_tracking_work.process_frame_func, input_queue=queue_arrays, output_queue=queue_angles, ) self.add_work( "create_couple", self.make_couples, input_queue=(queuemod0_angles, queue_angles, queue_couples_of_names), output_queue=(queuemod_angles, queue_couples_of_arrays), kind="global", ) self.add_work( "correct_couple_of_phases", self.surface_tracking_work.correctcouple, input_queue=queue_couples_of_arrays, output_queue=queuemod0_angles, ) self.add_work( "calcul_height", self.surface_tracking_work.calculheight_func, input_queue=queuemod_angles, output_queue=queue_heights, ) self.add_work("save", self.save_image, input_queue=queue_heights, kind="io") def make_couples(self, input_queues, output_queues): """correctphase""" queue_couples_of_names = input_queues[2] queue_angles = input_queues[1] queuemod0_angles = input_queues[0] queue_couple = output_queues[1] if not (queue_couples_of_names): for key in tuple(queuemod0_angles): output_queues[0][key] = queuemod0_angles[key] del queuemod0_angles[key] if not (queue_angles): print("no queue") return for key, couple in tuple(queue_couples_of_names.items()): # if correspondant arrays are available, make an array couple if couple[0] is couple[1]: if couple[0] in queue_angles.keys(): array1 = queue_angles[couple[0]] array2 = queue_angles[couple[0]] queue_couple[couple[0]] = (array1, array2) del queue_angles[couple[0]] del queue_couples_of_names[key] elif (couple[0] in queuemod0_angles.keys() and couple[1] in queue_angles.keys()): array1 = queuemod0_angles[couple[0]] array2 = queue_angles[couple[1]] queue_couple[couple[1]] = (array1, array2) del queue_angles[couple[1]] del queue_couples_of_names[key] output_queues[0][couple[0]] = queuemod0_angles[couple[0]] del queuemod0_angles[couple[0]] def imread(self, path): array = imread(path) return (array, path) def save_image(self, tuple_image_path): image, path = tuple_image_path name_file = Path(path).name path_out = self.path_dir_result / name_file imsave(path_out, image) def fill_queue_paths(self, input_queue, output_queues): assert input_queue is None queue_paths = output_queues[0] queue_couples_of_names = output_queues[1] serie = self.serie if len(serie) == 0: logger.warning("add 0 image. No image to process.") return names = serie.get_name_arrays() for name in names: path_im_output = self.path_dir_result / name path_im_input = str(self.path_dir_src / name) if self.how_saving == "complete": if not path_im_output.exists(): queue_paths[name] = path_im_input else: queue_paths[name] = path_im_input if len(names) == 0: if self.how_saving == "complete": logger.warning( 'topology in mode "complete" and work already done.') else: logger.warning("Nothing to do") return nb_names = len(names) logger.info(f"Add {nb_names} images to compute.") logger.info("First files to process: " + str(names[:4])) logger.debug("All files: " + str(names)) series = self.series if not series: logger.warning("add 0 couple. No phase to correct.") return nb_series = len(series) logger.info(f"Add {nb_series} phase to correct.") for iserie, serie in enumerate(series): if iserie > 1: break logger.info("Files of serie {}: {}".format( iserie, serie.get_name_arrays())) # for the first corrected angle : corrected_angle = angle ind_serie, serie = next(series.items()) name = serie.get_name_arrays()[0] queue_couples_of_names[ind_serie - 1] = (name, name) for ind_serie, serie in series.items(): queue_couples_of_names[ind_serie] = serie.get_name_arrays()
def __init__(self, params, logging_level="info", nb_max_workers=None): self.params = params if params.surface_tracking is None: raise ValueError("params.surface_tracking has to be set.") self.serie = SerieOfArraysFromFiles(params.images.path, params.images.str_slice) self.series = SeriesOfArrays( params.images.path, "i:i+" + str(self.serie.get_index_slices()[0][2] + 1) + ":" + str(self.serie.get_index_slices()[0][2]), ind_start=self.serie.get_index_slices()[0][0], ind_stop=self.serie.get_index_slices()[0][1] - 1, ind_step=self.serie.get_index_slices()[0][2], ) path_dir = self.serie.path_dir path_dir_result, self.how_saving = prepare_path_dir_result( path_dir, params.saving.path, params.saving.postfix, params.saving.how) self.path_dir_result = path_dir_result self.path_dir_src = Path(path_dir) self.surface_tracking_work = WorkSurfaceTracking(params) super().__init__( path_dir_result=path_dir_result, logging_level=logging_level, nb_max_workers=nb_max_workers, ) queue_paths = self.add_queue("paths") queue_couples_of_names = self.add_queue("couples of names") queue_arrays = self.add_queue("arrays") queue_angles = self.add_queue("angles") queue_couples_of_arrays = self.add_queue( "couples of corrected angles and angles") queuemod0_angles = self.add_queue("corrected angles copy") queuemod_angles = self.add_queue("corrected angles") queue_heights = self.add_queue("heights") self.add_work( "fill_path", self.fill_queue_paths, output_queue=(queue_paths, queue_couples_of_names), kind="one shot", ) self.add_work( "read_array", self.imread, input_queue=queue_paths, output_queue=queue_arrays, kind="io", ) self.add_work( "process_frame", self.surface_tracking_work.process_frame_func, input_queue=queue_arrays, output_queue=queue_angles, ) self.add_work( "create_couple", self.make_couples, input_queue=(queuemod0_angles, queue_angles, queue_couples_of_names), output_queue=(queuemod_angles, queue_couples_of_arrays), kind="global", ) self.add_work( "correct_couple_of_phases", self.surface_tracking_work.correctcouple, input_queue=queue_couples_of_arrays, output_queue=queuemod0_angles, ) self.add_work( "calcul_height", self.surface_tracking_work.calculheight_func, input_queue=queuemod_angles, output_queue=queue_heights, ) self.add_work("save", self.save_image, input_queue=queue_heights, kind="io")
def __init__(self, params=None, logging_level="info", nb_max_workers=None): if params is None: params = self.__class__.create_default_params() self.params = params self.piv_work = WorkPIV(params) serie_arrays = SerieOfArraysFromFiles(params.series.path) self.series = SeriesOfArrays( serie_arrays, params.series.strcouple, ind_start=params.series.ind_start, ind_stop=params.series.ind_stop, ind_step=params.series.ind_step, ) path_dir = self.series.serie.path_dir path_dir_result, self.how_saving = prepare_path_dir_result( path_dir, params.saving.path, params.saving.postfix, params.saving.how) self.path_dir_result = path_dir_result self.results = {} def save_piv_object(o): ret = o.save(path_dir_result) return ret self.wq_piv = WaitingQueueThreading("delta", save_piv_object, self.results, topology=self) self.wq_couples = WaitingQueueMultiprocessing("couple", self.piv_work.calcul, self.wq_piv, topology=self) self.wq_images = WaitingQueueMakeCouple("array image", self.wq_couples, topology=self) if params.preproc.im2im is not None: self.im2im_func = image2image.TopologyImage2Image.init_im2im( self, params.preproc) self.wq_images0 = WaitingQueueMultiprocessing("image ", self.im2im_func, self.wq_images, topology=self) wq_after_load = self.wq_images0 else: wq_after_load = self.wq_images self.wq0 = WaitingQueueLoadImage(destination=wq_after_load, path_dir=path_dir, topology=self) if params.preproc.im2im is not None: waiting_queues = [ self.wq0, self.wq_images0, self.wq_images, self.wq_couples, self.wq_piv, ] else: waiting_queues = [ self.wq0, self.wq_images, self.wq_couples, self.wq_piv, ] super().__init__( waiting_queues, path_output=path_dir_result, logging_level=logging_level, nb_max_workers=nb_max_workers, ) self.add_series(self.series)
class TopologyBOS(TopologyBase): """Topology for BOS computation. See https://en.wikipedia.org/wiki/Background-oriented_schlieren_technique The most useful methods for the user (in particular :func:`compute`) are defined in the base class :class:`fluidimage.topologies.base.TopologyBase`. Parameters ---------- params : None A ParamContainer (created with the class method :func:`create_default_params`) containing the parameters for the computation. logging_level : str, {'warning', 'info', 'debug', ...} Logging level. nb_max_workers : None, int Maximum numbers of "workers". If None, a number is computed from the number of cores detected. If there are memory errors, you can try to decrease the number of workers. """ @classmethod def create_default_params(cls): """Class method returning the default parameters. Typical usage:: params = TopologyPIV.create_default_params() # modify parameters here ... topo = TopologyPIV(params) """ params = ParamContainer(tag="params") params._set_child("images", attribs={"path": "", "str_slice": None}) params.images._set_doc( """ Parameters indicating the input image set. path : str, {''} String indicating the input images (can be a full path towards an image file or a string given to `glob`). str_slice : None String indicating as a Python slicing how to select images from the serie of images on the disk. If None, no selection so all images are going to be processed. """ ) params._set_attrib("reference", 0) params._set_doc( """ reference : str or int, {0} Reference file (from which the displacements will be computed). Can be an absolute file path, a file name or the index in the list of files found from the parameters in ``params.images``. """ ) params._set_child( "saving", attribs={"path": None, "how": "ask", "postfix": "bos"} ) params.saving._set_doc( """Saving of the results. path : None or str Path of the directory where the data will be saved. If None, the path is obtained from the input path and the parameter `postfix`. how : str {'ask'} 'ask', 'new_dir', 'complete' or 'recompute'. postfix : str Postfix from which the output file is computed. """ ) WorkPIV._complete_params_with_default(params) params._set_internal_attr( "_value_text", json.dumps( { "program": "fluidimage", "module": "fluidimage.topologies.bos", "class": "TopologyBOS", } ), ) params._set_child("preproc") image2image.complete_im2im_params_with_default(params.preproc) return params def __init__(self, params, logging_level="info", nb_max_workers=None): self.params = params self.serie = SerieOfArraysFromFiles( params.images.path, params.images.str_slice ) path_dir = Path(self.serie.path_dir) path_dir_result, self.how_saving = prepare_path_dir_result( path_dir, params.saving.path, params.saving.postfix, params.saving.how ) self.path_dir_result = path_dir_result self.path_dir_src = Path(path_dir) if not isinstance(params.reference, int): reference = Path(params.reference).expanduser() else: reference = params.reference if isinstance(reference, int): names = self.serie.get_name_arrays() names = sorted(names) path_reference = path_dir / names[reference] else: reference = Path(reference) if reference.is_file(): path_reference = reference else: path_reference = path_dir_result / reference if not path_reference.is_file(): raise ValueError( "Bad value of params.reference:" + path_reference ) self.name_reference = path_reference.name self.path_reference = path_reference self.image_reference = imread(path_reference) super().__init__( path_dir_result=path_dir_result, logging_level=logging_level, nb_max_workers=nb_max_workers, ) queue_paths = self.add_queue("paths") queue_arrays = queue_arrays1 = self.add_queue("arrays") queue_bos = self.add_queue("bos") if params.preproc.im2im is not None: queue_arrays1 = self.add_queue("arrays1") self.add_work( "fill paths", func_or_cls=self.fill_queue_paths, output_queue=queue_paths, kind=("global", "one shot"), ) def _imread(path): image = imread(path) return image, Path(path).name self.add_work( "read array", func_or_cls=_imread, input_queue=queue_paths, output_queue=queue_arrays, kind="io", ) if params.preproc.im2im is not None: im2im_func = image2image.TopologyImage2Image.init_im2im( self, params.preproc ) self.add_work( "image2image", func_or_cls=im2im_func, input_queue=queue_arrays, output_queue=queue_arrays1, ) self.add_work( "compute bos", func_or_cls=self.calcul, params_cls=params, input_queue=queue_arrays, output_queue=queue_bos, ) self.add_work( "save bos", func_or_cls=self.save_bos_object, input_queue=queue_bos, kind="io", ) def save_bos_object(self, obj): """Save a BOS object""" ret = obj.save(self.path_dir_result, kind="bos") return ret def calcul(self, tuple_image_path): """Compute a BOS field""" image, name = tuple_image_path array_couple = ArrayCoupleBOS( names=(self.name_reference, name), arrays=(self.image_reference, image), params_mask=self.params.mask, serie=self.serie, paths=[self.path_reference, self.path_dir_src / name], ) return WorkPIV(self.params).calcul(array_couple) def fill_queue_paths(self, input_queue, output_queue): """Fill the first queue (paths)""" assert input_queue is None serie = self.serie if not serie: logger.warning("add 0 image. No image to process.") return names = serie.get_name_arrays() for name in names: path_im_output = self.path_dir_result / name path_im_input = str(self.path_dir_src / name) if self.how_saving == "complete": if not path_im_output.exists(): output_queue[name] = path_im_input else: output_queue[name] = path_im_input if not names: if self.how_saving == "complete": logger.warning( 'topology in mode "complete" and work already done.' ) else: logger.warning("Nothing to do") return try: del output_queue[self.path_reference] except KeyError: pass nb_names = len(names) logger.info(f"Add {nb_names} images to compute.") logger.info(f"First files to process: {names[:4]}") logger.debug(f"All files: {names}") def make_text_at_exit(self, time_since_start): """Make a text printed at exit""" txt = "Stop compute after t = {time_since_start:.2f} s" try: nb_results = len(self.results) except AttributeError: nb_results = None if nb_results is not None and nb_results > 0: txt += f" ({nb_results} bos fields, {time_since_start / nb_results:.2f} s/field)." else: txt += "." txt += f"\npath results:\n{self.path_dir_result}" return txt
def __init__(self, params, logging_level="info", nb_max_workers=None): self.params = params self.serie = SerieOfArraysFromFiles( params.images.path, params.images.str_slice ) path_dir = Path(self.serie.path_dir) path_dir_result, self.how_saving = prepare_path_dir_result( path_dir, params.saving.path, params.saving.postfix, params.saving.how ) self.path_dir_result = path_dir_result self.path_dir_src = Path(path_dir) if not isinstance(params.reference, int): reference = Path(params.reference).expanduser() else: reference = params.reference if isinstance(reference, int): names = self.serie.get_name_arrays() names = sorted(names) path_reference = path_dir / names[reference] else: reference = Path(reference) if reference.is_file(): path_reference = reference else: path_reference = path_dir_result / reference if not path_reference.is_file(): raise ValueError( "Bad value of params.reference:" + path_reference ) self.name_reference = path_reference.name self.path_reference = path_reference self.image_reference = imread(path_reference) super().__init__( path_dir_result=path_dir_result, logging_level=logging_level, nb_max_workers=nb_max_workers, ) queue_paths = self.add_queue("paths") queue_arrays = queue_arrays1 = self.add_queue("arrays") queue_bos = self.add_queue("bos") if params.preproc.im2im is not None: queue_arrays1 = self.add_queue("arrays1") self.add_work( "fill paths", func_or_cls=self.fill_queue_paths, output_queue=queue_paths, kind=("global", "one shot"), ) def _imread(path): image = imread(path) return image, Path(path).name self.add_work( "read array", func_or_cls=_imread, input_queue=queue_paths, output_queue=queue_arrays, kind="io", ) if params.preproc.im2im is not None: im2im_func = image2image.TopologyImage2Image.init_im2im( self, params.preproc ) self.add_work( "image2image", func_or_cls=im2im_func, input_queue=queue_arrays, output_queue=queue_arrays1, ) self.add_work( "compute bos", func_or_cls=self.calcul, params_cls=params, input_queue=queue_arrays, output_queue=queue_bos, ) self.add_work( "save bos", func_or_cls=self.save_bos_object, input_queue=queue_bos, kind="io", )