Beispiel #1
0
    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
Beispiel #3
0
    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")
Beispiel #4
0
 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")
Beispiel #7
0
    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)
Beispiel #8
0
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
Beispiel #9
0
    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",
        )