Beispiel #1
0
def subaperture_processing_phase_history(phase_array,
                                         aperture_indices,
                                         output_resolution,
                                         dimension=0):
    """
    Perform the sub-aperture processing on the given complex phase history data.

    Parameters
    ----------
    phase_array : numpy.ndarray
        The complex array data. Dimension other than 2 is not supported.
    aperture_indices : Tuple[int, int]
        The start/stop indices for the subaperture processing.
    output_resolution : int
        The output resolution parameter.
    dimension : int
        The dimension along which to perform the sub-aperture processing. Must be
        one of 0 or 1.

    Returns
    -------
    numpy.ndarray
    """

    phase_array = _validate_input(phase_array)
    dimension = _validate_dimension(dimension)

    if dimension == 0:
        return ifft(phase_array[aperture_indices[0]:aperture_indices[1], :],
                    axis=0,
                    n=output_resolution)
    else:
        return ifft(phase_array[:, aperture_indices[0]:aperture_indices[1]],
                    axis=1,
                    n=output_resolution)
Beispiel #2
0
def _deweight_array(input_data, weight_array, oversample_rate, dimension):
    """
    Uniformly weight complex SAR data along the given dimension.

    Parameters
    ----------
    input_data : numpy.ndarray
    weight_array : numpy.ndarray
    oversample_rate : int|float
    dimension : int

    Returns
    -------
    numpy.ndarray
    """

    if weight_array is None:
        # nothing to be done
        return input_data

    weight_size = round(input_data.shape[dimension]/oversample_rate)
    if weight_array.ndim != 1:
        raise ValueError('weight_array must be one dimensional.')
    if weight_array.size != weight_size:
        weight_array = scipy.signal.resample(weight_array, weight_size)
    weight_ind_start = int_func(numpy.floor(0.5*(input_data.shape[dimension] - weight_size)))
    weight_ind_end = weight_ind_start + weight_size

    output_data = fftshift(fft(input_data, axis=dimension), axes=dimension)
    if dimension == 0:
        output_data[weight_ind_start:weight_ind_end, :] /= weight_array[:, numpy.newaxis]
    else:
        output_data[:, weight_ind_start:weight_ind_end] /= weight_array
    return ifft(ifftshift(output_data, axes=dimension), axis=dimension)
Beispiel #3
0
def apply_weight_array(input_data,
                       weight_array,
                       oversample_rate,
                       dimension,
                       inverse=False):
    """
    Apply the weight array along the given dimension.

    Parameters
    ----------
    input_data : numpy.ndarray
        The complex data array to weight.
    weight_array : numpy.ndarray
        The weight array.
    oversample_rate : int|float
        The oversample rate.
    dimension : int
        Along which dimension to apply the weighting? Must be one of `{0, 1}`.
    inverse : bool
        If `True`, this divides the weight (i.e. de-weight), otherwise it multiplies.

    Returns
    -------
    numpy.ndarray
    """

    if not (isinstance(input_data, numpy.ndarray) and input_data.ndim == 2):
        raise ValueError('The data array must be two-dimensional')

    if weight_array is None:
        # nothing to be done
        return input_data

    weight_array, weight_ind_start, weight_ind_end = determine_weight_array(
        input_data.shape, weight_array, oversample_rate, dimension)

    if inverse and numpy.any(weight_array == 0):
        raise ValueError(
            'inverse=True and the weight array contains some zero entries.')

    output_data = fftshift(fft(input_data, axis=dimension), axes=dimension)
    if dimension == 0:
        if inverse:
            output_data[weight_ind_start:
                        weight_ind_end, :] /= weight_array[:, numpy.newaxis]
        else:
            output_data[weight_ind_start:
                        weight_ind_end, :] *= weight_array[:, numpy.newaxis]
    else:
        if inverse:
            output_data[:, weight_ind_start:weight_ind_end] /= weight_array
        else:
            output_data[:, weight_ind_start:weight_ind_end] *= weight_array
    return ifft(ifftshift(output_data, axes=dimension), axis=dimension)
Beispiel #4
0
def csi_array(array, dimension=0, platform_direction='R', fill=1, filter_map=None):
    """
    Creates a color subaperture array from a complex array.

    .. Note: this ignores any potential sign issues for the fft and ifft, because
        the results would be identical - fft followed by ifft versus ifft followed
        by fft.

    Parameters
    ----------
    array : numpy.ndarray
        The complex valued SAR data, assumed to be in the "image" domain.
        Required to be two-dimensional.
    dimension : int
        The dimension over which to split the sub-aperture.
    platform_direction : str
        The (case insensitive) platform direction, required to be one of `('R', 'L')`.
    fill : float
        The fill factor. This will be ignored if `filter_map` is provided.
    filter_map : None|numpy.ndarray
        The RGB filter mapping. This is assumed constructed using :func:`filter_map_construction`.

    Returns
    -------
    numpy.ndarray
    """

    if not (isinstance(array, numpy.ndarray) and len(array.shape) == 2 and numpy.iscomplexobj(array)):
        raise ValueError('array must be a two-dimensional numpy array of complex dtype')

    dimension = int_func(dimension)
    if dimension not in [0, 1]:
        raise ValueError('dimension must be 0 or 1, got {}'.format(dimension))
    if dimension == 0:
        array = array.T

    pdir_func = platform_direction.upper()[0]
    if pdir_func not in ['R', 'L']:
        raise ValueError('It is expected that pdir is one of "R" or "L". Got {}'.format(platform_direction))

    # get our filter construction data
    if filter_map is None:
        fill = max(1.0, float(fill))
        filter_map = filter_map_construction(array.shape[1]/fill)
    if not (isinstance(filter_map, numpy.ndarray) and
            filter_map.dtype.name in ['float32', 'float64'] and
            filter_map.ndim == 2 and filter_map.shape[1] == 3):
        raise ValueError('filter_map must be a N x 3 numpy array of float dtype.')

    # move to phase history domain
    ph_indices = int(numpy.floor(0.5*(array.shape[1] - filter_map.shape[0]))) + \
                 numpy.arange(filter_map.shape[0], dtype=numpy.int32)
    ph0 = fftshift(ifft(numpy.cast[numpy.complex128](array), axis=1), axes=1)[:, ph_indices]
    # construct the filtered workspace
    # NB: processing is more efficient with color band in the first dimension
    ph0_RGB = numpy.zeros((3, array.shape[0], filter_map.shape[0]), dtype=numpy.complex128)
    for i in range(3):
        ph0_RGB[i, :, :] = ph0*filter_map[:, i]
    del ph0

    # Shift phase history to avoid having zeropad in middle of filter, to alleviate
    # the purple sidelobe artifact.
    filter_shift = int(numpy.ceil(0.25*filter_map.shape[0]))
    ph0_RGB[0, :] = numpy.roll(ph0_RGB[0, :], -filter_shift)
    ph0_RGB[2, :] = numpy.roll(ph0_RGB[2, :], filter_shift)
    # NB: the green band is already centered

    # FFT back to the image domain
    im0_RGB = fft(fftshift(ph0_RGB, axes=2), n=array.shape[1], axis=2)
    del ph0_RGB

    # Replace the intensity with the original image intensity to main full resolution
    # (in intensity, but not in color).
    scale_factor = numpy.abs(array)/numpy.abs(im0_RGB).max(axis=0)
    im0_RGB = numpy.abs(im0_RGB)*scale_factor

    # reorient image so that the color segment is in the final dimension
    if dimension == 0:
        im0_RGB = im0_RGB.transpose([2, 1, 0])
    else:
        im0_RGB = im0_RGB.transpose([1, 2, 0])
    if pdir_func == 'R':
        # reverse the color band order
        im0_RGB = im0_RGB[:, :, ::-1]
    return im0_RGB