Beispiel #1
0
    def detect_triple_points(self,
                             smooth=None,
                             use_x_minima=False,
                             verbose=False):
        """
        Compute the triple points (water, oil and air interfaces) positions.

        Parameters
        ==========
        smooth: number
           Smoothing factor for the triple point position.
        use_x_minima: boolean
            If True, try to define the triple point as the minimal x values and
            fall back to the curvature method if necessary.
            (default to False).

        Returns
        =======
        tripl_pts: 2x2 array of numbers
           Position of the triple points for each edge ([pt1, pt2])
        """
        if verbose:
            pg = ProgressCounter(init_mess="Detecting triple point positions",
                                 nmb_max=len(self.fits),
                                 name_things='triple points',
                                 perc_interv=5)
        for fit in self.fits:
            try:
                fit.detect_triple_points(use_x_minima=use_x_minima)
            except Exception:
                pass
            if verbose:
                pg.print_progress()
        if smooth is not None:
            self.smooth_triple_points(tos='gaussian', size=smooth)
    def fit_polyline(self, deg=5, iteration_hook=None, verbose=False):
        """
        Compute a polyline fitting for the droplets shape.

        Parameters
        ----------
        deg : integer
            Degree of the polynomial fitting.
        iteration_hook: function
            Hook run at each iterations with the iteration number
            and the total number of iterations planned.
        """
        if verbose:
            pg = ProgressCounter(init_mess="Fitting droplet interfaces",
                                 nmb_max=len(self.point_sets),
                                 name_things='edges',
                                 perc_interv=5)
        fits = []
        for i, edge in enumerate(self.point_sets):
            try:
                fits.append(edge.fit_polyline(deg=deg, verbose=False))
            except Exception:
                fits.append(
                    dropfit.DropFit(baseline=edge.baseline,
                                    x_bounds=edge.x_bounds,
                                    y_bounds=edge.y_bounds))
            if verbose:
                pg.print_progress()
            if iteration_hook is not None:
                iteration_hook(i, len(self.point_sets))
        # return
        tf = TemporalSplineFits(fits=fits, temporaledges=self)
        return tf
    def fit_ellipse(self, triple_pts=None, iteration_hook=None, verbose=False):
        """
        Fit an ellipse to the edges.

        Ignore the lower part of the drop if triple points are presents.

        Parameters
        ----------
        iteration_hook: function
            Hook run at each iterations with the iteration number
            and the total number of iterations planned.
        """
        if verbose:
            pg = ProgressCounter(init_mess="Fitting ellipses to edges",
                                 nmb_max=len(self.point_sets),
                                 name_things='edges',
                                 perc_interv=5)
        fits = []
        for i, edge in enumerate(self.point_sets):
            try:
                fits.append(edge.fit_ellipse(triple_pts=triple_pts))
            except Exception:
                fits.append(
                    dropfit.DropFit(baseline=edge.baseline,
                                    x_bounds=edge.x_bounds,
                                    y_bounds=edge.y_bounds))
            if verbose:
                pg.print_progress()
            if iteration_hook is not None:
                iteration_hook(i, len(self.point_sets))
        # return
        tf = TemporalEllipseFits(fits=fits, temporaledges=self)
        return tf
    def fit_circles(self,
                    triple_pts,
                    sigma_max=None,
                    verbose=False,
                    nmb_pass=1,
                    soft_constr=False,
                    iteration_hook=None):
        """
        Fit circles to the edges, cutting them if a triple point is
        present.

        Parameters
        ==========
        sigma_max: number
            If specified, points too far from the fit are iteratively removed
            until:
            std(R) < mean(R)*sigma_max
            With R the radii.
        nmb_pass: positive integer
            If superior to 1, specify the number of pass to make.
            Addintional passes use the previously triple points detected by
            circle fits to more accurately detect the next ones.
        iteration_hook: function
            Hook run at each iterations with the iteration number
            and the total number of iterations planned.
        """
        if verbose:
            pg = ProgressCounter(init_mess="Fitting circles to edges",
                                 nmb_max=len(self.point_sets) * nmb_pass,
                                 name_things='edges',
                                 perc_interv=5)
        # check
        if len(triple_pts) != len(self.point_sets):
            raise Exception('Not the right ner of triple points')
        #  passes
        tf = None
        for i in range(nmb_pass):
            if tf is not None:
                tf.smooth_triple_points('gaussian', size=10)
                triple_pts = tf.get_triple_points()
            fits = []
            for tp, edge in zip(triple_pts, self.point_sets):
                try:
                    fits.append(
                        edge.fit_circles(triple_pts=tp,
                                         sigma_max=sigma_max,
                                         soft_constr=soft_constr))
                except Exception:
                    fits.append(
                        dropfit.DropFit(baseline=edge.baseline,
                                        x_bounds=edge.x_bounds,
                                        y_bounds=edge.y_bounds))
                if verbose:
                    pg.print_progress()
                if iteration_hook is not None:
                    iteration_hook(i, len(self.point_sets) * nmb_pass)
            tf = TemporalCirclesFits(fits=fits, temporaledges=self)
        # return
        return tf
Beispiel #5
0
    def get_background(self, noise_level=10, verbose=False):
        """
        Return the background image based on the histogram of values
        at each point.

        Parameters
        ----------
        noise_level: integer
             Level of noise used to differentiate between noise and
             real perturbation of the background image.

        Returns
        -------
        bg: ScalarField object
             Background image
        """
        # Data
        min_len = len(self.times) / 10
        values = np.zeros(self.shape)
        if verbose:
            pg = ProgressCounter(init_mess="Computing background image",
                                 nmb_max=self.shape[0] * self.shape[1],
                                 name_things="Pixels",
                                 perc_interv=1)
        # Spatial loop
        for i, j in np.ndindex(self.shape):
            vals = np.array([
                self.fields[n]._ScalarField__values[i, j]
                for n in range(len(self.fields))
            ])
            # # HIST
            # hist = np.bincount(vals)
            # val = np.argmax(hist)
            # STATS
            std = np.std(vals, dtype=float)
            old_std = 0
            mean = np.mean(vals, dtype=float)
            while True:
                vals = vals[np.logical_and(vals > mean - std,
                                           vals < mean + std)]
                old_std = std
                std = np.std(vals)
                mean = np.mean(vals)
                if std < noise_level or len(vals) <= min_len or old_std == std:
                    break
            values[i, j] = mean
            if verbose:
                pg.print_progress()
        bg = sf.ScalarField()
        bg.import_from_arrays(axe_x=self.axe_x,
                              axe_y=self.axe_y,
                              values=values,
                              unit_x=self.unit_x,
                              unit_y=self.unit_y)
        return bg
Beispiel #6
0
    def substract_background(self,
                             bg,
                             noise_level=10,
                             blend=True,
                             filling_value=None,
                             verbose=False):
        """
        Remove the background without changing the perturbations.

        Parameters
        ----------
        bg: ScalarField object
             Background image
        noise_level: integer
             Level of noise used to differentiate between noise and
             real perturbation of the background image.
        blend: boolean
             Blend the foreground in the background.
        filling_value: integer
             Value used to fill the background.
             Default to the background spatial average.

        Returns
        -------
        nsf: TemporalScalarFields object
            substracted fields.
        """
        # data
        ntf = self.copy()
        bg_mean = bg.mean
        if filling_value is None:
            filling_value = bg_mean
        if verbose:
            pg = ProgressCounter(init_mess="Substracting background image",
                                 nmb_max=len(self.fields),
                                 name_things="Fields")
        # Spatial loop
        for n in range(len(ntf)):
            # Get foreground
            values = ntf.fields[n].values
            mask = np.logical_and(values < bg.values + noise_level,
                                  bg.values - noise_level < values)
            # get foreground and background avg
            if blend:
                fg_mean = np.mean(values[~mask])
                blend_field = (values - bg_mean) / (fg_mean - bg_mean)
                blend_field = ndimage.gaussian_filter(blend_field, 1)
                values = values * blend_field + (1 -
                                                 blend_field) * filling_value
            values[mask] = filling_value
            ntf.fields[n].values = values
            if verbose:
                pg.print_progress()
        #
        return ntf
Beispiel #7
0
    def edge_detection_contour(self,
                               size_ratio=.5,
                               nmb_edges=2,
                               level=0.5,
                               ignored_pixels=2,
                               iteration_hook=None,
                               verbose=False):
        """
        Perform edge detection.

        Parameters
        ==========
        nmb_edges: integer
            Number of maximum expected edges (default to 2).
        level: number
            Normalized level of the drop contour.
            Should be between 0 (black) and 1 (white).
            Default to 0.5.
        size_ratio: number
            Minimum size of edges, regarding the bigger detected one
            (default to 0.5).
        ignored_pixels: integer
            Number of pixels ignored around the baseline
            (default to 2).
            Putting a small value to this allow to avoid
            small surface defects to be taken into account.
        """
        pts = tde.TemporalDropEdges()
        pts.baseline = self.baseline
        if verbose:
            pg = ProgressCounter("Detecting drop edges", "Done",
                                 len(self.fields), 'images', 5)
        for i in range(len(self.fields)):
            try:
                pt = self.fields[i].edge_detection_contour(
                    nmb_edges=nmb_edges,
                    level=level,
                    ignored_pixels=ignored_pixels,
                    size_ratio=size_ratio)
            except Exception:
                pt = dropedges.DropEdges(xy=[], im=self, type='contour')
            pts.add_pts(pt, time=self.times[i], unit_times=self.unit_times)
            if verbose:
                pg.print_progress()
            if iteration_hook is not None:
                iteration_hook(i, len(self.fields))
        return pts
Beispiel #8
0
 def compute_contact_angle(self, iteration_hook=None, verbose=False):
     """
     Compute the drop contact angles.
     """
     if verbose:
         pg = ProgressCounter(init_mess="Getting contact angles",
                              nmb_max=len(self.fits),
                              name_things='images',
                              perc_interv=5)
     for i, fit in enumerate(self.fits):
         try:
             fit.compute_contact_angle()
         except Exception:
             pass
         if verbose:
             pg.print_progress()
         if iteration_hook is not None:
             iteration_hook(i, len(self.fits))
    def fit_spline(self, k=5, s=0.75, iteration_hook=None, verbose=False):
        """
        Compute a spline fitting for the droplets shape.

        Parameters
        ----------
        k : int, optional
            Degree of the smoothing spline.  Must be <= 5.
            Default is k=5.
        s : float, optional
            Smoothing factor between 0 (not smoothed) and 1 (very smoothed)
            Default to 0.75
        iteration_hook: function
            Hook run at each iterations with the iteration number
            and the total number of iterations planned.
        """
        if verbose:
            pg = ProgressCounter(init_mess="Fitting droplet interfaces",
                                 nmb_max=len(self.point_sets),
                                 name_things='edges',
                                 perc_interv=5)
        fits = []
        for i, edge in enumerate(self.point_sets):
            try:
                fits.append(edge.fit_spline(k=k, s=s, verbose=False))
            except Exception:
                fits.append(
                    dropfit.DropFit(baseline=edge.baseline,
                                    x_bounds=edge.x_bounds,
                                    y_bounds=edge.y_bounds))
            if verbose:
                pg.print_progress()
            if iteration_hook is not None:
                iteration_hook(i, len(self.point_sets))
        # return
        tf = TemporalSplineFits(fits=fits, temporaledges=self)
        return tf
Beispiel #10
0
    def get_phase_map(self, freq, tf=None, check_spec=None, verbose=True):
        """
        Return the phase map of the temporal scalar field for
        the given frequency.

        Parameters
        ----------
        freq: number
            Wanted frequency
        tf: Integer
            Last time indice to use
        check_spec: Integer
            If not None, specify the number of spectrum to display
            (useful to check if choosen frequencies are relevant).
        verbose: Boolean
            .

        Returns
        -------
        phase_map: ScalarField object
            .
        """
        #
        phases = np.zeros(self.shape, dtype=float)
        norms = np.zeros(self.shape, dtype=float)
        compo = "values"
        if tf is None:
            tf = len(self.fields)
        # select spectrum to display
        if check_spec is not None:
            check_spec_inds = np.random.choice(
                range(self.shape[0] * self.shape[1]), check_spec)
        # get phases
        if verbose:
            pg = ProgressCounter(init_mess="Computing phase maps",
                                 nmb_max=self.shape[0] * self.shape[1],
                                 name_things="profiles")
        for i, x in enumerate(self.axe_x):
            for j, y in enumerate(self.axe_y):
                if verbose:
                    pg.print_progress()
                # get profile
                profile = self.get_time_profile(compo, (x, y),
                                                wanted_times=[0, tf])
                prof = profile.y
                dx = profile.x[1] - profile.x[0]
                # get fft
                fft = np.fft.fft(prof)
                fft = fft[0:int(len(fft) / 2)]
                fft_norm = np.abs(fft)
                fft_phase = np.angle(fft)
                fft_f = np.fft.fftfreq(len(prof), dx)[0:len(fft)]
                # get phase at the wanted frequency
                ind = np.argmin(abs(fft_f - freq))
                # store phases and norms
                phases[i, j] = fft_phase[ind]
                norms[i, j] = fft_norm[ind]
                # display spectrum if asked
                if check_spec:
                    if i * len(self.axe_x) + j in check_spec_inds:
                        fig = plt.figure()
                        ax = fig.add_subplot(1, 1, 1)
                        ax.loglog(fft_f, fft_norm)
                        ax2 = ax.twinx()
                        ax2.plot([], [])
                        ax2.semilogx(fft_f, fft_phase)
                        plt.axvline(fft_f[ind], color="k", ls="--")
                        plt.show(block=True)
        # return
        norm = sf.ScalarField()
        norm.import_from_arrays(axe_x=self.axe_x,
                                axe_y=self.axe_y,
                                values=norms.transpose(),
                                unit_x=self.unit_x,
                                unit_y=self.unit_y,
                                unit_values="")
        phase = sf.ScalarField()
        phase.import_from_arrays(axe_x=self.axe_x,
                                 axe_y=self.axe_y,
                                 values=phases.transpose(),
                                 unit_x=self.unit_x,
                                 unit_y=self.unit_y,
                                 unit_values="rad")
        return norm, phase
Beispiel #11
0
    def edge_detection_canny(self,
                             threshold1=None,
                             threshold2=None,
                             base_max_dist=30,
                             size_ratio=.5,
                             ignored_pixels=2,
                             nmb_edges=2,
                             keep_exterior=True,
                             dilatation_steps=1,
                             smooth_size=None,
                             iteration_hook=None,
                             verbose=False):
        """
        Perform edge detection.

        Parameters
        ==========
        threshold1, threshold2: integers
            Thresholds for the Canny edge detection method.
            (By default, inferred from the data histogram)
        base_max_dist: integers
            Maximal distance (in pixel) between the baseline and
            the beginning of the drop edge (default to 30).
        nmb_edges: integer
            Number of maximum expected edges (default to 2).
        size_ratio: number
            Minimum size of edges, regarding the bigger detected one
            (default to 0.5).
        keep_exterior: boolean
            If True (default), only keep the exterior edges.
        smooth_size: number
            If specified, the image is smoothed before
            performing the edge detection.
            (can be useful to put this to 1 to get rid of compression
             artefacts on images).
        dilatation_steps: positive integer
            Number of dilatation/erosion steps.
            Increase this if the drop edges are discontinuous.
        iteration_hook: function
            Hook run at each iterations with the iteration number
            and the total number of iterations planned.
        """
        # check
        if self.baseline is None:
            raise Exception('You have to define a baseline first.')
        #
        all_edge_empty = True
        pts = tde.TemporalDropEdges()
        pts.baseline = self.baseline
        if verbose:
            pg = ProgressCounter(init_mess="Detecting drop edges",
                                 nmb_max=len(self.fields),
                                 name_things='images',
                                 perc_interv=5)
        for i in range(len(self.fields)):
            try:
                pt = self.fields[i].edge_detection_canny(
                    threshold1=threshold1,
                    threshold2=threshold2,
                    base_max_dist=base_max_dist,
                    size_ratio=size_ratio,
                    ignored_pixels=ignored_pixels,
                    keep_exterior=keep_exterior,
                    nmb_edges=nmb_edges,
                    dilatation_steps=dilatation_steps,
                    smooth_size=smooth_size)
                all_edge_empty = False
            except Exception:
                pt = dropedges.DropEdges(xy=[], im=self, type='canny')
            pts.add_pts(pt, time=self.times[i], unit_times=self.unit_times)
            if iteration_hook is not None:
                iteration_hook(i, len(self.fields))
            if verbose:
                pg.print_progress()
        # check if edges has been detected
        if all_edge_empty:
            raise Exception('No edges could be detected. You should'
                            ' check the baseline position.')
        return pts