Ejemplo n.º 1
0
def get_coordinates(image_size, search_area_size, window_size, overlap):
    """Compute the x, y coordinates of the centers of the interrogation windows.

    Parameters
    ----------
    image_size: two elements tuple
        a three dimensional tuple for the pixel size of the image

    window_size: tuple
        the size of the interrogation window.

    search_area_size: tuple
        the size of the search area window.

    overlap: tuple
        the number of pixel by which two adjacent interrogation
        windows overlap.


    Returns
    -------
    x : 23 np.ndarray
        a three dimensional array containing the x coordinates of the
        interrogation window centers, in pixels.

    y : 23 np.ndarray
        a three dimensional array containing the y coordinates of the
        interrogation window centers, in pixels.

    z : 23 np.ndarray
        a three dimensional array containing the y coordinates of the
        interrogation window centers, in pixels.

    """

    # get shape of the resulting flow field
    field_shape = get_field_shape(image_size, search_area_size, overlap)

    # compute grid coordinates of the search area centers
    x = (np.arange(field_shape[1]) * (window_size[1] - overlap[1]) +
         (search_area_size[1] - 1) / 2.0)
    y = (np.arange(field_shape[0]) * (window_size[0] - overlap[0]) +
         (search_area_size[0] - 1) / 2.0)
    z = (np.arange(field_shape[2]) * (window_size[2] - overlap[2]) +
         (search_area_size[2] - 1) / 2.0)

    # moving coordinates further to the center, so that the points at the extreme left/right or top/bottom
    # have the same distance to the window edges. For simplicity only integer movements are allowed.
    x += (image_size[1] - 1 -
          ((field_shape[1] - 1) * (window_size[1] - overlap[1]) +
           (search_area_size[1] - 1))) // 2
    y += (image_size[0] - 1 -
          ((field_shape[0] - 1) * (window_size[0] - overlap[0]) +
           (search_area_size[0] - 1))) // 2
    z += (image_size[2] - 1 -
          ((field_shape[2] - 1) * (window_size[2] - overlap[2]) +
           (search_area_size[2] - 1))) // 2

    return np.meshgrid(x, y, z)
Ejemplo n.º 2
0
def get_coordinates(image_size, window_size, overlap):
    """Compute the x, y coordinates of the centers of the interrogation windows.

        Parameters
        ----------
        image_size: two elements tuple
            a two dimensional tuple for the pixel size of the image
            first element is number of rows, second element is 
            the number of columns.

        window_size: int
            the size of the interrogation windows.

        overlap: int
            the number of pixel by which two adjacent interrogation
            windows overlap.


        Returns
        -------
        x : 2d np.ndarray
            a two dimensional array containing the x coordinates of the 
            interrogation window centers, in pixels.

        y : 2d np.ndarray
            a two dimensional array containing the y coordinates of the 
            interrogation window centers, in pixels.

        """

    # get shape of the resulting flow field
    '''%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        The get_field_shape function calculates how many interrogation windows
        fit in the image in each dimension output is a 
        tuple (amount of interrogation windows in y, amount of interrogation windows in x)
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        The get coordinates function calculates the coordinates of the center of each 
        interrogation window using bases on the to field_shape returned by the
        get field_shape function, the window size and the overlap. It returns a meshgrid
        of the interrogation area centers.
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        '''

    field_shape = pyprocess.get_field_shape(image_size, window_size, overlap)

    # compute grid coordinates of the interrogation window centers
    x = np.arange(
        field_shape[1]) * (window_size - overlap) + (window_size) / 2.0
    y = np.arange(
        field_shape[0]) * (window_size - overlap) + (window_size) / 2.0

    return np.meshgrid(x, y[::-1])
Ejemplo n.º 3
0
def run_piv(
    frame_a,
    frame_b,
    winsize=16,  # pixels, interrogation window size in frame A
    searchsize=20,  # pixels, search in image B
    overlap=8,  # pixels, 50% overlap
    dt=0.0001,  # sec, time interval between pulses
    image_check=False,
    show_vertical_profiles=False,
    figure_export_name='_results.png',
    text_export_name="_results.txt",
    scale_factor=1,
    pixel_density=36.74,
    arrow_width=0.001,
    show_result=True,
    u_bounds=(-100, 100),
    v_bounds=(-100, 100)):

    u0, v0, sig2noise = pyprocess.extended_search_area_piv(
        frame_a.astype(np.int32),
        frame_b.astype(np.int32),
        window_size=winsize,
        overlap=overlap,
        dt=dt,
        search_area_size=searchsize,
        sig2noise_method='peak2peak')

    x, y = pyprocess.get_coordinates(image_size=frame_a.shape,
                                     search_area_size=searchsize,
                                     overlap=overlap)

    x, y, u0, v0 = scaling.uniform(
        x, y, u0, v0, scaling_factor=pixel_density)  # no. pixel per distance

    u0, v0, mask = validation.global_val(u0, v0, u_bounds, v_bounds)

    u1, v1, mask = validation.sig2noise_val(u0, v0, sig2noise, threshold=1.05)

    u3, v3 = filters.replace_outliers(u1,
                                      v1,
                                      method='localmean',
                                      max_iter=10,
                                      kernel_size=3)

    #save in the simple ASCII table format
    if np.std(u3) < 480:
        tools.save(x, y, u3, v3, sig2noise, mask, text_export_name)

    if image_check == True:
        fig, ax = plt.subplots(2, 1, figsize=(24, 12))
        ax[0].imshow(frame_a)
        ax[1].imshow(frame_b)

    io.imwrite(figure_export_name, frame_a)

    if show_result == True:
        fig, ax = plt.subplots(figsize=(24, 12))
        tools.display_vector_field(
            text_export_name,
            ax=ax,
            scaling_factor=pixel_density,
            scale=scale_factor,  # scale defines here the arrow length
            width=arrow_width,  # width is the thickness of the arrow
            on_img=True,  # overlay on the image
            image_name=figure_export_name)
        fig.savefig(figure_export_name)

    if show_vertical_profiles:
        field_shape = pyprocess.get_field_shape(image_size=frame_a.shape,
                                                search_area_size=searchsize,
                                                overlap=overlap)
        vertical_profiles(text_export_name, field_shape)

    print('Std of u3: %.3f' % np.std(u3))
    print('Mean of u3: %.3f' % np.mean(u3))

    return np.std(u3)
Ejemplo n.º 4
0
    def quick_piv(self, search_dict, index_a=100, index_b=101, folder=None):
        self.show_piv_param()
        ns = Namespace(**self.piv_param)

        if folder == None:
            img_a, img_b = self.read_two_images(search_dict,
                                                index_a=index_a,
                                                index_b=index_b)

            location_path = [
                x['path'] for x in self.piv_dict_list
                if search_dict.items() <= x.items()
            ]
            results_path = os.path.join(self.results_path, *location_path)
            try:
                os.makedirs(results_path)
            except FileExistsError:
                pass
        else:
            try:
                file_a_path = os.path.join(self.path, folder,
                                           'frame_%06d.tiff' % index_a)
                file_b_path = os.path.join(self.path, folder,
                                           'frame_%06d.tiff' % index_b)

                img_a = np.array(Image.open(file_a_path))
                img_b = np.array(Image.open(file_b_path))
            except:
                return None

        # crop
        img_a = img_a[ns.crop[0]:-ns.crop[1] - 1, ns.crop[2]:-ns.crop[3] - 1]
        img_b = img_b[ns.crop[0]:-ns.crop[1] - 1, ns.crop[2]:-ns.crop[3] - 1]

        u0, v0, sig2noise = pyprocess.extended_search_area_piv(
            img_a.astype(np.int32),
            img_b.astype(np.int32),
            window_size=ns.winsize,
            overlap=ns.overlap,
            dt=ns.dt,
            search_area_size=ns.searchsize,
            sig2noise_method='peak2peak')

        x, y = pyprocess.get_coordinates(image_size=img_a.shape,
                                         search_area_size=ns.searchsize,
                                         overlap=ns.overlap)

        x, y, u0, v0 = scaling.uniform(
            x, y, u0, v0,
            scaling_factor=ns.pixel_density)  # no. pixel per distance

        u0, v0, mask = validation.global_val(
            u0, v0, (ns.u_lower_bound, ns.u_upper_bound),
            (ns.v_lower_bound, ns.v_upper_bound))

        u1, v1, mask = validation.sig2noise_val(u0,
                                                v0,
                                                sig2noise,
                                                threshold=1.01)

        u3, v3 = filters.replace_outliers(u1,
                                          v1,
                                          method='localmean',
                                          max_iter=500,
                                          kernel_size=3)

        #save in the simple ASCII table format
        tools.save(x, y, u3, v3, sig2noise, mask,
                   os.path.join(results_path, ns.text_export_name))

        if ns.image_check == True:
            fig, ax = plt.subplots(2, 1, figsize=(24, 12))
            ax[0].imshow(img_a)
            ax[1].imshow(img_b)

        io.imwrite(os.path.join(results_path, ns.figure_export_name), img_a)

        if ns.show_result == True:
            fig, ax = plt.subplots(figsize=(24, 12))
            tools.display_vector_field(
                os.path.join(results_path, ns.text_export_name),
                ax=ax,
                scaling_factor=ns.pixel_density,
                scale=ns.scale_factor,  # scale defines here the arrow length
                width=ns.arrow_width,  # width is the thickness of the arrow
                on_img=True,  # overlay on the image
                image_name=os.path.join(results_path, ns.figure_export_name))
            fig.savefig(os.path.join(results_path, ns.figure_export_name))

        if ns.show_vertical_profiles:
            field_shape = pyprocess.get_field_shape(
                image_size=img_a.shape,
                search_area_size=ns.searchsize,
                overlap=ns.overlap)
            vertical_profiles(ns.text_export_name, field_shape)

        print('Mean of u: %.3f' % np.mean(u3))
        print('Std of u: %.3f' % np.std(u3))
        print('Mean of v: %.3f' % np.mean(v3))
        print('Std of v: %.3f' % np.std(v3))

        output = np.array([np.mean(u3), np.std(u3), np.mean(v3), np.std(v3)])
        # if np.absolute(np.mean(v3)) < 50:
        #     output = self.quick_piv(search_dict,index_a = index_a + 1, index_b = index_b + 1)

        return x, y, u3, v3
Ejemplo n.º 5
0
def multipass_img_deform(
    frame_a,
    frame_b,
    current_iteration,
    x_old,
    y_old,
    u_old,
    v_old,
    settings,
    mask_coords=[],
):
    # window_size,
    # overlap,
    # iterations,
    # current_iteration,
    # x_old,
    # y_old,
    # u_old,
    # v_old,
    # correlation_method="circular",
    # normalized_correlation=False,
    # subpixel_method="gaussian",
    # deformation_method="symmetric",
    # sig2noise_method="peak2peak",
    # sig2noise_threshold=1.0,
    # sig2noise_mask=2,
    # interpolation_order=1,
    """
    Multi pass of the PIV evaluation.

    This function does the PIV evaluation of the second and other passes.
    It returns the coordinates of the interrogation window centres,
    the displacement u, v for each interrogation window as well as
    the signal to noise ratio array (which is full of NaNs if opted out)


    Parameters
    ----------
    frame_a : 2d np.ndarray
        the first image

    frame_b : 2d np.ndarray
        the second image

    window_size : tuple of ints
         the size of the interrogation window

    overlap : tuple of ints
        the overlap of the interrogation window, e.g. window_size/2

    x_old : 2d np.ndarray
        the x coordinates of the vector field of the previous pass

    y_old : 2d np.ndarray
        the y coordinates of the vector field of the previous pass

    u_old : 2d np.ndarray
        the u displacement of the vector field of the previous pass
        in case of the image mask - u_old and v_old are MaskedArrays

    v_old : 2d np.ndarray
        the v displacement of the vector field of the previous pass

    subpixel_method: string
        the method used for the subpixel interpolation.
        one of the following methods to estimate subpixel location of the peak:
        'centroid' [replaces default if correlation map is negative],
        'gaussian' [default if correlation map is positive],
        'parabolic'

    interpolation_order : int
        the order of the spline interpolation used for the image deformation

    mask_coords : list of x,y coordinates (pixels) of the image mask,
        default is an empty list

    Returns
    -------
    x : 2d np.array
        array containg the x coordinates of the interrogation window centres

    y : 2d np.array
        array containg the y coordinates of the interrogation window centres

    u : 2d np.array
        array containing the horizontal displacement for every interrogation
        window [pixels]

    u : 2d np.array
        array containing the vertical displacement for every interrogation
        window it returns values in [pixels]

    s2n : 2D np.array of signal to noise ratio values

    """

    if not isinstance(u_old, np.ma.MaskedArray):
        raise ValueError('Expected masked array')

    # calculate the y and y coordinates of the interrogation window centres.
    # Hence, the
    # edges must be extracted to provide the sufficient input. x_old and y_old
    # are the coordinates of the old grid. x_int and y_int are the coordinates
    # of the new grid

    window_size = settings.windowsizes[current_iteration]
    overlap = settings.overlap[current_iteration]

    x, y = get_coordinates(frame_a.shape, window_size, overlap)

    # The interpolation function dont like meshgrids as input.
    # plus the coordinate system for y is now from top to bottom
    # and RectBivariateSpline wants an increasing set

    y_old = y_old[:, 0]
    # y_old = y_old[::-1]
    x_old = x_old[0, :]

    y_int = y[:, 0]
    # y_int = y_int[::-1]
    x_int = x[0, :]

    # interpolating the displacements from the old grid onto the new grid
    # y befor x because of numpy works row major
    ip = RectBivariateSpline(y_old, x_old, u_old.filled(0.))
    u_pre = ip(y_int, x_int)

    ip2 = RectBivariateSpline(y_old, x_old, v_old.filled(0.))
    v_pre = ip2(y_int, x_int)

    # if settings.show_plot:
    if settings.show_all_plots:
        plt.figure()
        plt.quiver(x_old, y_old, u_old, -1 * v_old, color='b')
        plt.quiver(x_int, y_int, u_pre, -1 * v_pre, color='r', lw=2)
        plt.gca().set_aspect(1.)
        plt.gca().invert_yaxis()
        plt.title('inside deform, invert')
        plt.show()

    # @TKauefer added another method to the windowdeformation, 'symmetric'
    # splits the onto both frames, takes more effort due to additional
    # interpolation however should deliver better results

    old_frame_a = frame_a.copy()
    old_frame_b = frame_b.copy()

    # Image deformation has to occur in image coordinates
    # therefore we need to convert the results of the
    # previous pass which are stored in the physical units
    # and so y from the get_coordinates

    if settings.deformation_method == "symmetric":
        # this one is doing the image deformation (see above)
        x_new, y_new, ut, vt = create_deformation_field(
            frame_a, x, y, u_pre, v_pre)
        frame_a = scn.map_coordinates(frame_a,
                                      ((y_new - vt / 2, x_new - ut / 2)),
                                      order=settings.interpolation_order,
                                      mode='nearest')
        frame_b = scn.map_coordinates(frame_b,
                                      ((y_new + vt / 2, x_new + ut / 2)),
                                      order=settings.interpolation_order,
                                      mode='nearest')
    elif settings.deformation_method == "second image":
        frame_b = deform_windows(
            frame_b,
            x,
            y,
            u_pre,
            -v_pre,
            interpolation_order=settings.interpolation_order)
    else:
        raise Exception("Deformation method is not valid.")

    # if settings.show_plot:
    if settings.show_all_plots:
        if settings.deformation_method == 'symmetric':
            plt.figure()
            plt.imshow(frame_a - old_frame_a)
            plt.show()

        plt.figure()
        plt.imshow(frame_b - old_frame_b)
        plt.show()

    # if do_sig2noise is True
    #     sig2noise_method = sig2noise_method
    # else:
    #     sig2noise_method = None

    # so we use here default circular not normalized correlation:
    # if we did not want to validate every step, remove the method
    if settings.sig2noise_validate is False:
        settings.sig2noise_method = None

    u, v, s2n = extended_search_area_piv(
        frame_a,
        frame_b,
        window_size=window_size,
        overlap=overlap,
        width=settings.sig2noise_mask,
        subpixel_method=settings.subpixel_method,
        sig2noise_method=settings.sig2noise_method,
        correlation_method=settings.correlation_method,
        normalized_correlation=settings.normalized_correlation,
    )

    shapes = np.array(get_field_shape(frame_a.shape, window_size, overlap))
    u = u.reshape(shapes)
    v = v.reshape(shapes)
    s2n = s2n.reshape(shapes)

    u += u_pre
    v += v_pre

    # reapply the image mask to the new grid
    if settings.image_mask:
        grid_mask = preprocess.prepare_mask_on_grid(x, y, mask_coords)
        u = np.ma.masked_array(u, mask=grid_mask)
        v = np.ma.masked_array(v, mask=grid_mask)
    else:
        u = np.ma.masked_array(u, np.ma.nomask)
        v = np.ma.masked_array(v, np.ma.nomask)

    # validate in the multi-pass by default
    u, v, mask = validation.typical_validation(u, v, s2n, settings)

    if np.all(mask):
        raise ValueError("Something happened in the validation")

    if not isinstance(u, np.ma.MaskedArray):
        raise ValueError('not a masked array anymore')

    if settings.show_all_plots:
        plt.figure()
        nans = np.nonzero(mask)

        plt.quiver(x[~nans], y[~nans], u[~nans], -v[~nans], color='b')
        plt.quiver(x[nans], y[nans], u[nans], -v[nans], color='r')
        plt.gca().invert_yaxis()
        plt.gca().set_aspect(1.)
        plt.title('After sig2noise, inverted')
        plt.show()

    # we have to replace outliers
    u, v = filters.replace_outliers(
        u,
        v,
        method=settings.filter_method,
        max_iter=settings.max_filter_iteration,
        kernel_size=settings.filter_kernel_size,
    )

    # reapply the image mask to the new grid
    if settings.image_mask:
        grid_mask = preprocess.prepare_mask_on_grid(x, y, mask_coords)
        u = np.ma.masked_array(u, mask=grid_mask)
        v = np.ma.masked_array(v, mask=grid_mask)
    else:
        u = np.ma.masked_array(u, np.ma.nomask)
        v = np.ma.masked_array(v, np.ma.nomask)

    if settings.show_all_plots:
        plt.figure()
        plt.quiver(x, y, u, -v, color='r')
        plt.quiver(x, y, u_pre, -1 * v_pre, color='b')
        plt.gca().invert_yaxis()
        plt.gca().set_aspect(1.)
        plt.title(' after replaced outliers, red, invert')
        plt.show()

    return x, y, u, v, s2n, mask
Ejemplo n.º 6
0
def first_pass(frame_a, frame_b, settings):
    # window_size,
    # overlap,
    # iterations,
    # correlation_method="circular",
    # normalized_correlation=False,
    # subpixel_method="gaussian",
    # do_sig2noise=False,
    # sig2noise_method="peak2peak",
    # sig2noise_mask=2,
    # settings):
    """
    First pass of the PIV evaluation.

    This function does the PIV evaluation of the first pass. It returns
    the coordinates of the interrogation window centres, the displacment
    u and v for each interrogation window as well as the mask which indicates
    wether the displacement vector was interpolated or not.


    Parameters
    ----------
    frame_a : 2d np.ndarray
        the first image

    frame_b : 2d np.ndarray
        the second image

    window_size : int
         the size of the interrogation window

    overlap : int
        the overlap of the interrogation window, typically it is window_size/2

    subpixel_method: string
        the method used for the subpixel interpolation.
        one of the following methods to estimate subpixel location of the peak:
        'centroid' [replaces default if correlation map is negative],
        'gaussian' [default if correlation map is positive],
        'parabolic'

    Returns
    -------
    x : 2d np.array
        array containg the x coordinates of the interrogation window centres

    y : 2d np.array
        array containg the y coordinates of the interrogation window centres

    u : 2d np.array
        array containing the u displacement for every interrogation window

    u : 2d np.array
        array containing the u displacement for every interrogation window

    """

    #     if do_sig2noise is False or iterations != 1:
    #         sig2noise_method = None  # this indicates to get out nans

    u, v, s2n = extended_search_area_piv(
        frame_a,
        frame_b,
        window_size=settings.windowsizes[0],
        overlap=settings.overlap[0],
        search_area_size=settings.windowsizes[0],
        width=settings.sig2noise_mask,
        subpixel_method=settings.subpixel_method,
        sig2noise_method=settings.sig2noise_method,
        correlation_method=settings.correlation_method,
        normalized_correlation=settings.normalized_correlation)

    shapes = np.array(
        get_field_shape(frame_a.shape, settings.windowsizes[0],
                        settings.overlap[0]))
    u = u.reshape(shapes)
    v = v.reshape(shapes)
    s2n = s2n.reshape(shapes)

    x, y = get_coordinates(frame_a.shape, settings.windowsizes[0],
                           settings.overlap[0])

    return x, y, u, v, s2n
Ejemplo n.º 7
0
def multipass_img_deform(frame_a,
                         frame_b,
                         window_size,
                         overlap,
                         iterations,
                         current_iteration,
                         x_old,
                         y_old,
                         u_old,
                         v_old,
                         correlation_method='circular',
                         subpixel_method='gaussian',
                         do_sig2noise=False,
                         sig2noise_method='peak2peak',
                         sig2noise_mask=2,
                         MinMaxU=(-100, 50),
                         MinMaxV=(-50, 50),
                         std_threshold=5,
                         median_threshold=2,
                         median_size=1,
                         filter_method='localmean',
                         max_filter_iteration=10,
                         filter_kernel_size=2,
                         interpolation_order=3):
    """
    First pass of the PIV evaluation.

    This function does the PIV evaluation of the first pass. It returns
    the coordinates of the interrogation window centres, the displacment
    u and v for each interrogation window as well as the mask which indicates
    wether the displacement vector was interpolated or not.


    Parameters
    ----------
    frame_a : 2d np.ndarray
        the first image

    frame_b : 2d np.ndarray
        the second image

    window_size : tuple of ints
         the size of the interrogation window

    overlap : tuple of ints
        the overlap of the interrogation window normal for example window_size/2

    x_old : 2d np.ndarray
        the x coordinates of the vector field of the previous pass

    y_old : 2d np.ndarray
        the y coordinates of the vector field of the previous pass

    u_old : 2d np.ndarray
        the u displacement of the vector field of the previous pass

    v_old : 2d np.ndarray
        the v displacement of the vector field of the previous pass

    subpixel_method: string
        the method used for the subpixel interpolation.
        one of the following methods to estimate subpixel location of the peak:
        'centroid' [replaces default if correlation map is negative],
        'gaussian' [default if correlation map is positive],
        'parabolic'

    MinMaxU : two elements tuple
        sets the limits of the u displacment component
        Used for validation.

    MinMaxV : two elements tuple
        sets the limits of the v displacment component
        Used for validation.

    std_threshold : float
        sets the  threshold for the std validation

    median_threshold : float
        sets the threshold for the median validation

    filter_method : string
        the method used to replace the non-valid vectors
        Methods:
            'localmean',
            'disk',
            'distance', 

    max_filter_iteration : int
        maximum of filter iterations to replace nans

    filter_kernel_size : int
        size of the kernel used for the filtering

    interpolation_order : int
        the order of the spline interpolation used for the image deformation

    Returns
    -------
    x : 2d np.array
        array containg the x coordinates of the interrogation window centres

    y : 2d np.array
        array containg the y coordinates of the interrogation window centres 

    u : 2d np.array
        array containing the u displacement for every interrogation window

    u : 2d np.array
        array containing the u displacement for every interrogation window

    mask : 2d np.array
        array containg the mask values (bool) which contains information if
        the vector was filtered

    """

    x, y = get_coordinates(np.shape(frame_a), window_size, overlap)
    'calculate the y and y coordinates of the interrogation window centres'
    y_old = y_old[:, 0]
    # y_old = y_old[::-1]
    x_old = x_old[0, :]
    y_int = y[:, 0]
    # y_int = y_int[::-1]
    x_int = x[0, :]
    '''The interpolation function dont like meshgrids as input. Hence, the the edges
    must be extracted to provide the sufficient input. x_old and y_old are the 
    are the coordinates of the old grid. x_int and y_int are the coordiantes
    of the new grid'''

    ip = RectBivariateSpline(y_old, x_old, u_old)
    u_pre = ip(y_int, x_int)
    ip2 = RectBivariateSpline(y_old, x_old, v_old)
    v_pre = ip2(y_int, x_int)
    ''' interpolating the displacements from the old grid onto the new grid
    y befor x because of numpy works row major
    '''

    frame_b_deform = frame_interpolation(
        frame_b, x, y, u_pre, -v_pre, interpolation_order=interpolation_order)
    '''this one is doing the image deformation (see above)'''

    cor_win_1 = pyprocess.moving_window_array(frame_a, window_size, overlap)
    cor_win_2 = pyprocess.moving_window_array(frame_b_deform, window_size,
                                              overlap)
    '''Filling the interrogation window. They windows are arranged
    in a 3d array with number of interrogation window *window_size*window_size
    this way is much faster then using a loop'''

    correlation = correlation_func(cor_win_1,
                                   cor_win_2,
                                   correlation_method=correlation_method,
                                   normalized_correlation=False)
    'do the correlation'
    disp = np.zeros((np.size(correlation, 0), 2))
    for i in range(0, np.size(correlation, 0)):
        ''' determine the displacment on subpixel level  '''
        disp[i, :] = find_subpixel_peak_position(
            correlation[i, :, :], subpixel_method=subpixel_method)
    'this loop is doing the displacment evaluation for each window '
    disp = np.array(disp) - np.floor(np.array(correlation[0, :, :].shape) / 2)

    'reshaping the interrogation window to vector field shape'
    shapes = np.array(
        pyprocess.get_field_shape(np.shape(frame_a), window_size, overlap))
    u = disp[:, 1].reshape(shapes)
    v = -disp[:, 0].reshape(shapes)

    'adding the recent displacment on to the displacment of the previous pass'
    u = u + u_pre
    v = v + v_pre
    'validation using gloabl limits and local median'
    u, v, mask_g = validation.global_val(u, v, MinMaxU, MinMaxV)
    u, v, mask_s = validation.global_std(u, v, std_threshold=std_threshold)
    u, v, mask_m = validation.local_median_val(u,
                                               v,
                                               u_threshold=median_threshold,
                                               v_threshold=median_threshold,
                                               size=median_size)
    mask = mask_g + mask_m + mask_s
    'adding masks to add the effect of alle the validations'
    #mask=np.zeros_like(u)
    'filter to replace the values that where marked by the validation'
    if current_iteration != iterations:
        'filter to replace the values that where marked by the validation'
        u, v = filters.replace_outliers(u,
                                        v,
                                        method=filter_method,
                                        max_iter=max_filter_iteration,
                                        kernel_size=filter_kernel_size)
    if do_sig2noise == True and current_iteration == iterations and iterations != 1:
        sig2noise_ratio = sig2noise_ratio_function(
            correlation,
            sig2noise_method=sig2noise_method,
            width=sig2noise_mask)
        sig2noise_ratio = sig2noise_ratio.reshape(shapes)
    else:
        sig2noise_ratio = np.full_like(u, np.nan)

    return x, y, u, v, sig2noise_ratio, mask
Ejemplo n.º 8
0
def first_pass(frame_a,
               frame_b,
               window_size,
               overlap,
               iterations,
               correlation_method='circular',
               subpixel_method='gaussian',
               do_sig2noise=False,
               sig2noise_method='peak2peak',
               sig2noise_mask=2):
    """
    First pass of the PIV evaluation.

    This function does the PIV evaluation of the first pass. It returns
    the coordinates of the interrogation window centres, the displacment
    u and v for each interrogation window as well as the mask which indicates
    wether the displacement vector was interpolated or not.


    Parameters
    ----------
    frame_a : 2d np.ndarray
        the first image

    frame_b : 2d np.ndarray
        the second image

    window_size : int
         the size of the interrogation window

    overlap : int
        the overlap of the interrogation window normal for example window_size/2

    subpixel_method: string
        the method used for the subpixel interpolation.
        one of the following methods to estimate subpixel location of the peak:
        'centroid' [replaces default if correlation map is negative],
        'gaussian' [default if correlation map is positive],
        'parabolic'

    Returns
    -------
    x : 2d np.array
        array containg the x coordinates of the interrogation window centres

    y : 2d np.array
        array containg the y coordinates of the interrogation window centres 

    u : 2d np.array
        array containing the u displacement for every interrogation window

    u : 2d np.array
        array containing the u displacement for every interrogation window

    """

    cor_win_1 = pyprocess.moving_window_array(frame_a, window_size, overlap)
    cor_win_2 = pyprocess.moving_window_array(frame_b, window_size, overlap)
    '''Filling the interrogation window. They windows are arranged
    in a 3d array with number of interrogation window *window_size*window_size
    this way is much faster then using a loop'''

    correlation = correlation_func(cor_win_1,
                                   cor_win_2,
                                   correlation_method=correlation_method,
                                   normalized_correlation=False)
    'do the correlation'
    disp = np.zeros((np.size(correlation,
                             0), 2))  #create a dummy for the loop to fill
    for i in range(0, np.size(correlation, 0)):
        ''' determine the displacment on subpixel level '''
        disp[i, :] = find_subpixel_peak_position(
            correlation[i, :, :], subpixel_method=subpixel_method)
    'this loop is doing the displacment evaluation for each window '

    disp = np.array(disp) - np.floor(np.array(correlation[0, :, :].shape) / 2)

    shapes = np.array(
        pyprocess.get_field_shape(frame_a.shape, window_size, overlap))
    u = disp[:, 1].reshape(shapes)
    v = -disp[:, 0].reshape(shapes)
    'reshaping the interrogation window to vector field shape'

    x, y = get_coordinates(frame_a.shape, window_size, overlap)
    'get coordinates for to map the displacement'
    if do_sig2noise == True and iterations == 1:
        sig2noise_ratio = sig2noise_ratio_function(
            correlation,
            sig2noise_method=sig2noise_method,
            width=sig2noise_mask)
        sig2noise_ratio = sig2noise_ratio.reshape(shapes)
    else:
        sig2noise_ratio = np.full_like(u, np.nan)
    return x, y, u, v, sig2noise_ratio
Ejemplo n.º 9
0
def extended_search_area_piv3D(
    frame_a,
    frame_b,
    window_size,
    overlap=(0, 0, 0),
    dt=(1.0, 1.0, 1.0),
    search_area_size=None,
    correlation_method="fft",
    subpixel_method="gaussian",
    sig2noise_method=None,
    width=2,
    nfftx=None,
    nffty=None,
    nfftz=None,
):
    """Standard PIV cross-correlation algorithm, with an option for
    extended area search that increased dynamic range. The search region
    in the second frame is larger than the interrogation window size in the
    first frame.

    This is a pure python implementation of the standard PIV cross-correlation
    algorithm. It is a zero order displacement predictor, and no iterative
    process is performed.

    Parameters
    ----------
    frame_a : 3d np.ndarray
        an two dimensions array of integers containing grey levels of
        the first frame.

    frame_b : 3d np.ndarray
        an two dimensions array of integers containing grey levels of
        the second frame.

    window_size : tuple
        the size of the (square) interrogation window, [default: 32 pix].

    overlap : tuple
        the number of pixels by which two adjacent windows overlap
        [default: 16 pix].

    dt : tuple
        the time delay separating the two frames [default: 1.0].

    correlation_method : string
        only one method is currently implemented: 'fft'

    subpixel_method : string
         one of the following methods to estimate subpixel location of the peak:
         'centroid' [replaces default if correlation map is negative],
         'gaussian' [default if correlation map is positive],
         'parabolic'.

    sig2noise_method : string
        defines the method of signal-to-noise-ratio measure,
        ('peak2peak' or 'peak2mean'. If None, no measure is performed.)

    nfftx   : int
        the size of the 3D FFT in x-direction,
        [default: 2 x windows_a.shape[0] is recommended]

    nffty   : int
        the size of the 3D FFT in y-direction,
        [default: 2 x windows_a.shape[1] is recommended]

    nfftz   : int
        the size of the 3D FFT in z-direction,
        [default: 2 x windows_a.shape[2] is recommended]

    width : int
        the half size of the region around the first
        correlation peak to ignore for finding the second
        peak. [default: 2]. Only used if ``sig2noise_method==peak2peak``.

    search_area_size :  tuple
       the size of the interrogation window in the second frame,
       default is the same interrogation window size and it is a
       fallback to the simplest FFT based PIV


    Returns
    -------
    u : 3d np.ndarray
        a three dimensional array containing the u velocity component,
        in pixels/seconds.

    v : 3d np.ndarray
        a three dimensional array containing the v velocity component,
        in pixels/seconds.

    w : 3d np.ndarray
        a three dimensional array containing the w velocity component,
        in pixels/seconds.

    sig2noise : 3d np.ndarray, (optional: only if sig2noise_method is not None)
        a three dimensional array the signal to noise ratio for each
        window pair.

    """

    # checking if the input is correct
    window_size, overlap, search_area_size = check_input(
        window_size, overlap, search_area_size, frame_a, frame_b)

    # get field shape
    field_shape = get_field_shape(frame_a.shape, search_area_size, overlap)

    u = np.zeros(field_shape)
    v = np.zeros(field_shape)
    w = np.zeros(field_shape)

    # if we want sig2noise information, allocate memory
    if sig2noise_method is not None:
        sig2noise = np.zeros(field_shape)

    # shift for x and y coordinates of the search area windows so that the centers of search area windows have
    # the same distances to the image edge at all sides. For simplicity only shifts by integers are allowed
    x_centering = (frame_a.shape[1] - 1 -
                   ((field_shape[1] - 1) * (window_size[1] - overlap[1]) +
                    (search_area_size[1] - 1))) // 2
    y_centering = (frame_a.shape[0] - 1 -
                   ((field_shape[0] - 1) * (window_size[0] - overlap[0]) +
                    (search_area_size[0] - 1))) // 2
    z_centering = (frame_a.shape[2] - 1 -
                   ((field_shape[2] - 1) * (window_size[2] - overlap[2]) +
                    (search_area_size[2] - 1))) // 2

    # loop over the interrogation windows
    # i, j are the row, column indices of the center of each interrogation
    # window
    for k in tqdm(range(field_shape[0])):
        for m in range(field_shape[1]):
            for l in range(field_shape[2]):

                # centers of search area. (window_size - overlap) defines the distance between each center
                # and (search_area_size - 1)/2.0 moves the center points away from the left or top image edge
                y = k * (window_size[0] - overlap[0]) + (search_area_size[0] -
                                                         1) / 2.0
                x = m * (window_size[1] - overlap[1]) + (search_area_size[1] -
                                                         1) / 2.0
                z = l * (window_size[2] - overlap[2]) + (search_area_size[2] -
                                                         1) / 2.0

                # moving the coordinates a bit to the center, to guarantee that the distance of a extreme
                # point at the image edges is symmetric all all edges
                x += x_centering
                y += y_centering
                z += z_centering

                # left, right, top, bottom, front, back indices of the search area edges
                # note that x - (search_area_size +/- 1)/2  always returns an integer due to the definition of x and y
                # see also "get_coordinates()"
                il = int(y - (search_area_size[0] - 1) / 2.0)
                ir = int(y + (search_area_size[0] + 1) / 2.0)
                it = int(x - (search_area_size[1] - 1) / 2.0)
                ib = int(x + (search_area_size[1] + 1) / 2.0)
                ifr = int(z - (search_area_size[2] - 1) / 2.0)
                iba = int(z + (search_area_size[2] + 1) / 2.0)
                # picking the search area from frame b
                window_b = frame_b[il:ir, it:ib, ifr:iba]

                # left, right, top, bottom, front, back indices of the interrogation window
                # Sometimes the interrogation window cannot be placed in the middle of the search area, e.g.
                # in the case of window_size=3 search_area_size=4. In this case the interrogation window
                # is shifted 0.5 pixels to the left/top, which is achieved by rounding the indices
                #  down during the int() conversion
                il = int(y - (window_size[0] - 1) / 2)
                ir = int(y + (window_size[0] + 1) / 2)
                it = int(x - (window_size[1] - 1) / 2)
                ib = int(x + (window_size[1] + 1) / 2)
                ifr = int(z - (window_size[2] - 1) / 2)
                iba = int(z + (window_size[2] + 1) / 2)
                # picking the interrogation window from frame a
                window_a = frame_a[il:ir, it:ib, ifr:iba]

                if np.any(window_a):
                    corr = correlate_windows(
                        window_a,
                        window_b,
                        correlation_method=correlation_method,
                        nfftx=nfftx,
                        nffty=nffty,
                        nfftz=nfftz,
                    )

                    # get subpixel approximation for peak position row and column index
                    row, col, z = find_subpixel_peak_position(
                        corr, subpixel_method=subpixel_method)

                    row -= (search_area_size[0] + window_size[0] - 1) // 2
                    col -= (search_area_size[1] + window_size[1] - 1) // 2
                    z -= (search_area_size[2] + window_size[2] - 1) // 2

                    # get displacements, apply coordinate system definition
                    u[k, m, l], v[k, m, l], w[k, m, l] = col, -row, -z

                    # get signal to noise ratio
                    if sig2noise_method is not None:
                        sig2noise[k, m, l] = sig2noise_ratio(
                            corr,
                            sig2noise_method=sig2noise_method,
                            width=width)

    # return output if user wanted sig2noise information
    if sig2noise_method is not None:
        return u / dt[0], v / dt[1], w / dt[2], sig2noise
    else:
        return u / dt[0], v / dt[1], w / dt[2]