Ejemplo n.º 1
0
    def test_xform_sinusoid_params_roi(self):
        """
        Test function xform_sinusoid_params_roi() by constructing sinusoid pattern and passing through an affine
        transformation. Compare the resulting frequency determined numerically with the resulting frequency determined
        from the initial frequency + affine parameters
        :return:
        """
        # define object space parameters
        # roi_img = [0, 2048, 0, 2048]
        roi_img = [512, 788, 390, 871]

        fobj = np.array([0.08333333, 0.08333333])
        phase_obj = 5.497787143782089
        fn = lambda x, y: 1 + np.cos(2 * np.pi * (fobj[0] * x + fobj[1] * y) + phase_obj)

        # define affine transform
        xform = affine.params2xform([1.4296003114502853, 2.3693263411981396, 2671.39109,
                                     1.4270495211450602, 2.3144621088632635, 790.402632])

        # sinusoid parameter transformation
        fxi, fyi, phase_roi = affine.xform_sinusoid_params_roi(fobj[0], fobj[1], phase_obj, None, roi_img, xform,
                                                               input_origin="edge", output_origin="edge")
        fimg = np.array([fxi, fyi])

        # FFT phase
        _, _, phase_roi_ft = affine.xform_sinusoid_params_roi(fobj[0], fobj[1], phase_obj, None, roi_img, xform,
                                                              input_origin="edge", output_origin="fft")

        # compared with phase from fitting image directly
        out_coords = np.meshgrid(range(roi_img[2], roi_img[3]), range(roi_img[0], roi_img[1]))
        img = affine.xform_fn(fn, xform, out_coords)
        phase_fit_roi = float(sim.get_phase_realspace(img, fimg, 1, phase_guess=phase_roi, origin="edge"))

        # phase FFT
        ny, nx = img.shape
        window = scipy.signal.windows.hann(nx)[None, :] * scipy.signal.windows.hann(ny)[:, None]
        img_ft = fft.fftshift(fft.fft2(fft.ifftshift(img * window)))
        fx = tools.get_fft_frqs(nx, 1)
        fy = tools.get_fft_frqs(ny, 1)

        peak = tools.get_peak_value(img_ft, fx, fy, fimg, 2)
        phase_fit_roi_ft = np.mod(np.angle(peak), 2*np.pi)

        # accuracy is limited by frequency fitting routine...
        self.assertAlmostEqual(phase_roi, phase_fit_roi, 1)
        # probably limited by peak height finding routine
        self.assertAlmostEqual(phase_roi_ft, phase_fit_roi_ft, 3)
Ejemplo n.º 2
0
    def test_pattern_main_phase_vs_phase_index(self):
        """
        Test get_sim_phase() on the main frequency component for one SIM pattern. Ensure works for all phase indices.

        Tests only a single pattern vector
        :return:
        """
        nx = 1920
        ny = 1080
        nphases = 3

        fx = tools.get_fft_frqs(nx)
        fy = tools.get_fft_frqs(ny)
        window = scipy.signal.windows.hann(nx)[
            None, :] * scipy.signal.windows.hann(ny)[:, None]

        va = [-3, 11]
        vb = [3, 12]
        # va = [-1, 117]
        # vb = [-6, 117]
        rva, rvb = dmd.get_reciprocal_vects(va, vb)

        for jj in range(nphases):
            phase = dmd.get_sim_phase(va,
                                      vb,
                                      nphases,
                                      jj, [nx, ny],
                                      origin="fft")
            pattern, _ = dmd.get_sim_pattern([nx, ny], va, vb, nphases, jj)
            pattern_ft = fft.fftshift(fft.fft2(fft.ifftshift(pattern *
                                                             window)))

            pattern_phase_est = np.mod(
                np.angle(tools.get_peak_value(pattern_ft, fx, fy, rvb, 2)),
                2 * np.pi)

            # assert np.round(np.abs(pattern_phase_est - float(phase)), 3) == 0
            self.assertAlmostEqual(pattern_phase_est, float(phase), 3)
Ejemplo n.º 3
0
def get_all_fourier_exp(imgs,
                        frq_vects_theory,
                        roi,
                        pixel_size_um,
                        fmax_img,
                        to_use=None,
                        use_guess_frqs=True,
                        max_frq_shift_pix=1.5,
                        force_start_from_guess=True,
                        peak_pix=2,
                        bg=100):
    """
    Calculate Fourier components from a set of images.

    :param imgs: nimgs x ny x nx
    :param vects: nimgs x nvecs1 x nvecs2 x 2
    :param float pixel_size_um:
    :param bool use_guess_frqs: if True, use guess frequencies computed from frq_vects_theory, if False use fitting
    procedure to find peak
    :param int peak_pix: number of pixels to use when calculating peak. Typically 2.
    :param float bg:

    :return intensity:
    :return intensity_unc:
    :return frq_vects_expt:
    """
    if to_use is None:
        to_use = np.ones(frq_vects_theory[:, :, :, 0].shape, dtype=np.int)

    nimgs = frq_vects_theory.shape[0]
    n1_vecs = frq_vects_theory.shape[1]
    n2_vecs = frq_vects_theory.shape[2]

    intensity = np.zeros(frq_vects_theory.shape[:-1],
                         dtype=np.complex) * np.nan
    intensity_unc = np.zeros(intensity.shape) * np.nan

    # apodization, 2D window from broadcasting
    nx_roi = roi[3] - roi[2]
    ny_roi = roi[1] - roi[0]
    window = scipy.signal.windows.hann(nx_roi)[
        None, :] * scipy.signal.windows.hann(ny_roi)[:, None]

    # generate frequency data for image FT's
    fxs = tools.get_fft_frqs(nx_roi, pixel_size_um)
    dfx = fxs[1] - fxs[0]
    fys = tools.get_fft_frqs(ny_roi, pixel_size_um)
    dfy = fys[1] - fys[0]

    if imgs.shape[0] == nimgs:
        multiple_images = True
    elif imgs.shape[0] == 1:
        multiple_images = False
        icrop = imgs[0, roi[0]:roi[1], roi[2]:roi[3]]

        img = icrop - bg
        img[img < 0] = 1e-6

        img_ft = fft.fftshift(fft.fft2(fft.ifftshift(img * window)))
        noise_power = sim_reconstruction.get_noise_power(
            img_ft, fxs, fys, fmax_img)
    else:
        raise Exception()

    frq_vects_expt = np.zeros(frq_vects_theory.shape)
    tstart = time.process_time()
    for ii in range(nimgs):
        tnow = time.process_time()
        print("%d/%d, %d peaks, elapsed time = %0.2fs" %
              (ii + 1, nimgs, np.sum(to_use[ii]), tnow - tstart))

        if multiple_images:
            # subtract background and crop to ROI
            # img = img[0, roi[0]:roi[1], roi[2]:roi[3]] - bg
            # img[img < 0] = 1e-6
            icrop = imgs[ii, roi[0]:roi[1], roi[2]:roi[3]]
            img = icrop - bg
            img[img < 0] = 1e-6

            # fft
            img_ft = fft.fftshift(fft.fft2(fft.ifftshift(img * window)))
            # get noise
            noise_power = sim_reconstruction.get_noise_power(
                img_ft, fxs, fys, fmax_img)

        # minimimum separation between reciprocal lattice vectors
        vnorms = np.linalg.norm(frq_vects_theory[ii], axis=2)
        min_sep = np.min(vnorms[vnorms > 0])

        # get experimental weights of fourier components
        for aa in range(n1_vecs):
            for bb in range(n2_vecs):

                frq_vects_expt[ii, aa, bb] = frq_vects_theory[ii, aa, bb]

                # only do fitting if peak size exceeds tolerance, and only fit one of a peak and its compliment
                if not to_use[ii, aa, bb]:
                    continue

                max_frq_shift = np.min([
                    max_frq_shift_pix * dfx, 0.5 * vnorms[aa, bb],
                    0.5 * min_sep
                ])

                # get experimental frequency
                if (max_frq_shift /
                        dfx) < 1 or use_guess_frqs or np.linalg.norm(
                            frq_vects_expt[ii, aa, bb]) == 0:
                    # if can't get large enough ROI, then use our guess
                    pass
                else:
                    # fit real fourier component in image space
                    # only need wavelength and na to get fmax
                    frq_vects_expt[
                        ii, aa,
                        bb], mask = sim_reconstruction.fit_modulation_frq(
                            img_ft,
                            img_ft,
                            pixel_size_um,
                            fmax_img,
                            frq_guess=frq_vects_theory[ii, aa, bb],
                            max_frq_shift=max_frq_shift,
                            force_start_from_guess=force_start_from_guess)

                    sim_reconstruction.plot_correlation_fit(
                        img_ft,
                        img_ft,
                        frq_vects_expt[ii, aa, bb],
                        pixel_size_um,
                        fmax_img,
                        frqs_guess=frq_vects_theory[ii, aa, bb],
                        roi_size=3)

                try:
                    # get peak value and phase
                    intensity[ii, aa, bb] = tools.get_peak_value(
                        img_ft,
                        fxs,
                        fys,
                        frq_vects_expt[ii, aa, bb],
                        peak_pixel_size=peak_pix)

                    intensity_unc[ii, aa,
                                  bb] = np.sqrt(noise_power) * peak_pix**2

                    # handle complimentary point with aa > bb
                    aa_neg = n1_vecs - 1 - aa
                    bb_neg = n2_vecs - 1 - bb
                    intensity[ii, aa_neg, bb_neg] = intensity[ii, aa,
                                                              bb].conj()
                    intensity_unc[ii, aa_neg, bb_neg] = intensity_unc[ii, aa,
                                                                      bb]

                except:
                    pass

    return intensity, intensity_unc, frq_vects_expt
Ejemplo n.º 4
0
    def test_patterns_main_phase(self):
        """
        Test determination of DMD pattern phase by comparing with FFT phase for dominant frequency component
        of given pattern.

        This compares get_sim_phase() with directly producing a pattern via get_sim_pattern() and numerically determining
        the phase.

        Unlike test_phase_vs_phase_index(), test many different lattice vectors, but only a single phase index
        :return:
        """

        # dmd_size = [1920, 1080]
        dmd_size = [192, 108]
        nphases = 3
        phase_index = 0
        nx, ny = dmd_size

        # va_comps = np.arange(-15, 15)
        # vb_comps = np.arange(-30, 30, 3)
        va_comps = np.array([-15, -7, -3, 0, 4, 8, 17])
        vb_comps = np.array([-30, -15, -6, -3, 12, 18])
        # va_comps = np.array([1, 3, 10])
        # vb_comps = np.array([-3, 0, 3])

        # generate all lattice vectors
        vas_x, vas_y = np.meshgrid(va_comps, va_comps)
        vas = np.concatenate((vas_x.ravel()[:, None], vas_y.ravel()[:, None]),
                             axis=1)
        vas = vas[np.linalg.norm(vas, axis=1) != 0]

        vbs_x, vbs_y = np.meshgrid(vb_comps, vb_comps)
        vbs = np.concatenate((vbs_x.ravel()[:, None], vbs_y.ravel()[:, None]),
                             axis=1)
        vbs = vbs[np.linalg.norm(vbs, axis=1) != 0]

        for ii in range(len(vas)):
            for jj in range(len(vbs)):
                print("pattern %d/%d" %
                      (len(vbs) * ii + jj + 1, len(vas) * len(vbs)))

                vec_a = vas[ii]
                vec_b = vbs[jj]

                try:
                    recp_va, recp_vb = dmd.get_reciprocal_vects(vec_a, vec_b)
                except:
                    continue

                # normal phase function
                phase = dmd.get_sim_phase(vec_a, vec_b, nphases, phase_index,
                                          dmd_size)

                # estimate phase from FFT
                pattern, _ = dmd.get_sim_pattern(dmd_size, vec_a, vec_b,
                                                 nphases, phase_index)

                window = scipy.signal.windows.hann(nx)[
                    None, :] * scipy.signal.windows.hann(ny)[:, None]
                pattern_ft = fft.fftshift(
                    fft.fft2(fft.ifftshift(pattern * window)))
                fx = tools.get_fft_frqs(nx, 1)
                fy = tools.get_fft_frqs(ny, 1)

                try:
                    phase_direct = np.angle(
                        tools.get_peak_value(pattern_ft,
                                             fx,
                                             fy,
                                             recp_vb,
                                             peak_pixel_size=2))
                except:
                    # recp_vb too close to edge of pattern
                    continue

                phase_diff = np.min([
                    np.abs(phase - phase_direct),
                    np.abs(phase - phase_direct - 2 * np.pi)
                ])

                # assert np.round(phase_diff, 1) == 0
                self.assertAlmostEqual(phase_diff, 0, 1)
Ejemplo n.º 5
0
    def test_affine_phase_xform(self):
        """
        Test transforming pattern and phases through affine xform


        :return:
        """

        # get pattern
        dmd_size = [1920, 1080]  #[nx, ny]
        nphases = 3
        phase_index = 0
        nmax = 40
        # roi = tools.get_centered_roi([1024, 1024], [600, 800])
        roi = tools.get_centered_roi([1024, 1024], [500, 500])
        nx = roi[3] - roi[2]
        ny = roi[1] - roi[0]

        # vec_a = np.array([8, 17])
        # vec_b = np.array([3, -6])
        vec_a = [1, -117]
        vec_b = [6, -117]

        pattern, _ = dmd.get_sim_pattern(dmd_size, vec_a, vec_b, nphases,
                                         phase_index)
        unit_cell, xc, yc = dmd.get_sim_unit_cell(vec_a, vec_b, nphases)

        # get affine matrix
        # affine_mat = affine.params2xform([2, 15 * np.pi/180, 15, 1.7, -13 * np.pi/180, 3])
        affine_mat = np.array(
            [[-1.01788979e+00, -1.04522661e+00, 2.66353915e+03],
             [9.92641451e-01, -9.58516962e-01, 7.83771959e+02],
             [0.00000000e+00, 0.00000000e+00, 1.00000000e+00]])
        # get affine matrix for our ROI
        affine_xform_roi = affine.xform_shift_center(affine_mat,
                                                     cimg_new=(roi[2], roi[0]))

        # get transformed phase from affine xform
        # transform pattern phase
        efields, ns, ms, vecs = dmd.get_efield_fourier_components(unit_cell,
                                                                  xc,
                                                                  yc,
                                                                  vec_a,
                                                                  vec_b,
                                                                  nphases,
                                                                  phase_index,
                                                                  dmd_size,
                                                                  nmax=nmax,
                                                                  origin="fft")
        efields = efields / np.max(np.abs(efields))

        vecs_xformed = np.zeros(vecs.shape)
        vecs_xformed[..., 0], vecs_xformed[
            ...,
            1], phases = affine.xform_sinusoid_params_roi(vecs[..., 0],
                                                          vecs[..., 1],
                                                          np.angle(efields),
                                                          pattern.shape,
                                                          roi,
                                                          affine_mat,
                                                          input_origin="fft",
                                                          output_origin="fft")
        efields_xformed = np.abs(efields) * np.exp(1j * phases)

        # get pattern phase directly from fft
        # transform pattern to image space
        img_coords = np.meshgrid(range(nx), range(ny))
        # interpolation preserves phases but can distort Fourier components
        pattern_xform = affine.affine_xform_mat(pattern,
                                                affine_xform_roi,
                                                img_coords,
                                                mode="interp")
        # taking nearest pixel does a better job with amplitudes, but can introduce fourier components that did not exist before
        # pattern_xform_nearest = affine.affine_xform_mat(pattern, affine_xform_roi, img_coords, mode="nearest")

        window = scipy.signal.windows.hann(nx)[
            None, :] * scipy.signal.windows.hann(ny)[:, None]
        pattern_ft = fft.fftshift(
            fft.fft2(fft.ifftshift(pattern_xform * window)))
        fx = tools.get_fft_frqs(nx, 1)
        fy = tools.get_fft_frqs(ny, 1)

        efields_direct = np.zeros(efields_xformed.shape, dtype=np.complex)
        for ii in range(efields.shape[0]):
            for jj in range(efields.shape[1]):
                if np.abs(vecs_xformed[ii, jj][0]) > 0.5 or np.abs(
                        vecs_xformed[ii, jj][1]) > 0.5:
                    efields_direct[ii, jj] = np.nan
                else:
                    try:
                        efields_direct[ii, jj] = tools.get_peak_value(
                            pattern_ft,
                            fx,
                            fy,
                            vecs_xformed[ii, jj],
                            peak_pixel_size=2)
                    except:
                        efields_direct[ii, jj] = np.nan

        efields_direct = efields_direct / np.nanmax(np.abs(efields_direct))

        to_compare = np.abs(efields_xformed) > 0.05
        # check phases
        self.assertTrue(
            np.max(
                np.abs(
                    np.angle(efields_xformed[to_compare]) -
                    np.angle(efields_direct[to_compare]))) < 0.003)

        # check amplitudes
        self.assertTrue(
            np.nanmax(
                np.abs(efields_xformed[to_compare] -
                       efields_direct[to_compare])) < 0.07)
        # check relative amplitudes
        self.assertTrue(
            np.nanmax(
                np.abs(efields_xformed[to_compare] -
                       efields_direct[to_compare]) /
                np.abs(efields_xformed[to_compare])) < 0.25)
Ejemplo n.º 6
0
    def test_pattern_all_phases(self):
        """
        Test that can predict phases for ALL reciprocal lattice vectors in pattern using the
        get_efield_fourier_components() function.

        Do this for a few lattice vectors
        :return:
        """
        dmd_size = [1920, 1080]
        nx, ny = dmd_size
        nphases = 3
        phase_index = 0

        # list of vectors to test
        vec_as = [[-7, 7], [-5, 5]]
        vec_bs = [[3, 9], [3, 9]]
        # vec_as = [[-1, 117]]
        # vec_bs = [[-6, 117]]

        # other unit vectors with larger unit cells that don't perfectly tile DMD do not work as well.
        # close, but larger errors
        # [12, -12]
        # [0, 18]

        for vec_a, vec_b in zip(vec_as, vec_bs):

            pattern, _, _, angles, frqs, periods, phases, recp_vects_a, recp_vects_b, min_leakage_angle = \
                dmd.vects2pattern_data(dmd_size, [vec_a], [vec_b], nphases=nphases)

            pattern = pattern[0, 0]
            unit_cell, xc, yc = dmd.get_sim_unit_cell(vec_a, vec_b, nphases)

            # get ft
            window = scipy.signal.windows.hann(nx)[
                None, :] * scipy.signal.windows.hann(ny)[:, None]
            pattern_ft = fft.fftshift(fft.fft2(fft.ifftshift(pattern *
                                                             window)))
            fxs = tools.get_fft_frqs(nx)
            dfx = fxs[1] - fxs[0]
            fys = tools.get_fft_frqs(ny)
            dfy = fys[1] - fys[0]

            # get expected pattern components
            efield, ns, ms, vecs = dmd.get_efield_fourier_components(
                unit_cell,
                xc,
                yc,
                vec_a,
                vec_b,
                nphases,
                phase_index,
                dmd_size,
                nmax=40)
            # divide by size of DC component
            efield = efield / np.max(np.abs(efield))

            # get phase from fft
            efield_img = np.zeros(efield.shape, dtype=np.complex)
            for ii in range(len(ns)):
                for jj in range(len(ms)):
                    if np.abs(vecs[ii, jj][0]) > 0.5 or np.abs(
                            vecs[ii, jj][1]) > 0.5:
                        efield_img[ii, jj] = np.nan
                        continue

                    try:
                        efield_img[ii, jj] = tools.get_peak_value(
                            pattern_ft, fxs, fys, vecs[ii, jj], 2)
                    except:
                        efield_img[ii, jj] = np.nan

            # divide by size of DC component
            efield_img = efield_img / np.nanmax(np.abs(efield_img))

            # import matplotlib.pyplot as plt
            # from matplotlib.colors import PowerNorm
            # plt.figure()
            # fs = np.linalg.norm(vecs, axis=2)
            #
            # xlim = [-0.05, 1.2*np.max([fxs.max(), fys.max()])]
            # to_use = np.logical_and(np.logical_not(np.isnan(efield_img)), np.abs(efield) > 1e-8)
            #
            # plt.subplot(2, 2, 1)
            # plt.semilogy(fs[to_use], np.abs(efield_img[to_use]), 'r.')
            # plt.semilogy(fs[to_use], np.abs(efield[to_use]), 'bx')
            # plt.xlim(xlim)
            # plt.ylabel('amplitude')
            # plt.xlabel('Frq 1/mirrors')
            # plt.legend(['FFT', 'Prediction'])
            #
            # plt.subplot(2, 2, 2)
            # plt.plot(fs[to_use], np.abs(efield_img[to_use]), 'r.')
            # plt.plot(fs[to_use], np.abs(efield[to_use]), 'bx')
            # plt.xlim(xlim)
            # plt.ylabel('amplitude')
            # plt.xlabel('Frq 1/mirrors')
            #
            # plt.subplot(2, 2, 3)
            # plt.plot(fs[to_use], np.mod(np.angle(efield_img[to_use]), 2*np.pi), 'r.')
            # plt.plot(fs[to_use], np.mod(np.angle(efield[to_use]), 2*np.pi), 'bx')
            # plt.xlim(xlim)
            # plt.ylabel('phases')
            # plt.xlabel('Frq 1/mirrors')
            #
            # plt.subplot(2, 2, 4)
            # extent = [fxs[0] - 0.5 * dfx, fxs[-1] + 0.5 * dfx, fys[-1] + 0.5 * dfy, fys[0] - 0.5 * dfy]
            # plt.imshow(np.abs(pattern_ft), extent=extent, norm=PowerNorm(gamma=0.1))
            #
            # assert np.round(np.nanmax(np.abs(efield_img - efield)), 12) == 0
            self.assertAlmostEqual(np.nanmax(np.abs(efield_img - efield)), 0,
                                   12)