def test_minimal_piv(self): params = WorkPIV.create_default_params() # for a very short computation params.piv0.shape_crop_im0 = 32 params.piv0.grid.overlap = -3 # still buggy # params.piv0.nb_peaks_to_search = 2 params.multipass.number = 2 params.fix.displacement_max = 2 params.fix.threshold_diff_neighbour = 2 piv = WorkPIV(params=params) with stdout_redirected(): result = piv.calcul(self.serie) result.piv0.save(self.path_tmp) result.save(self.path_tmp) path_file = next(self.path_tmp.iterdir()) MultipassPIVResults(path_file) result.save(self.path_tmp, "uvmat") light = result.make_light_result() light.save(self.path_tmp) path_file = next(self.path_tmp.glob("*light*")) LightPIVResults(str_path=str(path_file))
def test_piv_list(self): params = WorkPIV.create_default_params() # for a very short computation params.piv0.shape_crop_im0 = [33, 44] params.piv0.grid.overlap = -3 # params.piv0.nb_peaks_to_search = 2 params.multipass.use_tps = False piv = WorkPIV(params=params) with stdout_redirected(): result = piv.calcul(self.serie) piv0 = result.piv0 im0, im1 = piv0.get_images() with stdout_redirected(): DisplayPIV(im0, im1, piv0) d = DisplayPIV(im0, im1, piv0, show_interp=True, hist=True) d.switch() d.select_arrow([0], artist=d.q) d.select_arrow([0], artist=None) event = MyObj() event.key = "alt+h" event.inaxes = None d.onclick(event) event.inaxes = d.ax1 event.key = "alt+s" d.onclick(event) event.key = "alt+left" d.onclick(event) event.key = "alt+right" d.onclick(event) event.artist = None d.onpick(event) event.artist = d.q event.ind = [0] d.onpick(event)
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)
from fluidimage import SeriesOfArrays from fluidimage.works.piv import WorkPIV params = WorkPIV.create_default_params() params.multipass.number = 2 params.multipass.use_tps = True params.piv0.shape_crop_im0 = 32 params.piv0.displacement_max = 5 params.fix.correl_min = 0.2 params.fix.threshold_diff_neighbour = 8 params.mask.strcrop = '30:250, 100:' work = WorkPIV(params=params) path = '../../image_samples/Oseen/Images' # path = '../../image_samples/Karman/Images' series = SeriesOfArrays(path, 'i+1:i+3') serie = series.get_serie_from_index(0) piv = work.calcul(serie) # piv.display(show_interp=True, scale=0.3, show_error=True) piv.display(show_interp=False, scale=1, show_error=True) # result.save()
import pstats import cProfile from fluidimage import SeriesOfArrays from fluidimage.works.piv import WorkPIV params = WorkPIV.create_default_params() # for a very short computation params.piv0.shape_crop_im0 = 32 params.piv0.grid.overlap = 0.5 # params.piv0.method_subpix = 'centroid' # params.piv0.method_correl = 'theano' params.multipass.number = 2 params.multipass.use_tps = 'last' params.multipass.coeff_zoom = [2] piv = WorkPIV(params=params) series = SeriesOfArrays('../../image_samples/Oseen/Images', 'i+1:i+3') serie = series.get_serie_from_index(0) cProfile.runctx('result = piv.calcul(serie)', globals(), locals(), 'profile.pstats') s = pstats.Stats('profile.pstats') s.strip_dirs().sort_stats('time').print_stats(10) print('with gprof2dot and graphviz (command dot):\n'
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( "series", attribs={ "path": "", "strcouple": "i:i+2", "ind_start": 0, "ind_stop": None, "ind_step": 1, }, ) params.series._set_doc(""" Parameters indicating the input series of images. path : str, {''} String indicating the input images (can be a full path towards an image file or a string given to `glob`). strcouple : 'i:i+2' String indicating as a Python slicing how couples of images are formed. There is one couple per value of `i`. The values of `i` are set with the other parameters `ind_start`, `ind_step` and `ind_stop` approximately with the function range (`range(ind_start, ind_stop, ind_step)`). Python slicing is a very powerful notation to define subset from a (possibly multidimensional) set of images. For a user, an alternative is to understand how Python slicing works. See for example this page: http://stackoverflow.com/questions/509211/explain-pythons-slice-notation. Another possibility is to follow simple examples: For single-frame images (im0, im1, im2, im3, ...), we keep the default value 'i:i+2' to form the couples (im0, im1), (im1, im2), ... To see what it gives, one can use IPython and range: >>> i = 0 >>> list(range(10))[i:i+2] [0, 1] >>> list(range(10))[i:i+4:2] [0, 2] We see that we can also use the value 'i:i+4:2' to form the couples (im0, im2), (im1, im3), ... For double-frame images (im1a, im1b, im2a, im2b, ...) you can write >>> params.series.strcouple = 'i, 0:2' In this case, the first couple will be (im1a, im1b). To get the first couple (im1a, im1a), we would have to write >>> params.series.strcouple = 'i:i+2, 0' ind_start : int, {0} ind_step : int, {1} int_stop : None """) params._set_child("saving", attribs={ "path": None, "how": "ask", "postfix": "piv" }) 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.piv", "class": "TopologyPIV", }), ) 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.series = SeriesOfArrays( params.series.path, 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) super().__init__( path_dir_result=path_dir_result, logging_level=logging_level, nb_max_workers=nb_max_workers, ) queue_couples_of_names = self.add_queue("couples of names") queue_paths = self.add_queue("paths") queue_arrays = queue_arrays1 = self.add_queue("arrays") queue_couples_of_arrays = self.add_queue("couples of arrays") queue_piv = self.add_queue("piv") if params.preproc.im2im is not None: queue_arrays1 = self.add_queue("arrays1") self.add_work( "fill (couples of names, paths)", func_or_cls=self.fill_couples_of_names_and_paths, output_queue=(queue_couples_of_names, queue_paths), kind=("global", "one shot"), ) 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( "make couples of arrays", func_or_cls=self.make_couples, params_cls=None, input_queue=(queue_couples_of_names, queue_arrays), output_queue=queue_couples_of_arrays, kind="global", ) self.work_piv = WorkPIV(self.params) self.add_work( "compute piv", func_or_cls=self.work_piv.calcul, params_cls=params, input_queue=queue_couples_of_arrays, output_queue=queue_piv, ) self.add_work( "save piv", func_or_cls=self.save_piv_object, input_queue=queue_piv, kind="io", ) self.results = []
from fluidimage.works.piv import WorkPIV import params_piv try: reload except NameError: from importlib import reload reload(params_piv) iexp = 0 params = params_piv.make_params_piv(iexp) work = WorkPIV(params=params) pathin = params.series.path series = SeriesOfArrays(pathin, params.series.strcouple, ind_start=params.series.ind_start) # c060a.png and c060b.png serie = series.get_serie_from_index(params.series.ind_start) piv = work.calcul(serie) # piv.piv0.display(show_interp=True, scale=0.05, show_error=True) piv.display(show_interp=False, scale=0.05, show_error=True)
class TopologyPIV(TopologyBase): """Topology for PIV. 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") params._set_child( "series", attribs={ "path": "", "strcouple": "i:i+2", "ind_start": 0, "ind_stop": None, "ind_step": 1, }, ) params.series._set_doc(""" Parameters indicating the input series of images. path : str, {''} String indicating the input images (can be a full path towards an image file or a string given to `glob`). strcouple : 'i:i+2' String indicating as a Python slicing how couples of images are formed. There is one couple per value of `i`. The values of `i` are set with the other parameters `ind_start`, `ind_step` and `ind_stop` approximately with the function range (`range(ind_start, ind_stop, ind_step)`). Python slicing is a very powerful notation to define subset from a (possibly multidimensional) set of images. For a user, an alternative is to understand how Python slicing works. See for example this page: http://stackoverflow.com/questions/509211/explain-pythons-slice-notation. Another possibility is to follow simple examples: For single-frame images (im0, im1, im2, im3, ...), we keep the default value 'i:i+2' to form the couples (im0, im1), (im1, im2), ... To see what it gives, one can use ipython and range: >>> i = 0 >>> list(range(10))[i:i+2] [0, 1] >>> list(range(10))[i:i+4:2] [0, 2] We see that we can also use the value 'i:i+4:2' to form the couples (im0, im2), (im1, im3), ... For double-frame images (im1a, im1b, im2a, im2b, ...) you can write >>> params.series.strcouple = 'i, 0:2' In this case, the first couple will be (im1a, im1b). To get the first couple (im1a, im1a), we would have to write >>> params.series.strcouple = 'i:i+2, 0' ind_start : int, {0} ind_step : int, {1} int_stop : None """) params._set_child("saving", attribs={ "path": None, "how": "ask", "postfix": "piv" }) 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.piv", "class": "TopologyPIV", }), ) params._set_child("preproc") image2image.complete_im2im_params_with_default(params.preproc) return params 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) def add_series(self, series): if len(series) == 0: logger.warning("add 0 couple. No PIV to compute.") return if self.how_saving == "complete": names = [] index_series = [] for i, serie in enumerate(series): name_piv = get_name_piv(serie, prefix="piv") if os.path.exists(os.path.join(self.path_dir_result, name_piv)): continue for name in serie.get_name_arrays(): if name not in names: names.append(name) index_series.append(i * series.ind_step + series.ind_start) if len(index_series) == 0: logger.warning( 'topology in mode "complete" and work already done.') return series.set_index_series(index_series) logger.debug(repr(names)) logger.debug(repr([serie.get_name_arrays() for serie in series])) else: names = series.get_name_all_arrays() nb_series = len(series) print("Add {} PIV fields to compute.".format(nb_series)) for i, serie in enumerate(series): if i > 1: break print("Files of serie {}: {}".format(i, serie.get_name_arrays())) self.wq0.add_name_files(names) self.wq_images.add_series(series) k, o = self.wq0.popitem() im = self.wq0.work(o) self.wq0.fill_destination(k, im) # a little bit strange, to apply mask... try: params_mask = self.params.mask except AttributeError: params_mask = None couple = ArrayCouple(names=("", ""), arrays=(im, im), params_mask=params_mask) im, _ = couple.get_arrays() self.piv_work._prepare_with_image(im) def print_at_exit(self, time_since_start): txt = "Stop compute after t = {:.2f} s".format(time_since_start) try: nb_results = len(self.results) except AttributeError: nb_results = None if nb_results is not None and nb_results > 0: txt += " ({} piv fields, {:.2f} s/field).".format( nb_results, time_since_start / nb_results) else: txt += "." txt += "\npath results:\n" + str(self.path_dir_result) print(txt)
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)
# import h5py from fluidimage import SeriesOfArrays from fluidimage.works.piv import WorkPIV from fluidimage.data_objects.piv import LightPIVResults params = WorkPIV.create_default_params() # # for a very short computation # params.piv0.shape_crop_im0 = 128 # params.piv0.grid.overlap = 0. # params.piv0.method_subpix = 'centroid' # params.piv0.method_correl = 'pythran' params.multipass.number = 1 params.multipass.use_tps = False # params.multipass.coeff_zoom = [2, 2] # bug params.piv0.shape_crop_im0 = 128 # !! params.piv0.shape_crop_im0 = 64 # (80, 90) # params.piv0.shape_crop_im1 = (38, 36) params.fix.correl_min = 0.2 params.fix.threshold_diff_neighbour = 4 # params.piv0.grid.overlap = 10 piv = WorkPIV(params=params) series = SeriesOfArrays("../../../image_samples/Oseen/Images", "i+1:i+3") serie = series.get_serie_from_index(0)
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