示例#1
0
def main():
    # Variables to be set.
    wavelength                 = 0.5*pow(10,-6)
    pixeltom                   = 6*pow(10,-6)
    distance                   = 10.0
    propagation_type           = 'Fraunhofer'
    k                          = wavenumber(wavelength)
    sample_field               = np.zeros((150,150),dtype=np.complex64)
    sample_field               = np.zeros((150,150),dtype=np.complex64)
    sample_field[
                 65:85,
                 65:85
                ]              = 1
    sample_field               = add_random_phase(sample_field)
    hologram                   = propagate_beam(
                                                sample_field,
                                                k,
                                                distance,
                                                pixeltom,
                                                wavelength,
                                                propagation_type
                                               )
    if propagation_type == 'Fraunhofer':
        # Uncomment if you want to match the physical size of hologram and input field.
        #from odak.wave import fraunhofer_equal_size_adjust
        #hologram         = fraunhofer_equal_size_adjust(hologram,distance,pixeltom,wavelength)
        propagation_type = 'Fraunhofer Inverse'
        distance = np.abs(distance)
    reconstruction             = propagate_beam(
                                                hologram,
                                                k,
                                                -distance,
                                                pixeltom,
                                                wavelength,
                                                propagation_type
                                               )

    #from odak.visualize.plotly import detectorshow
    #detector       = detectorshow()
    #detector.add_field(sample_field)
    #detector.show()
    #detector       = detectorshow()
    #detector.add_field(hologram)
    #detector.show()
    #detector       = detectorshow()
    #detector.add_field(reconstruction)
    #detector.show()
    assert True==True
示例#2
0
def main():
    n = [100, 100]
    ranges = [[500., 3000.], [10., 100.]]
    x, y = np.mgrid[0:n[0], 0:n[1]]
    focals = x * (ranges[0][1] - ranges[0][0]) / n[0] + ranges[0][0]
    apertures = y * (ranges[1][1] - ranges[1][0]) / n[1] + ranges[1][0]
    wavelength = 0.0005
    resolutions = np.zeros((n[0], n[1], 3))
    for i in range(0, n[0]):
        for j in range(0, n[1]):
            resolutions[i, j, 0] = focals[i, j]
            resolutions[i, j, 1] = apertures[i, j]
            resolutions[i, j, 2] = odak.wave.rayleigh_resolution(
                diameter=resolutions[i, j, 1],
                focal=resolutions[i, j, 0],
                wavelength=wavelength) * 1000  # Conversion to um.
    figure = odak.visualize.surfaceshow(
        title='Spatial resolution',
        labels=[
            'Throw distance (mm)', 'Aperture size (mm) ',
            'Spatial resolution (um)'
        ],
        types=['log', 'log', 'log'],
        font_size=16,
        tick_no=[2, 2, 4],
    )
    figure.add_surface(data_x=resolutions[:, :, 0],
                       data_y=resolutions[:, :, 1],
                       data_z=resolutions[:, :, 2],
                       contour=False)
    figure.show()
    assert True == True
示例#3
0
def main():
    # Variables to be set.
    wavelength = 0.5 * pow(10, -6)
    pixeltom = 6 * pow(10, -6)
    distance = 0.2
    propagation_type = 'IR Fresnel'
    k = wavenumber(wavelength)
    sample_field = np.zeros((500, 500), dtype=np.complex64)
    sample_field[240:260, 240:260] = 1000
    random_phase = np.pi * np.random.random(sample_field.shape)
    sample_field = sample_field * np.cos(
        random_phase) + 1j * sample_field * np.sin(random_phase)
    sample_field = torch.from_numpy(sample_field)
    hologram = propagate_beam_torch(sample_field, k, distance, pixeltom,
                                    wavelength, propagation_type)
    reconstruction = propagate_beam_torch(hologram, k, -distance, pixeltom,
                                          wavelength, propagation_type)
    # from odak.visualize.plotly import detectorshow
    # detector       = detectorshow()
    # detector.add_field(sample_field)
    # detector.show()
    # detector.add_field(hologram)
    # detector.show()
    # detector.add_field(reconstruction)
    # detector.show()
    assert True == True
示例#4
0
文件: sample.py 项目: fschiffers/odak
def box_volume_sample(no=[10, 10, 10],
                      size=[100., 100., 100.],
                      center=[0., 0., 0.],
                      angles=[0., 0., 0.]):
    """
    Definition to generate samples in a box volume.

    Parameters
    ----------
    no          : list
                  Number of samples.
    size        : list
                  Physical size of the volume.
    center      : list
                  Center location of the volume.
    angles      : list
                  Tilt of the volume.

    Returns
    ----------
    samples     : ndarray
                  Samples generated.
    """
    samples = np.zeros((no[0], no[1], no[2], 3))
    x, y, z = np.mgrid[0:no[0], 0:no[1], 0:no[2]]
    step = [size[0] / no[0], size[1] / no[1], size[2] / no[2]]
    samples[:, :, :, 0] = x * step[0] + step[0] / 2. - size[0] / 2.
    samples[:, :, :, 1] = y * step[1] + step[1] / 2. - size[1] / 2.
    samples[:, :, :, 2] = z * step[2] + step[2] / 2. - size[2] / 2.
    samples = samples.reshape(
        (samples.shape[0] * samples.shape[1] * samples.shape[2],
         samples.shape[3]))
    samples = rotate_points(samples, angles=angles, offset=center)
    return samples
示例#5
0
文件: sample.py 项目: fschiffers/odak
def sphere_sample(no=[10, 10], radius=1., center=[0., 0., 0.], k=[1, 2]):
    """
    Definition to generate a regular sample set on the surface of a sphere using polar coordinates.

    Parameters
    ----------
    no          : list
                  Number of samples.
    radius      : float
                  Radius of a sphere.
    center      : list
                  Center of a sphere.
    k           : list
                  Multipliers for gathering samples. If you set k=[1,2] it will draw samples from a perfect sphere.

    Returns
    ----------
    samples     : ndarray
                  Samples generated.
    """
    samples = np.zeros((no[0], no[1], 3))
    psi, teta = np.mgrid[0:no[0], 0:no[1]]
    psi = k[0] * np.pi / no[0] * psi
    teta = k[1] * np.pi / no[1] * teta
    samples[:, :, 0] = center[0] + radius * np.sin(psi) * np.cos(teta)
    samples[:, :, 1] = center[0] + radius * np.sin(psi) * np.sin(teta)
    samples[:, :, 2] = center[0] + radius * np.cos(psi)
    samples = samples.reshape((no[0] * no[1], 3))
    return samples
示例#6
0
def compare():
    wavelength = 0.5 * pow(10, -6)
    pixeltom = 6 * pow(10, -6)
    distance = 0.2
    propagation_type = 'IR Fresnel'
    k = wavenumber(wavelength)
    sample_field = np.zeros((500, 500), dtype=np.complex64)
    sample_field[240:260, 240:260] = 1000
    random_phase = np.pi * np.random.random(sample_field.shape)
    sample_field = sample_field * np.cos(
        random_phase) + 1j * sample_field * np.sin(random_phase)

    sample_field_torch = torch.from_numpy(sample_field)

    ## Propagate and reconstruct using torch.
    hologram_torch = propagate_beam_torch(sample_field_torch, k, distance,
                                          pixeltom, wavelength,
                                          propagation_type)
    reconstruction_torch = propagate_beam_torch(hologram_torch, k, -distance,
                                                pixeltom, wavelength,
                                                propagation_type)

    ## Propagate and reconstruct using np.
    hologram = propagate_beam(sample_field, k, distance, pixeltom, wavelength,
                              propagation_type)
    reconstruction = propagate_beam(hologram, k, -distance, pixeltom,
                                    wavelength, propagation_type)

    np.testing.assert_array_almost_equal(hologram_torch.numpy(), hologram, 3)
示例#7
0
def get_triangle_normal(triangle, triangle_center=None):
    """
    Definition to calculate surface normal of a triangle.

    Parameters
    ----------
    triangle        : ndarray
                      Set of points in X,Y and Z to define a planar surface (3,3). It can also be list of triangles (mx3x3).
    triangle_center : ndarray
                      Center point of the given triangle. See odak.raytracing.center_of_triangle for more. In many scenarios you can accelerate things by precomputing triangle centers.

    Returns
    ----------
    normal          : ndarray
                      Surface normal at the point of intersection.
    """
    triangle = np.asarray(triangle)
    if len(triangle.shape) == 2:
        triangle = triangle.reshape((1, 3, 3))
    normal = np.zeros((triangle.shape[0], 2, 3))
    direction = np.cross(triangle[:, 0] - triangle[:, 1],
                         triangle[:, 2] - triangle[:, 1])
    if type(triangle_center) == type(None):
        normal[:, 0] = center_of_triangle(triangle)
    else:
        normal[:, 0] = triangle_center
    normal[:, 1] = direction / np.sum(direction, axis=1)[0]
    if normal.shape[0] == 1:
        normal = normal.reshape((2, 3))
    return normal
示例#8
0
文件: asset.py 项目: fschiffers/odak
def read_PLY_point_cloud(filename):
    """
    Definition to read a PLY file as a point cloud.

    Parameters
    ----------
    filename     : str
                   Filename of a PLY file.

    Returns
    ----------
    point_cloud  : ndarray
                   An array filled with poitns from the PLY file.
    """
    plydata      = PlyData.read(filename)
    if np.__name__ != 'numpy':
        import numpy as np_ply
        point_cloud      = np_ply.zeros((plydata['vertex'][:].shape[0],3))
        point_cloud[:,0] = np_ply.asarray(plydata['vertex']['x'][:])
        point_cloud[:,1] = np_ply.asarray(plydata['vertex']['y'][:])
        point_cloud[:,2] = np_ply.asarray(plydata['vertex']['z'][:])
        point_cloud      = np.asarray(point_cloud)
    else:
        point_cloud      = np.zeros((plydata['vertex'][:].shape[0],3))
        point_cloud[:,0] = np.asarray(plydata['vertex']['x'][:])
        point_cloud[:,1] = np.asarray(plydata['vertex']['y'][:])
        point_cloud[:,2] = np.asarray(plydata['vertex']['z'][:])
    return point_cloud
示例#9
0
文件: sample.py 项目: fschiffers/odak
def grid_sample(no=[10, 10],
                size=[100., 100.],
                center=[0., 0., 0.],
                angles=[0., 0., 0.]):
    """
    Definition to generate samples over a surface.

    Parameters
    ----------
    no          : list
                  Number of samples.
    size        : list
                  Physical size of the surface.
    center      : list
                  Center location of the surface.
    angles      : list
                  Tilt of the surface.

    Returns
    ----------
    samples     : ndarray
                  Samples generated.
    """
    samples = np.zeros((no[0], no[1], 3))
    step = [size[0] / (no[0] - 1), size[1] / (no[1] - 1)]
    x, y = np.mgrid[0:no[0], 0:no[1]]
    samples[:, :, 0] = x * step[0] - size[0] / 2.
    samples[:, :, 1] = y * step[1] - size[1] / 2.
    samples = samples.reshape(
        (samples.shape[0] * samples.shape[1], samples.shape[2]))
    samples = rotate_points(samples, angles=angles, offset=center)
    return samples
示例#10
0
def reflect(input_ray, normal):
    """ 
    Definition to reflect an incoming ray from a surface defined by a surface normal. Used method described in G.H. Spencer and M.V.R.K. Murty, "General Ray-Tracing Procedure", 1961.

    Parameters
    ----------
    input_ray    : ndarray
                   A vector/ray (2x3). It can also be a list of rays (nx2x3).
    normal       : ndarray
                   A surface normal (2x3). It also be a list of normals (nx2x3).

    Returns
    ----------
    output_ray   : ndarray
                   Array that contains starting points and cosines of a reflected ray.
    """
    input_ray = np.asarray(input_ray)
    normal = np.asarray(normal)
    if len(input_ray.shape) == 2:
        input_ray = input_ray.reshape((1, 2, 3))
    if len(normal.shape) == 2:
        normal = normal.reshape((1, 2, 3))
    mu = 1
    div = normal[:, 1, 0]**2 + normal[:, 1, 1]**2 + normal[:, 1, 2]**2
    a = mu * (input_ray[:, 1, 0] * normal[:, 1, 0] + input_ray[:, 1, 1] *
              normal[:, 1, 1] + input_ray[:, 1, 2] * normal[:, 1, 2]) / div
    n = np.int(np.amax(np.array([normal.shape[0], input_ray.shape[0]])))
    output_ray = np.zeros((n, 2, 3))
    output_ray[:, 0] = normal[:, 0]
    output_ray[:, 1] = input_ray[:, 1] - 2 * a * normal[:, 1]
    if output_ray.shape[0] == 1:
        output_ray = output_ray.reshape((2, 3))
    return output_ray
示例#11
0
文件: ray.py 项目: fschiffers/odak
def create_ray_from_angles(point, angles, mode='XYZ'):
    """
    Definition to create a ray from a point and angles.

    Parameters
    ----------
    point      : ndarray
                 Point in X,Y and Z.
    angles     : ndarray
                 Angles with X,Y,Z axes in degrees. All zeros point Z axis.
    mode       : str
                 Rotation mode determines ordering of the rotations at each axis. There are XYZ,YXZ    ,ZXY and ZYX modes.

    Returns
    ----------
    ray        : ndarray
                 Created ray.
    """
    if len(point.shape) == 1:
        point = point.reshape((1, 3))
    new_point = np.zeros(point.shape)
    new_point[:, 2] += 5.
    new_point = rotate_points(new_point, angles, mode=mode, offset=point[:, 0])
    ray = create_ray_from_two_points(point, new_point)
    if ray.shape[0] == 1:
        ray = ray.reshape((2, 3))
    return ray
示例#12
0
文件: sample.py 项目: fschiffers/odak
def circular_sample(no=[10, 10],
                    radius=10.,
                    center=[0., 0., 0.],
                    angles=[0., 0., 0.]):
    """
    Definition to generate samples inside a circle over a surface.

    Parameters
    ----------
    no          : list
                  Number of samples.
    radius      : float
                  Radius of the circle.
    center      : list
                  Center location of the surface.
    angles      : list
                  Tilt of the surface.

    Returns
    ----------
    samples     : ndarray
                  Samples generated.
    """
    samples = np.zeros((no[0] + 1, no[1] + 1, 3))
    r_angles, r = np.mgrid[0:no[0] + 1, 0:no[1] + 1]
    r = r / np.amax(r) * radius
    r_angles = r_angles / np.amax(r_angles) * np.pi * 2
    samples[:, :, 0] = r * np.cos(r_angles)
    samples[:, :, 1] = r * np.sin(r_angles)
    samples = samples[1:no[0] + 1, 1:no[1] + 1, :]
    samples = samples.reshape(
        (samples.shape[0] * samples.shape[1], samples.shape[2]))
    samples = rotate_points(samples, angles=angles, offset=center)
    return samples
def test():
    from odak import np
    import torch
    from odak.learn.wave import gerchberg_saxton, produce_phase_only_slm_pattern, calculate_amplitude
    from odak.tools import save_image
    wavelength = 0.000000532
    dx = 0.0000064
    distance = 0.2
    input_field = np.zeros((500, 500), dtype=np.complex64)
    input_field[0::50, :] += 1
    iteration_number = 3
    if np.__name__ == 'cupy':
        input_field = np.asnumpy(input_field)
    input_field = torch.from_numpy(input_field)
    hologram, reconstructed = gerchberg_saxton(input_field, iteration_number,
                                               distance, dx, wavelength,
                                               np.pi * 2, 'IR Fresnel')
    # hologram               = produce_phase_only_slm_pattern(
    #                                                         hologram,
    #                                                         2*np.pi
    #                                                         )
    # amplitude              = calculate_amplitude(reconstructed)
    # amplitude              = amplitude.numpy()
    # save_image(
    #             'output_amplitude_torch.png',
    #             amplitude,
    #             cmin=0,
    #             cmax=np.amax(amplitude)
    #             )
    assert True == True
示例#14
0
def test():
    from odak import np
    from odak.wave import gerchberg_saxton, adjust_phase_only_slm_range, produce_phase_only_slm_pattern, calculate_amplitude
    from odak.tools import save_image
    wavelength = 0.000000532
    dx = 0.0000064
    distance = 0.2
    input_field = np.zeros((500, 500), dtype=np.complex64)
    input_field[0::50, :] += 1
    iteration_number = 3
    hologram, reconstructed = gerchberg_saxton(input_field, iteration_number,
                                               distance, dx, wavelength,
                                               np.pi * 2, 'IR Fresnel')
    #    hologram               = produce_phase_only_slm_pattern(
    #                                                            hologram,
    #                                                            2*np.pi,
    #                                                            'output_hologram.png'
    #                                                           )
    #    amplitude              = calculate_amplitude(reconstructed)
    #    save_image(
    #               'output_amplitude.png',
    #               amplitude,
    #               cmin=0,
    #               cmax=np.amax(amplitude)
    #              )
    assert True == True
示例#15
0
def main():
    # Variables to be set.
    wavelength = 0.5 * pow(10, -6)
    pixeltom = 6 * pow(10, -6)
    distance = 0.1
    propagation_type = 'Fraunhofer'
    k = wavenumber(wavelength)
    sample_field = np.zeros((150, 150), dtype=np.complex64)
    sample_field[40:60, 40:60] = 10
    sample_field = add_random_phase(sample_field)
    hologram = propagate_beam(sample_field, k, distance, pixeltom, wavelength,
                              propagation_type)

    if propagation_type == 'Fraunhofer':
        distance = np.abs(distance)
        reconstruction = propagate_beam(hologram, k, distance, pixeltom,
                                        wavelength, 'Fraunhofer Inverse')

    from odak.visualize.plotly import detectorshow
    detector = detectorshow()
    detector.add_field(sample_field)
    detector.show()
    detector.add_field(hologram)
    detector.show()
    detector.add_field(reconstruction / np.amax(np.abs(reconstruction)))
    detector.show()
    assert True == True
示例#16
0
def test():
    no0 = [100, 100]
    no1 = [100, 100]
    size0 = [10., 10.]
    size1 = [10., 10.]
    wavelength = 0.005
    surface_location_0 = [0., 0., 0.]
    surface_location_1 = [0., 0., 10.]
    wave_number = wave.wavenumber(wavelength)
    samples_surface_0 = tools.grid_sample(no=no0,
                                          size=size0,
                                          center=surface_location_0)
    samples_surface_1 = tools.grid_sample(no=no1,
                                          size=size1,
                                          center=surface_location_1)
    field_0 = np.zeros((no0[0], no0[1]))
    field_0[50, 50] = 1.
    field_0[0, 20] = 2.
    field_0 = field_0.reshape((no0[0] * no0[1]))
    # Propagates to a specific plane.
    field_1 = wave.propagate_field(samples_surface_0,
                                   samples_surface_1,
                                   field_0,
                                   wave_number,
                                   direction=1)
    # Reconstruction: propagates back from that specific plane to start plane.
    field_2 = wave.propagate_field(samples_surface_1,
                                   samples_surface_0,
                                   field_1,
                                   wave_number,
                                   direction=-1)
    assert True == True
示例#17
0
def generate_bandlimits(size=[512, 512], levels=9):
    """
    A definition to calculate octaves used in bandlimiting frequencies in the frequency domain.

    Parameters
    ----------
    size       : list
                 Size of each mask in octaves.

    Returns
    ----------
    masks      : ndarray
                 Masks (Octaves).
    """
    masks = np.zeros((levels, size[0], size[1]))
    cx = int(size[0] / 2)
    cy = int(size[1] / 2)
    for i in range(0, masks.shape[0]):
        deltax = int((size[0]) / (2**(i + 1)))
        deltay = int((size[1]) / (2**(i + 1)))
        masks[i, cx - deltax:cx + deltax, cy - deltay:cy + deltay] = 1.
        masks[i,
              int(cx - deltax / 2.):int(cx + deltax / 2.),
              int(cy - deltay / 2.):int(cy + deltay / 2.)] = 0.
    masks = np.asarray(masks)
    return masks
示例#18
0
def main():
    # Variables to be set.
    wavelength                 = 0.5*pow(10,-6)
    pixeltom                   = 6*pow(10,-6)
    distance                   = 0.2
    propagation_type           = 'Bandlimited Angular Spectrum'
    k                          = wavenumber(wavelength)
    sample_field               = np.zeros((500,500),dtype=np.complex64)
    sample_field[
                 240:260,
                 240:260
                ]              = 1000
    random_phase               = np.pi*np.random.random(sample_field.shape)
    sample_field               = sample_field*np.cos(random_phase)+1j*sample_field*np.sin(random_phase)
    criterion = torch.nn.MSELoss()

    if np.__name__ == 'cupy':
        sample_field = np.asnumpy(sample_field)

    sample_field               = torch.from_numpy(sample_field)

    hologram                   = propagate_beam_torch(
                                                sample_field,
                                                k,
                                                distance,
                                                pixeltom,
                                                wavelength,
                                                propagation_type
                                               )
    hologram.requires_grad = True
    reconstruction             = propagate_beam_torch(
                                                hologram,
                                                k,
                                                -distance,
                                                pixeltom,
                                                wavelength,
                                                propagation_type
                                               )
    loss = criterion(torch.abs(sample_field), torch.abs(reconstruction))
    loss.backward()
    print(hologram.grad)
    print('backward successfully')

    #from odak.visualize.plotly import detectorshow
    #detector       = detectorshow()
    #detector.add_field(sample_field)
    #detector.show()
    #detector.add_field(hologram)
    #detector.show()
    #detector.add_field(reconstruction)
    #detector.show()
    assert True==True
示例#19
0
文件: ray.py 项目: fschiffers/odak
def create_ray_from_two_points(x0y0z0, x1y1z1):
    """
    Definition to create a ray from two given points. Note that both inputs must match in shape.

    Parameters
    ----------
    x0y0z0       : list
                   List that contains X,Y and Z start locations of a ray (3). It can also be a list of points as well (mx3). This is the starting point.
    x1y1z1       : list
                   List that contains X,Y and Z ending locations of a ray (3). It can also be a list of points as well (mx3). This is the end point.

    Returns
    ----------
    ray          : ndarray
                   Array that contains starting points and cosines of a created ray.
    """
    x0y0z0 = np.asarray(x0y0z0, dtype=np.float)
    x1y1z1 = np.asarray(x1y1z1, dtype=np.float)
    if len(x0y0z0.shape) == 1:
        x0y0z0 = x0y0z0.reshape((1, 3))
    if len(x1y1z1.shape) == 1:
        x1y1z1 = x1y1z1.reshape((1, 3))
    xdiff = x1y1z1[:, 0] - x0y0z0[:, 0]
    ydiff = x1y1z1[:, 1] - x0y0z0[:, 1]
    zdiff = x1y1z1[:, 2] - x0y0z0[:, 2]
    s = np.sqrt(xdiff**2 + ydiff**2 + zdiff**2)
    s[s == 0] = np.NaN
    cosines = np.zeros((xdiff.shape[0], 3))
    cosines[:, 0] = xdiff / s
    cosines[:, 1] = ydiff / s
    cosines[:, 2] = zdiff / s
    ray = np.zeros((xdiff.shape[0], 2, 3), dtype=np.float)
    ray[:, 0] = x0y0z0
    ray[:, 1] = cosines
    if ray.shape[0] == 1:
        ray = ray.reshape((2, 3))
    return ray
示例#20
0
    def plot_diffuser(self, figure):
        """
        Definition to plot diffuser to a odak.visualize.plotly.rayshow().

        Parameters
        ----------
        figure      : odak.visualize.plotly.rayshow()
                      Figure to plot the diffuser.
        """
        points = grid_sample(no=[10, 10],
                             size=self.settings["shape"],
                             center=self.settings["center"],
                             angles=self.settings["angles"])
        points = points.reshape((10, 10, 3))
        figure.add_surface(data_x=points[:, :, 0],
                           data_y=points[:, :, 1],
                           data_z=points[:, :, 2],
                           surface_color=np.zeros(points[:, :, 2].shape),
                           opacity=0.5,
                           contour=False)
示例#21
0
    def __init__(self,field=None,resolution=[1000,1000],shape=[10.,10.],center=[0.,0.,0.],angles=[0.,0.,0.],name='detector'):
        """
        Class to represent a simple planar detector.

        Parameters
        ----------
        field       : ndarray
                      Initial field to be loaded.
        resolution  : list
                      Resolution of the detector.
        shape       : list
                      Shape of the detector.
        center      : list
                      Center of the detector.
        angles      : list
                      Rotation angles of the detector.
        """
        self.settings   = {
                           'name'          : name,
                           'resolution'    : resolution,
                           'center'        : center,
                           'angles'        : angles,
                           'rotation mode' : 'XYZ',
                           'shape'         : shape,
                          }
        self.plane      = define_plane(
                                       self.settings['center'],
                                       angles=self.settings['angles']
                                      )
        if type(field) == type(None):
            self.field = np.zeros(
                                  (
                                   self.settings['resolution'][0],
                                   self.settings['resolution'][1],
                                   1
                                  ),
                                  dtype=np.complex64
                                  )
            self.clear_detector()
示例#22
0
def test():
    from odak import np
    from odak.wave import gerchberg_saxton, adjust_phase_only_slm_range, produce_phase_only_slm_pattern, calculate_amplitude
    from odak.tools import save_image
    wavelength = 0.000000532
    dx = 0.0000064
    distance = 2.0
    input_field = np.zeros((500, 500), dtype=np.complex64)
    input_field[0::50, :] += 1
    iteration_number = 200
    hologram, reconstructed = gerchberg_saxton(input_field, iteration_number,
                                               distance, dx, wavelength,
                                               np.pi * 2,
                                               'Bandlimited Angular Spectrum')
    hologram = produce_phase_only_slm_pattern(hologram, 2 * np.pi,
                                              'output_hologram.png')
    amplitude = calculate_amplitude(reconstructed)
    save_image('output_amplitude.png',
               amplitude,
               cmin=0,
               cmax=np.amax(amplitude))
    assert True == True
示例#23
0
def intersect_w_surface(ray, points):
    """
    Definition to find intersection point inbetween a surface and a ray. For more see: http://geomalgorithms.com/a06-_intersect-2.html

    Parameters
    ----------
    ray          : ndarray
                   A vector/ray.
    points       : ndarray
                   Set of points in X,Y and Z to define a planar surface.

    Returns
    ----------
    normal       : ndarray
                   Surface normal at the point of intersection.
    distance     : float
                   Distance in between starting point of a ray with it's intersection with a planar surface.
    """
    points = np.asarray(points)
    normal = get_triangle_normal(points)
    if len(ray.shape) == 2:
        ray = ray.reshape((1, 2, 3))
    if len(points) == 2:
        points = points.reshape((1, 3, 3))
    if len(normal.shape) == 2:
        normal = normal.reshape((1, 2, 3))
    f = normal[:, 0] - ray[:, 0]
    distance = np.dot(normal[:, 1], f.T) / np.dot(normal[:, 1], ray[:, 1].T)
    n = np.int(np.amax(np.array([ray.shape[0], normal.shape[0]])))
    normal = np.zeros((n, 2, 3))
    normal[:, 0] = ray[:, 0] + distance.T * ray[:, 1]
    distance = np.abs(distance)
    if normal.shape[0] == 1:
        normal = normal.reshape((2, 3))
        distance = distance.reshape((1))
    if distance.shape[0] == 1 and len(distance.shape) > 1:
        distance = distance.reshape((distance.shape[1]))
    return normal, distance
示例#24
0
def band_limited_angular_spectrum(field,k,distance,dx,wavelength):
    """
    A definition to calculate bandlimited angular spectrum based beam propagation. For more Matsushima, Kyoji, and Tomoyoshi Shimobaba. "Band-limited angular spectrum method for numerical simulation of free-space propagation in far and near fields." Optics express 17.22 (2009): 19662-19673.

    Parameters
    ----------
    field            : np.complex
                       Complex field (MxN).
    k                : odak.wave.wavenumber
                       Wave number of a wave, see odak.wave.wavenumber for more.
    distance         : float
                       Propagation distance.
    dx               : float
                       Size of one single pixel in the field grid (in meters).
    wavelength       : float
                       Wavelength of the electric field.

    Returns
    =======
    result           : np.complex
                       Final complex field (MxN).
    """
    nv,nu  = field.shape
    x      = np.linspace(-nu/2*dx,nu/2*dx,nu)
    y      = np.linspace(-nv/2*dx,nv/2*dx,nv)
    X,Y    = np.meshgrid(x,y)
    Z      = X**2+Y**2
    h      = 1./(1j*wavelength*distance)*np.exp(1j*k*(distance+Z/2/distance))
    h      = np.fft.fft2(np.fft.fftshift(h))*dx**2
    flimx  = np.ceil(1/(((2*distance*(1./(nu)))**2+1)**0.5*wavelength))
    flimy  = np.ceil(1/(((2*distance*(1./(nv)))**2+1)**0.5*wavelength))
    mask   = np.zeros((nu,nv),dtype=np.complex64)
    mask   = (np.abs(X)<flimx) & (np.abs(Y)<flimy)
    mask   = set_amplitude(h,mask)
    U1     = np.fft.fft2(np.fft.fftshift(field))
    U2     = mask*U1
    result = np.fft.ifftshift(np.fft.ifft2(U2))
    return result
示例#25
0
def rayleigh_sommerfeld(field,k,distance,dx,wavelength):
    """
    Definition to compute beam propagation using Rayleigh-Sommerfeld's diffraction formula (Huygens-Fresnel Principle). For more see Section 3.5.2 in Goodman, Joseph W. Introduction to Fourier optics. Roberts and Company Publishers, 2005.

    Parameters
    ----------
    field            : np.complex
                       Complex field (MxN).
    k                : odak.wave.wavenumber
                       Wave number of a wave, see odak.wave.wavenumber for more.
    distance         : float
                       Propagation distance.
    dx               : float
                       Size of one single pixel in the field grid (in meters).
    wavelength       : float
                       Wavelength of the electric field.

    Returns
    =======
    result           : np.complex
                       Final complex field (MxN).
    """
    nv,nu     = field.shape
    x         = np.linspace(-nv*dx/2,nv*dx/2,nv)
    y         = np.linspace(-nu*dx/2,nu*dx/2,nu)
    X,Y       = np.meshgrid(x,y)
    Z         = X**2+Y**2
    result    = np.zeros(field.shape,dtype=np.complex64)
    direction = int(distance/np.abs(distance))
    for i in range(nu):
        for j in range(nv):
            if field[i,j] != 0:
                r01      = np.sqrt(distance**2+(X-X[i,j])**2+(Y-Y[i,j])**2)*direction
                cosnr01  = np.cos(distance/r01)
                result  += field[i,j]*np.exp(1j*k*r01)/r01*cosnr01
    result *= 1./(1j*wavelength)
    return result
示例#26
0
    def raytrace(self,ray,field=None,channel=0):
        """
        A definition to calculate the intersection between given ray(s) and the detector. If a ray contributes to the detector, field will be taken into account in calculating the field over the planar detector.
 
        Parameters
        ----------
        ray          : ndarray
                       Ray(s) to be intersected.
        field        : ndarray
                       Field(s) to be used for calculating contribution of rays to the detector.
        channel      : list
                       Which color channel to contribute to in the detector plane. Default is zero. One can use a list to select multiple channels separately.
 
        Returns
        ----------
        normal       : ndarray
                       Normal for each intersection point.
        distance     : ndarray
                       Distance for each ray.
        """
        normal,distance = intersect_w_surface(ray,self.plane)
        points          = bring_plane_to_origin(
                                                normal[:,0],
                                                self.plane,
                                                shape=self.settings["shape"],
                                                center=self.settings["center"],
                                                angles=self.settings["angles"],
                                                mode=self.settings["rotation mode"]
                                               )
        if points.shape[0] == 3:
            points = points.reshape((1,3))
        # This could improve with a bilinear filter. Basically removing int with a filter.
        detector_ids = np.array(
                                [
                                 (points[:,0]+self.settings["shape"][0]/2.)/self.settings["shape"][0]*self.settings["resolution"][0]+1,
                                 (points[:,1]+self.settings["shape"][1]/2.)/self.settings["shape"][1]*self.settings["resolution"][1]+1
                                ],
                                dtype=int
                               )
        detector_ids[0,:] = (detector_ids[0,:]>=1)*detector_ids[0,:]
        detector_ids[1,:] = (detector_ids[1,:]>=1)*detector_ids[1,:]
        detector_ids[0,:] = (detector_ids[0,:]<self.settings["resolution"][0]+1)*detector_ids[0,:]
        detector_ids[1,:] = (detector_ids[1,:]<self.settings["resolution"][1]+1)*detector_ids[1,:]
        cache             = np.zeros(
                                     (
                                      self.settings["resolution"][0]+1,
                                      self.settings["resolution"][1]+1,
                                      self.field.shape[2]
                                     ),
                                     dtype=np.complex64
                                    )

        ##################################################################
        # This solution is far from ideal. There has to be a better way. #
        ##################################################################
        for detector_id in range(0,detector_ids.shape[1]):
            x           = detector_ids[0,detector_id]
            y           = detector_ids[1,detector_id]
            r2          = distance[detector_id]**2
            if type(field) == type(None):
                cache[x,y] += 1000./r2
            else:
                cache[x,y] += field[x,y]/r2
        ##################################################################
        # This solution isn't working at all as two same ids are         #
        # interpretted as one.                                           #
        ##################################################################
        #cache[
        #       detector_ids[0],
        #       detector_ids[1],
        #       channel
        #      ]           += field
        ##################################################################
        self.field      += cache[1::,1::,:]
        return normal,distance
示例#27
0
def point_wise(field,distances,k,dx,wavelength,lens_method='ideal',propagation_method='Bandlimited Angular Spectrum',n_iteration=3):
    """
    Point-wise hologram calculation method. For more Maimone, Andrew, Andreas Georgiou, and Joel S. Kollin. "Holographic near-eye displays for virtual and augmented reality." ACM Transactions on Graphics (TOG) 36.4 (2017): 1-16.

    Parameters
    ----------
    field            : ndarray
                       Complex input field to be converted into a hologram.
    distances        : ndarray
                       Depth map of the input field.
    k                : odak.wave.wavenumber
                       Wave number of a wave, see odak.wave.wavenumber for more.
    dx               : float
                       Pixel pitch.
    wavelength       : float
                       Wavelength of the light.
    lens_model       : str
                       Method to calculate the lens patterns.
    propagation_mode : str
                       Beam propagation method to be used if the lens_model is not equal to `ideal`.
    n_iteration      : int
                       Number of iterations.

    Returns
    ----------
    hologram   : ndarray
                 Generated complex hologram.
    """
    hologram      = np.zeros(field.shape,dtype=np.complex64)
    nx,ny         = field.shape
    cx            = int(nx/2)
    cy            = int(ny/2)
    non_zeros     = np.asarray((np.abs(field)>0).nonzero())
    unique_dist   = np.unique(distances)
    unique_dist   = unique_dist[unique_dist!=0]
    target        = np.zeros((nx,ny),dtype=np.complex64)
    target[cx,cy] = 1.
    lenses        = []
    for distance in unique_dist:
        if lens_method == 'ideal':
            new_lens = quadratic_phase_function(nx,ny,k,focal=distance,dx=dx)
            lenses.append(new_lens)
        elif lens_method == 'Gerchberg-Saxton':
            new_lens,_ = gerchberg_saxton(
                                          target,
                                          n_iteration,
                                          distance,
                                          dx,
                                          wavelength,
                                          np.pi*2,
                                          propagation_method
                                         )
            lenses.append(new_lens)
    for m in tqdm(range(non_zeros.shape[1])):
        i         = int(non_zeros[0,m])
        j         = int(non_zeros[1,m])
        lens_id   = int(np.argwhere(unique_dist==distances[i,j]))
        lens      = lenses[lens_id]
        lens      = np.roll(lens,i-cx,axis=0)
        lens      = np.roll(lens,j-cy,axis=1)
        hologram += lens*field[i,j]
    return hologram
示例#28
0
 def clear_detector(self):
     """
     A definition to clear the field accumulated on the detector.
     """
     self.field = np.zeros(self.field.shape,dtype=np.complex64)