def inside_outline(fault):
    def inside(tri):
        return rotated_outline.contains(Polygon(rotated_xyz[tri]))
    # Iterate through triangles in internal coords and select those inside 
    # outline the non-convex outline of the fault...
    x, y, z = fault._internal_xyz.T
    rotated_tri = Triangulation(x, y)
    rotated_xyz = fault._internal_xyz
    rotated_outline = Polygon(fault._rotated_outline)

    return np.array([inside(tri) for tri in rotated_tri.triangle_nodes])
Exemplo n.º 2
0
 def tri(self):
     try:
         from matplotlib.delaunay import Triangulation
     except ImportError:
         raise ImportError('Maplotlib is required for geoprobe.swfault '
                           'triangulation')
     try:
         return self._tri
     except AttributeError:
         x, y, z = self._internal_xyz.T
         self._tri = Triangulation(x, y)
         self._tri.x = self.x
         self._tri.y = self.y
         return self._tri
Exemplo n.º 3
0
def calc_geodesic_distances(xyz, res=.03):
    """
    Calculates pairwise geodesic distances.
    Note that we generate the graph by projecting to 2D
    """
    x,y = xyz[:,:2].T
    tri = Triangulation(x,y)
    G = nx.Graph()
    #G.add_nodes_from(xrange(len(xyz)))
    for i0 in xrange(len(xyz)):
        G.add_node(i0)
    for (i0, i1) in tri.edge_db:
        dist = np.linalg.norm(xyz[i1] - xyz[i0])
        if dist < res:
            G.add_edge(i0, i1, weight = np.linalg.norm(xyz[i1] - xyz[i0]))
    distmat = np.asarray(nx.floyd_warshall_numpy(G))
    
    finitevals = distmat[np.isfinite(distmat)]
    distmat[~np.isfinite(distmat)] = finitevals.max() * 3
    return distmat
Exemplo n.º 4
0
xi, yi, zi = xxr.flat[ij], yyr.flat[ij], zzr.flat[ij]

ij2 = N.unique((N.random.rand(50)*zzr.size).astype('i'))
xo2, yo2 = xxr.flat[ij2], yyr.flat[ij2]


# CDAT natgrid
from nat import Natgrid
I = Natgrid(xi, yi, xr, yr)
I.ext = 1
I.igr = 1
zzoc = I.rgrd(zi).T

# Matplotlib / R. Kern
from matplotlib.delaunay import Triangulation
tri = Triangulation(xi,yi)
I = tri.nn_extrapolator(zi)
zzok = I(xxr,yyr)


# Plot
from matplotlib import pyplot as P
P.figure(figsize=(4, 11))
P.subplot(311)
P.pcolormesh(zzr, **vminmax)
P.title('Original')
stdref = zzr.std()
P.subplot(312)
P.pcolormesh(zzoc, **vminmax)
P.title('CDAT Natgrid: err=%i%%'%((zzr-zzoc).std()*100/stdref))
P.subplot(313)
Exemplo n.º 5
0
ij2 = N.unique((N.random.rand(50) * zzr.size).astype('i'))
xo2, yo2 = xxr.flat[ij2], yyr.flat[ij2]

# CDAT natgrid
from nat import Natgrid

I = Natgrid(xi, yi, xr, yr)
I.ext = 1
I.igr = 1
zzoc = I.rgrd(zi).T

# Matplotlib / R. Kern
from matplotlib.delaunay import Triangulation

tri = Triangulation(xi, yi)
I = tri.nn_extrapolator(zi)
zzok = I(xxr, yyr)

# Plot
from matplotlib import pyplot as P

P.figure(figsize=(4, 11))
P.subplot(311)
P.pcolormesh(zzr, **vminmax)
P.title('Original')
stdref = zzr.std()
P.subplot(312)
P.pcolormesh(zzoc, **vminmax)
P.title('CDAT Natgrid: err=%i%%' % ((zzr - zzoc).std() * 100 / stdref))
P.subplot(313)
Exemplo n.º 6
0
ij2 = N.unique((N.random.rand(100)*zzr.size).astype('i'))
xo, yo = xxr.flat[ij2], yyr.flat[ij2]


# Sans VACUMM

# - CDAT natgrid
from nat import Natgrid
I = Natgrid(xi, yi, xr, yr)
I.ext = 1                                               # Changer
I.igr = 1                                               # les parametres
zzoc = I.rgrd(zi).T

# - Matplotlib / R. Kern
from matplotlib.delaunay import Triangulation
tri = Triangulation(xi,yi)
I = tri.nn_extrapolator(zi)                             # Tester les autres methodes
zzork = I(xxr,yyr)  # vers grille
zork = I(xo,yo) # vers points


# Avec VACUMM
from vacumm.misc.grid.regridding import GridData, griddata, xy2xy
zzov = griddata(xi, yi, zi, (xr, yr), method='nat', ext=True, sub=10)     
# -> Tester la methode "carg"
# -> Testez parametre sub=...
# -> Essayer avec GridData
zov2 = xy2xy(xi, yi, zi, xo, yo)

# Krigeage
from vacumm.misc.grid.kriging import krig
Exemplo n.º 7
0
def AngleResolved2Polar(data, output_size, hole=True, dtype=None):
    """
    Converts an angle resolved image to polar (aka azymuthal) projection
    data (model.DataArray): The image that was projected on the CCD after being
      relfected on the parabolic mirror. The flat line of the D shape is
      expected to be horizontal, at the top. It needs PIXEL_SIZE and AR_POLE
      metadata. Pixel size is the sensor pixel size * binning / magnification.
    output_size (int): The size of the output DataArray (assumed to be square)
    hole (boolean): Crop the pole if True
    dtype (numpy dtype): intermediary dtype for computing the theta/phi data
    returns (model.DataArray): converted image in polar view
    """
    assert(len(data.shape) == 2)  # => 2D with greyscale
    # TODO: separate raw projection to another function, named AngleResolved2Rectangular()

    # Get the metadata
    try:
        pixel_size = data.metadata[model.MD_PIXEL_SIZE]
        mirror_x, mirror_y = data.metadata[model.MD_AR_POLE]
        parabola_f = data.metadata.get(model.MD_AR_PARABOLA_F, AR_PARABOLA_F)
    except KeyError:
        raise ValueError("Metadata required: MD_PIXEL_SIZE, MD_AR_POLE.")

    if dtype is None:
        dtype = numpy.float64

    # Crop the input image to half circle
    cropped_image = _CropHalfCircle(data, pixel_size, (mirror_x, mirror_y), hole)

    theta_data = numpy.empty(shape=cropped_image.shape, dtype=dtype)
    phi_data = numpy.empty(shape=cropped_image.shape, dtype=dtype)
    omega_data = numpy.empty(shape=cropped_image.shape)

    # For each pixel of the input ndarray, input metadata is used to
    # calculate the corresponding theta, phi and radiant intensity
    image_x, image_y = cropped_image.shape
    jj = numpy.linspace(0, image_y - 1, image_y)
    xpix = mirror_x - jj

    for i in xrange(image_x):
        ypix = (i - mirror_y) + (2 * parabola_f) / pixel_size[1]
        theta, phi, omega = _FindAngle(data, xpix, ypix, pixel_size)

        theta_data[i, :] = theta
        phi_data[i, :] = phi
        omega_data[i, :] = cropped_image[i] / omega

    # Convert into polar coordinates
    h_output_size = output_size / 2
    theta = theta_data * (h_output_size / math.pi * 2)
    phi = phi_data
    theta_data = numpy.cos(phi) * theta
    phi_data = numpy.sin(phi) * theta

    # Interpolation into 2d array
#    xi = numpy.linspace(-h_output_size, h_output_size, 2 * h_output_size + 1)
#    yi = numpy.linspace(-h_output_size, h_output_size, 2 * h_output_size + 1)
#    qz = mlab.griddata(phi_data.flat, theta_data.flat, omega_data.flat, xi, yi, interp="linear")

    # FIXME: need rotation (=swap axes), but swapping theta/phi slows down the
    # interpolation by 3 ?!
    with warnings.catch_warnings():
        # Some points might be so close that they are identical (within float
        # precision). It's fine, no need to generate a warning.
        warnings.simplefilter("ignore", DuplicatePointWarning)
        triang = Triangulation(theta_data.flat, phi_data.flat)
        # TODO use the standard matplotlib.tri.Triangulation
        # + matplotlib.tri.LinearTriInterpolator
    interp = triang.linear_interpolator(omega_data.flat, default_value=0)
    qz = interp[-h_output_size:h_output_size:complex(0, output_size),  # Y
                - h_output_size:h_output_size:complex(0, output_size)]  # X
    qz = qz.swapaxes(0, 1)[:, ::-1]  # rotate by 90°
    result = model.DataArray(qz, data.metadata)

    return result
Exemplo n.º 8
0
def AngleResolved2Rectangular(data, output_size, hole=True, dtype=None):
    """
    Converts an angle resolved image to equirectangular (aka cylindrical)
      projection (ie, phi/theta axes)
    data (model.DataArray): The image that was projected on the CCD after being
      relfected on the parabolic mirror. The flat line of the D shape is
      expected to be horizontal, at the top. It needs PIXEL_SIZE and AR_POLE
      metadata. Pixel size is the sensor pixel size * binning / magnification.
    output_size (int, int): The size of the output DataArray (theta, phi),
      not including the theta/phi angles at the first row/column
    hole (boolean): Crop the pole if True
    dtype (numpy dtype): intermediary dtype for computing the theta/phi data
    returns (model.DataArray): converted image in equirectangular view
    """
    assert(len(data.shape) == 2)  # => 2D with greyscale

    # Get the metadata
    try:
        pixel_size = data.metadata[model.MD_PIXEL_SIZE]
        mirror_x, mirror_y = data.metadata[model.MD_AR_POLE]
        parabola_f = data.metadata.get(model.MD_AR_PARABOLA_F, AR_PARABOLA_F)
    except KeyError:
        raise ValueError("Metadata required: MD_PIXEL_SIZE, MD_AR_POLE.")

    if dtype is None:
        dtype = numpy.float64

    # Crop the input image to half circle
    cropped_image = _CropHalfCircle(data, pixel_size, (mirror_x, mirror_y), hole)

    theta_data = numpy.empty(shape=cropped_image.shape, dtype=dtype)
    phi_data = numpy.empty(shape=cropped_image.shape, dtype=dtype)
    omega_data = numpy.empty(shape=cropped_image.shape)

    # For each pixel of the input ndarray, input metadata is used to
    # calculate the corresponding theta, phi and radiant intensity
    image_x, image_y = cropped_image.shape
    jj = numpy.linspace(0, image_y - 1, image_y)
    xpix = mirror_x - jj

    for i in xrange(image_x):
        ypix = (i - mirror_y) + (2 * parabola_f) / pixel_size[1]
        theta, phi, omega = _FindAngle(data, xpix, ypix, pixel_size)

        theta_data[i, :] = theta
        phi_data[i, :] = phi
        omega_data[i, :] = cropped_image[i] / omega

    # compute new mask
    phi_lin = numpy.linspace(0, 2 * math.pi, output_size[1])
    theta_lin = numpy.linspace(0, math.pi / 2, output_size[0])
    phi_grid, theta_grid = numpy.meshgrid(phi_lin, theta_lin)

    a = (1 / (4 * parabola_f))
    xcut = AR_XMAX - AR_PARABOLA_F
    # length vector
    c = (2 * (a * numpy.cos(phi_grid) * numpy.sin(theta_grid) + a)) ** -1
    x = -numpy.sin(theta_grid) * numpy.cos(phi_grid) * c
    z = numpy.cos(theta_grid) * c

    mask = numpy.ones(output_size)
    mask[(x > xcut) | (theta_grid < (4 * numpy.pi / 180)) | (z < AR_FOCUS_DISTANCE)] = 0
    # TODO: can probably choose a selection here to speed up interpolation.
    # This is a silly fix but it works. Prevents extrapolation which leads to errors
    theta_data = numpy.tile(theta_data, (1, 3))
    phi_data = numpy.append(numpy.append(phi_data - 2 * math.pi, phi_data, axis=1), phi_data + 2 * math.pi, axis=1)

    ARdata = numpy.tile(omega_data, (1, 3))
    with warnings.catch_warnings():
        # Some points might be so close that they are identical (within float
        # precision). It's fine, no need to generate a warning.
        warnings.simplefilter("ignore", DuplicatePointWarning)
        triang = Triangulation(phi_data.flat, theta_data.flat)
    interp = triang.linear_interpolator(ARdata.flat, default_value=0)
    qz = interp[0:numpy.pi / 2:complex(0, output_size[0]),
                0:2 * numpy.pi:complex(0, output_size[1])]
    qz = numpy.roll(qz, qz.shape[1] // 2, axis=1)
    qz_masked = qz * mask

    # TODO: put theta/phi angles in metadata?
    # attach theta as first column
    qz_masked = numpy.append(theta_lin.reshape(theta_lin.shape[0], 1), qz_masked, axis=1)
    # attach phi as first row
    phi_lin = numpy.append([[0]], phi_lin.reshape(1, phi_lin.shape[0]), axis=1)
    qz_masked = numpy.append(phi_lin, qz_masked, axis=0)
    result = model.DataArray(qz_masked, data.metadata)

    return result
Exemplo n.º 9
0
def AngleResolved2Polar(data, output_size, hole=True, dtype=None):
    """
    Converts an angle resolved image to polar (aka azymuthal) projection
    data (model.DataArray): The image that was projected on the CCD after being
      relfected on the parabolic mirror. The flat line of the D shape is
      expected to be horizontal, at the top. It needs PIXEL_SIZE and AR_POLE
      metadata. Pixel size is the sensor pixel size * binning / magnification.
    output_size (int): The size of the output DataArray (assumed to be square)
    hole (boolean): Crop the pole if True
    dtype (numpy dtype): intermediary dtype for computing the theta/phi data
    returns (model.DataArray): converted image in polar view
    """
    assert(len(data.shape) == 2)  # => 2D with greyscale
    # TODO: separate raw projection to another function, named AngleResolved2Rectangular()

    # Get the metadata
    try:
        pixel_size = data.metadata[model.MD_PIXEL_SIZE]
        mirror_x, mirror_y = data.metadata[model.MD_AR_POLE]
        parabola_f = data.metadata.get(model.MD_AR_PARABOLA_F, AR_PARABOLA_F)
    except KeyError:
        raise ValueError("Metadata required: MD_PIXEL_SIZE, MD_AR_POLE.")

    if dtype is None:
        dtype = numpy.float64

    # Crop the input image to half circle
    cropped_image = _CropHalfCircle(data, pixel_size, (mirror_x, mirror_y), hole)

    theta_data = numpy.empty(shape=cropped_image.shape, dtype=dtype)
    phi_data = numpy.empty(shape=cropped_image.shape, dtype=dtype)
    omega_data = numpy.empty(shape=cropped_image.shape)

    # For each pixel of the input ndarray, input metadata is used to
    # calculate the corresponding theta, phi and radiant intensity
    image_x, image_y = cropped_image.shape
    jj = numpy.linspace(0, image_y - 1, image_y)
    xpix = mirror_x - jj

    for i in xrange(image_x):
        ypix = (i - mirror_y) + (2 * parabola_f) / pixel_size[1]
        theta, phi, omega = _FindAngle(data, xpix, ypix, pixel_size)

        theta_data[i, :] = theta
        phi_data[i, :] = phi
        omega_data[i, :] = cropped_image[i] / omega

    # Convert into polar coordinates
    h_output_size = output_size / 2
    theta = theta_data * (h_output_size / math.pi * 2)
    phi = phi_data
    theta_data = numpy.cos(phi) * theta
    phi_data = numpy.sin(phi) * theta

    # Interpolation into 2d array
    # FIXME: griddata() uses a 3x less memory (and especially, doesn't leak),
    # but it's 5x slower
    # => create a cpython function calling libqhull directly?
#     grid_x, grid_y = numpy.mgrid[-h_output_size:h_output_size:output_size * 1j,
#                                  - h_output_size:h_output_size:output_size * 1j]
#
#     #One way possible to increase the speed is to discard points too close from
#     #each other. Everything < 1 px apart is pretty useless. As they are
#     #spatially ordered, it's shouldn't be too costly to check
#     #See kmeans clustering maybe?
#     #nt, np, no = [theta_data[0, 0]], [phi_data[0, 0]], [omega_data[0, 0]]
#     #for t, p, o in zip(theta_data.flat, phi_data.flat, omega_data.flat):
#     #    if math.hypot(t - nt[-1], p - np[-1]) > 0.9:
#     #        nt.append(t)
#     #        np.append(p)
#     #        no.append(o)
#     #logging.warning("Reduce size to %d", len(no))
#     #qz = griddata((nt, np), no, (grid_x, grid_y), method='linear', fill_value=0)
#     qz = griddata((theta_data.flat, phi_data.flat), omega_data.flat, (grid_x, grid_y),
#                   method='linear', fill_value=0)
#     qz = qz[:, ::-1]

    # Warning: Uses a lot of memory, which is not recovered until the thread is
    # ended. Every thread will use a different memory pool.
    # FIXME: need rotation (=swap axes), but swapping theta/phi slows down the
    # interpolation by 3 ?!
    with warnings.catch_warnings():
        # Some points might be so close that they are identical (within float
        # precision). It's fine, no need to generate a warning.
        warnings.simplefilter("ignore", DuplicatePointWarning)
        triang = Triangulation(theta_data.flat, phi_data.flat)  # FIXME: Leaks memory when run in a separate thread
    interp = triang.linear_interpolator(omega_data.flat, default_value=0)
    qz = interp[-h_output_size:h_output_size:complex(0, output_size),  # Y
                - h_output_size:h_output_size:complex(0, output_size)]  # X
    qz = qz.swapaxes(0, 1)[:, ::-1]  # rotate by 90°

# TODO use the standard matplotlib.tri.Triangulation, but it uses 3x more memory
# also leaks, and is slower!
#     triang = Triangulation(phi_data.flat, theta_data.flat)
#     interp = LinearTriInterpolator(triang, omega_data.flat)
#     xi, yi = numpy.meshgrid(numpy.linspace(-h_output_size, h_output_size, output_size),
#                             numpy.linspace(-h_output_size, h_output_size, output_size))
#     qz = interp(xi, yi)
#     qz = qz[:, ::-1]

    result = model.DataArray(qz, data.metadata)

    return result
Exemplo n.º 10
0
def AngleResolved2Polar(data, output_size, hole=True, dtype=None):
    """
    Converts an angle resolved image to polar (aka azymuthal) projection
    data (model.DataArray): The image that was projected on the CCD after being
      relfected on the parabolic mirror. The flat line of the D shape is
      expected to be horizontal, at the top. It needs PIXEL_SIZE and AR_POLE
      metadata. Pixel size is the sensor pixel size * binning / magnification.
    output_size (int): The size of the output DataArray (assumed to be square)
    hole (boolean): Crop the pole if True
    dtype (numpy dtype): intermediary dtype for computing the theta/phi data
    returns (model.DataArray): converted image in polar view
    """
    assert (len(data.shape) == 2)  # => 2D with greyscale
    # TODO: separate raw projection to another function, named AngleResolved2Rectangular()

    # Get the metadata
    try:
        pixel_size = data.metadata[model.MD_PIXEL_SIZE]
        mirror_x, mirror_y = data.metadata[model.MD_AR_POLE]
        parabola_f = data.metadata.get(model.MD_AR_PARABOLA_F, AR_PARABOLA_F)
    except KeyError:
        raise ValueError("Metadata required: MD_PIXEL_SIZE, MD_AR_POLE.")

    if dtype is None:
        dtype = numpy.float64

    # Crop the input image to half circle
    cropped_image = _CropHalfCircle(data, pixel_size, (mirror_x, mirror_y),
                                    hole)

    theta_data = numpy.empty(shape=cropped_image.shape, dtype=dtype)
    phi_data = numpy.empty(shape=cropped_image.shape, dtype=dtype)
    omega_data = numpy.empty(shape=cropped_image.shape)

    # For each pixel of the input ndarray, input metadata is used to
    # calculate the corresponding theta, phi and radiant intensity
    image_x, image_y = cropped_image.shape
    jj = numpy.linspace(0, image_y - 1, image_y)
    xpix = mirror_x - jj

    for i in xrange(image_x):
        ypix = (i - mirror_y) + (2 * parabola_f) / pixel_size[1]
        theta, phi, omega = _FindAngle(data, xpix, ypix, pixel_size)

        theta_data[i, :] = theta
        phi_data[i, :] = phi
        omega_data[i, :] = cropped_image[i] / omega

    # Convert into polar coordinates
    h_output_size = output_size / 2
    theta = theta_data * (h_output_size / math.pi * 2)
    phi = phi_data
    theta_data = numpy.cos(phi) * theta
    phi_data = numpy.sin(phi) * theta

    # Interpolation into 2d array
    # FIXME: griddata() uses a 3x less memory (and especially, doesn't leak),
    # but it's 5x slower
    # => create a cpython function calling libqhull directly?
    #     grid_x, grid_y = numpy.mgrid[-h_output_size:h_output_size:output_size * 1j,
    #                                  - h_output_size:h_output_size:output_size * 1j]
    #
    #     #One way possible to increase the speed is to discard points too close from
    #     #each other. Everything < 1 px apart is pretty useless. As they are
    #     #spatially ordered, it's shouldn't be too costly to check
    #     #See kmeans clustering maybe?
    #     #nt, np, no = [theta_data[0, 0]], [phi_data[0, 0]], [omega_data[0, 0]]
    #     #for t, p, o in zip(theta_data.flat, phi_data.flat, omega_data.flat):
    #     #    if math.hypot(t - nt[-1], p - np[-1]) > 0.9:
    #     #        nt.append(t)
    #     #        np.append(p)
    #     #        no.append(o)
    #     #logging.warning("Reduce size to %d", len(no))
    #     #qz = griddata((nt, np), no, (grid_x, grid_y), method='linear', fill_value=0)
    #     qz = griddata((theta_data.flat, phi_data.flat), omega_data.flat, (grid_x, grid_y),
    #                   method='linear', fill_value=0)
    #     qz = qz[:, ::-1]

    # Warning: Uses a lot of memory, which is not recovered until the thread is
    # ended. Every thread will use a different memory pool.
    # FIXME: need rotation (=swap axes), but swapping theta/phi slows down the
    # interpolation by 3 ?!
    with warnings.catch_warnings():
        # Some points might be so close that they are identical (within float
        # precision). It's fine, no need to generate a warning.
        warnings.simplefilter("ignore", DuplicatePointWarning)
        triang = Triangulation(
            theta_data.flat,
            phi_data.flat)  # FIXME: Leaks memory when run in a separate thread
    interp = triang.linear_interpolator(omega_data.flat, default_value=0)
    qz = interp[-h_output_size:h_output_size:complex(0, output_size),  # Y
                -h_output_size:h_output_size:complex(0, output_size)]  # X
    qz = qz.swapaxes(0, 1)[:, ::-1]  # rotate by 90°

    # TODO use the standard matplotlib.tri.Triangulation, but it uses 3x more memory
    # also leaks, and is slower!
    #     triang = Triangulation(phi_data.flat, theta_data.flat)
    #     interp = LinearTriInterpolator(triang, omega_data.flat)
    #     xi, yi = numpy.meshgrid(numpy.linspace(-h_output_size, h_output_size, output_size),
    #                             numpy.linspace(-h_output_size, h_output_size, output_size))
    #     qz = interp(xi, yi)
    #     qz = qz[:, ::-1]

    result = model.DataArray(qz, data.metadata)

    return result
Exemplo n.º 11
0
def AngleResolved2Rectangular(data, output_size, hole=True, dtype=None):
    """
    Converts an angle resolved image to equirectangular (aka cylindrical)
      projection (ie, phi/theta axes)
    data (model.DataArray): The image that was projected on the CCD after being
      relfected on the parabolic mirror. The flat line of the D shape is
      expected to be horizontal, at the top. It needs PIXEL_SIZE and AR_POLE
      metadata. Pixel size is the sensor pixel size * binning / magnification.
    output_size (int, int): The size of the output DataArray (theta, phi),
      not including the theta/phi angles at the first row/column
    hole (boolean): Crop the pole if True
    dtype (numpy dtype): intermediary dtype for computing the theta/phi data
    returns (model.DataArray): converted image in equirectangular view
    """
    assert (len(data.shape) == 2)  # => 2D with greyscale

    # Get the metadata
    try:
        pixel_size = data.metadata[model.MD_PIXEL_SIZE]
        mirror_x, mirror_y = data.metadata[model.MD_AR_POLE]
        parabola_f = data.metadata.get(model.MD_AR_PARABOLA_F, AR_PARABOLA_F)
    except KeyError:
        raise ValueError("Metadata required: MD_PIXEL_SIZE, MD_AR_POLE.")

    if dtype is None:
        dtype = numpy.float64

    # Crop the input image to half circle
    cropped_image = _CropHalfCircle(data, pixel_size, (mirror_x, mirror_y),
                                    hole)

    theta_data = numpy.empty(shape=cropped_image.shape, dtype=dtype)
    phi_data = numpy.empty(shape=cropped_image.shape, dtype=dtype)
    omega_data = numpy.empty(shape=cropped_image.shape)

    # For each pixel of the input ndarray, input metadata is used to
    # calculate the corresponding theta, phi and radiant intensity
    image_x, image_y = cropped_image.shape
    jj = numpy.linspace(0, image_y - 1, image_y)
    xpix = mirror_x - jj

    for i in xrange(image_x):
        ypix = (i - mirror_y) + (2 * parabola_f) / pixel_size[1]
        theta, phi, omega = _FindAngle(data, xpix, ypix, pixel_size)

        theta_data[i, :] = theta
        phi_data[i, :] = phi
        omega_data[i, :] = cropped_image[i] / omega

    # compute new mask
    phi_lin = numpy.linspace(0, 2 * math.pi, output_size[1])
    theta_lin = numpy.linspace(0, math.pi / 2, output_size[0])
    phi_grid, theta_grid = numpy.meshgrid(phi_lin, theta_lin)

    a = (1 / (4 * parabola_f))
    xcut = AR_XMAX - AR_PARABOLA_F
    # length vector
    c = (2 * (a * numpy.cos(phi_grid) * numpy.sin(theta_grid) + a))**-1
    x = -numpy.sin(theta_grid) * numpy.cos(phi_grid) * c
    z = numpy.cos(theta_grid) * c

    mask = numpy.ones(output_size)
    mask[(x > xcut) | (theta_grid <
                       (4 * numpy.pi / 180)) | (z < AR_FOCUS_DISTANCE)] = 0
    # TODO: can probably choose a selection here to speed up interpolation.
    # This is a silly fix but it works. Prevents extrapolation which leads to errors
    theta_data = numpy.tile(theta_data, (1, 3))
    phi_data = numpy.append(numpy.append(phi_data - 2 * math.pi,
                                         phi_data,
                                         axis=1),
                            phi_data + 2 * math.pi,
                            axis=1)

    ARdata = numpy.tile(omega_data, (1, 3))
    with warnings.catch_warnings():
        # Some points might be so close that they are identical (within float
        # precision). It's fine, no need to generate a warning.
        warnings.simplefilter("ignore", DuplicatePointWarning)
        triang = Triangulation(phi_data.flat, theta_data.flat)
    interp = triang.linear_interpolator(ARdata.flat, default_value=0)
    qz = interp[0:numpy.pi / 2:complex(0, output_size[0]),
                0:2 * numpy.pi:complex(0, output_size[1])]
    qz = numpy.roll(qz, qz.shape[1] // 2, axis=1)
    qz_masked = qz * mask

    # TODO: put theta/phi angles in metadata?
    # attach theta as first column
    qz_masked = numpy.append(theta_lin.reshape(theta_lin.shape[0], 1),
                             qz_masked,
                             axis=1)
    # attach phi as first row
    phi_lin = numpy.append([[0]], phi_lin.reshape(1, phi_lin.shape[0]), axis=1)
    qz_masked = numpy.append(phi_lin, qz_masked, axis=0)
    result = model.DataArray(qz_masked, data.metadata)

    return result