Beispiel #1
0
def _convolve_2d_cupy(data, kernel):
    data = data.astype(cupy.float32)
    out = cupy.empty(data.shape, dtype='f4')
    out[:, :] = cupy.nan
    griddim, blockdim = cuda_args(data.shape)
    _convolve_2d_cuda[griddim, blockdim](data, kernel, cupy.asarray(out))
    return out
def _evi_cupy(nir_data, red_data, blue_data, c1, c2, soil_factor, gain):
    griddim, blockdim = cuda_args(nir_data.shape)
    out = cupy.empty(nir_data.shape, dtype='f4')
    out[:] = cupy.nan
    args = (nir_data, red_data, blue_data, c1, c2, soil_factor, gain, out)
    _evi_gpu[griddim, blockdim](*args)
    return out
Beispiel #3
0
def _run_cupy(data, azimuth, angle_altitude):
    x, y = np.gradient(data.get())
    x = cupy.asarray(x, dtype=x.dtype)
    y = cupy.asarray(y, dtype=y.dtype)

    altituderad = angle_altitude * np.pi / 180.
    sin_altituderad = np.sin(altituderad)
    cos_altituderad = np.cos(altituderad)

    griddim, blockdim = cuda_args(data.shape)
    arctan_part = cupy.empty(data.shape, dtype='f4')
    _gpu_calc[griddim, blockdim](x, y, arctan_part)

    slope = np.pi / 2. - np.arctan(arctan_part)
    sin_slope = np.sin(slope)
    sin_part = sin_altituderad * sin_slope

    azimuthrad = (360.0 - azimuth) * np.pi / 180.
    aspect = (azimuthrad - np.pi / 2.) - np.arctan2(-x, y)
    cos_aspect = np.cos(aspect)
    cos_slope = np.cos(slope)

    cos_part = cupy.empty(data.shape, dtype='f4')
    _gpu_cos_part[griddim, blockdim](cos_altituderad, cos_slope,
                                     cos_aspect, cos_part)
    shaded = sin_part + cos_part
    out = (shaded + 1) / 2

    out[0, :] = cupy.nan
    out[-1, :] = cupy.nan
    out[:, 0] = cupy.nan
    out[:, -1] = cupy.nan

    return out
Beispiel #4
0
def _terrain_gpu(height_map, seed, x_range=(0, 1), y_range=(0, 1)):

    NOISE_LAYERS = ((1 / 2**i, (2**i, 2**i)) for i in range(16))

    noise = cupy.empty_like(height_map, dtype=np.float32)

    griddim, blockdim = cuda_args(height_map.shape)

    for i, (m, (xfreq, yfreq)) in enumerate(NOISE_LAYERS):

        # cupy.random.seed(seed+i)
        # p = cupy.random.permutation(2**20)

        # use numpy.random then transfer data to GPU to ensure the same result
        # when running numpy backed and cupy backed data array.
        np.random.seed(seed + i)
        p = cupy.asarray(np.random.permutation(2**20))
        p = cupy.append(p, p)

        _perlin_gpu[griddim,
                    blockdim](p, x_range[0] * xfreq, x_range[1] * xfreq,
                              y_range[0] * yfreq, y_range[1] * yfreq, m, noise)

        height_map += noise

    height_map /= (1.00 + 0.50 + 0.25 + 0.13 + 0.06 + 0.03)
    height_map = height_map**3
    return height_map
Beispiel #5
0
def _run_cupy_binary(data, values):
    values_cupy = cupy.asarray(values)
    out = cupy.empty(data.shape, dtype='f4')
    out[:] = cupy.nan
    griddim, blockdim = cuda_args(data.shape)
    _run_gpu_binary[griddim, blockdim](data, values_cupy, out)
    return out
Beispiel #6
0
def convolve_2d(image, kernel, pad=True, use_cuda=True):
    """Function to call the 2D convolution via Numba.
    The Numba convolution function does not account for an edge so
    if we wish to take this into account, will pad the image array.
    """
    # Don't allow padding on (1, 1) kernel
    if (kernel.shape[0] == 1 and kernel.shape[1] == 1):
        pad = False

    if pad:
        pad_rows = kernel.shape[0] // 2
        pad_cols = kernel.shape[1] // 2
        pad_width = ((pad_rows, pad_rows), (pad_cols, pad_cols))
    else:
        # If padding is not desired, set pads to 0
        pad_rows = 0
        pad_cols = 0
        pad_width = 0

    padded_image = np.pad(image, pad_width=pad_width, mode="reflect")
    result = np.empty_like(padded_image)

    if has_cuda() and use_cuda:
        griddim, blockdim = cuda_args(padded_image.shape)
        _convolve_2d_cuda[griddim, blockdim](result, kernel, padded_image)
    else:
        result = _convolve_2d(kernel, padded_image)

    if pad:
        result = result[pad_rows:-pad_rows, pad_cols:-pad_cols]

    if result.shape != image.shape:
        raise ValueError("Output and input rasters are not the same shape.")

    return result
Beispiel #7
0
def _run_cupy(data: cupy.ndarray) -> cupy.ndarray:
    data = data.astype(cupy.float32)
    griddim, blockdim = cuda_args(data.shape)
    out = cupy.empty(data.shape, dtype='f4')
    out[:] = cupy.nan
    _run_gpu[griddim, blockdim](data, out)
    return out
Beispiel #8
0
def savi(nir_agg, red_agg, soil_factor=1.0, name='savi', use_cuda=True, use_cupy=True):
    """Returns Soil Adjusted Vegetation Index (SAVI).

    Parameters
    ----------
    nir_agg : DataArray
        near-infrared band data

    red_agg : DataArray
        red band data

    soil_factor : float
      soil adjustment factor between -1.0 and 1.0.
      when set to zero, savi will return the same as ndvi

    Returns
    -------
    data: DataArray

    Notes:
    ------
    Algorithm References:
     - https://www.sciencedirect.com/science/article/abs/pii/003442578890106X
    """
    _check_is_dataarray(nir_agg, 'near-infrared')
    _check_is_dataarray(red_agg, 'red')

    if not red_agg.shape == nir_agg.shape:
        raise ValueError("red_agg and nir_agg expected to have equal shapes")

    if soil_factor > 1.0 or soil_factor < -1.0:
        raise ValueError("soil factor must be between (-1.0, 1.0)")

    nir_data = nir_agg.data
    red_data = red_agg.data

    if has_cuda() and use_cuda:
        griddim, blockdim = cuda_args(nir_data.shape)
        soil_factor_arr = np.array([float(soil_factor)], dtype='f4')

        out = np.empty(nir_data.shape, dtype='f4')
        out[:] = np.nan

        if use_cupy:
            import cupy
            out = cupy.asarray(out)

        _savi_gpu[griddim, blockdim](nir_data,
                                     red_data,
                                     soil_factor_arr,
                                     out)
    else:
        out = _savi(nir_agg.data, red_agg.data, soil_factor)

    return DataArray(out,
                     name=name,
                     coords=nir_agg.coords,
                     dims=nir_agg.dims,
                     attrs=nir_agg.attrs)
Beispiel #9
0
def _run_cupy_bin(data, bins, new_values):
    bins_cupy = cupy.asarray(bins)
    new_values_cupy = cupy.asarray(new_values)
    out = cupy.empty(data.shape, dtype='f4')
    out[:] = cupy.nan
    griddim, blockdim = cuda_args(data.shape)
    _run_gpu_bin[griddim, blockdim](data, bins_cupy, new_values_cupy, out)
    return out
Beispiel #10
0
def _mean_cupy(data, excludes):
    out = cupy.zeros_like(data)
    out[:, :] = cupy.nan
    griddim, blockdim = cuda_args(data.shape)
    out = cupy.empty(data.shape, dtype='f4')
    out[:] = cupy.nan

    _mean_gpu[griddim, blockdim](data, cupy.asarray(excludes), out)

    return out
Beispiel #11
0
def _run_cupy(data: cupy.ndarray, cellsize_x: Union[int, float],
              cellsize_y: Union[int, float]) -> cupy.ndarray:
    cellsize_x_arr = cupy.array([float(cellsize_x)], dtype='f4')
    cellsize_y_arr = cupy.array([float(cellsize_y)], dtype='f4')

    griddim, blockdim = cuda_args(data.shape)
    out = cupy.empty(data.shape, dtype='f4')
    out[:] = cupy.nan

    _run_gpu[griddim, blockdim](data, cellsize_x_arr, cellsize_y_arr, out)
    return out
Beispiel #12
0
def sipi(nir_agg, red_agg, blue_agg, name='sipi', use_cuda=True, use_cupy=True):
    """Computes Structure Insensitive Pigment Index which helpful
    in early disease detection

    Parameters
    ----------
    nir_agg : DataArray
        near-infrared band data

    green_agg : DataArray
        green band data

    Returns
    -------
    data: DataArray

    Notes:
    ------
    Algorithm References:
    https://en.wikipedia.org/wiki/Enhanced_vegetation_index
    """

    _check_is_dataarray(nir_agg, 'near-infrared')
    _check_is_dataarray(red_agg, 'red')
    _check_is_dataarray(blue_agg, 'blue')

    if not red_agg.shape == nir_agg.shape == blue_agg.shape:
        raise ValueError("input layers expected to have equal shapes")

    nir_data = nir_agg.data
    red_data = red_agg.data
    blue_data = blue_agg.data

    if has_cuda() and use_cuda:
        griddim, blockdim = cuda_args(nir_data.shape)
        out = np.empty(nir_data.shape, dtype='f4')
        out[:] = np.nan

        if use_cupy:
            import cupy
            out = cupy.asarray(out)

        _sipi_gpu[griddim, blockdim](nir_data,
                                     red_data,
                                     blue_data,
                                     out)
    else:
        out = _sipi(nir_data, red_data, blue_data)

    return DataArray(out,
                     name=name,
                     coords=nir_agg.coords,
                     dims=nir_agg.dims,
                     attrs=nir_agg.attrs)
Beispiel #13
0
def _run_cupy_bin(data, bins, new_values):
    # replace inf by nan to avoid classify these values as we want to treat them as outliers
    data = cupy.where(data == cupy.inf, cupy.nan, data)
    data = cupy.where(data == -cupy.inf, cupy.nan, data)

    bins_cupy = cupy.asarray(bins)
    new_values_cupy = cupy.asarray(new_values)
    out = cupy.empty(data.shape, dtype='f4')
    out[:] = cupy.nan
    griddim, blockdim = cuda_args(data.shape)
    _run_gpu_bin[griddim, blockdim](data, bins_cupy, new_values_cupy, out)
    return out
def _run_cupy(data: cupy.ndarray, cellsize: Union[int, float]) -> cupy.ndarray:

    cellsize_arr = cupy.array([float(cellsize)], dtype='f4')

    # TODO: add padding
    griddim, blockdim = cuda_args(data.shape)
    out = cupy.empty(data.shape, dtype='f4')
    out[:] = cupy.nan

    _run_gpu[griddim, blockdim](data, cellsize_arr, out)

    return out
Beispiel #15
0
def ebbi(red_agg, swir_agg, tir_agg, name='ebbi', use_cuda=True, use_cupy=True):
    """Computes Enhanced Built-Up and Bareness Index
    Parameters
    ----------
    red_agg : DataArray
        red band data
    swir_agg : DataArray
        shortwave infrared band data
    tir_agg : DataArray
        thermal infrared band data
    Returns
    -------
    data: DataArray
    Notes:
    ------
    Algorithm References:
    https://rdrr.io/cran/LSRS/man/EBBI.html
    """

    _check_is_dataarray(red_agg, 'red')
    _check_is_dataarray(swir_agg, 'swir')
    _check_is_dataarray(tir_agg, 'thermal infrared')

    if not red_agg.shape == swir_agg.shape == tir_agg.shape:
        raise ValueError("input layers expected to have equal shapes")

    red_data = red_agg.data
    swir_data = swir_agg.data
    tir_data = tir_agg.data

    if has_cuda() and use_cuda:
        griddim, blockdim = cuda_args(red_data.shape)
        out = np.empty(red_data.shape, dtype='f4')
        out[:] = np.nan

        if use_cupy:
            import cupy
            out = cupy.asarray(out)

        _sipi_gpu[griddim, blockdim](red_data,
                                     swir_data,
                                     tir_data,
                                     out)
    else:
        out = _sipi(red_data, swir_data, tir_data)

    return DataArray(out,
                     name=name,
                     coords=red_agg.coords,
                     dims=red_agg.dims,
                     attrs=red_agg.attrs)
Beispiel #16
0
def _run_normalized_ratio(arr1, arr2, use_cuda=True, use_cupy=True):

    if has_cuda() and use_cuda:
        griddim, blockdim = cuda_args(arr1.shape)
        out = np.empty(arr1.shape, dtype='f4')
        out[:] = np.nan

        if use_cupy:
            import cupy
            out = cupy.asarray(out)

        _normalized_ratio_gpu[griddim, blockdim](arr1, arr2, out)
    else:
        out = _normalized_ratio(arr1, arr2)
    
    return out
Beispiel #17
0
def _perlin_cupy(data: cupy.ndarray, freq: tuple, seed: int) -> cupy.ndarray:

    # cupy.random.seed(seed)
    # p = cupy.random.permutation(2**20)

    # use numpy.random then transfer data to GPU to ensure the same result
    # when running numpy backed and cupy backed data array.
    np.random.seed(seed)
    p = cupy.asarray(np.random.permutation(2**20))
    p = cupy.append(p, p)

    griddim, blockdim = cuda_args(data.shape)
    _perlin_gpu[griddim, blockdim](p, 0, freq[0], 0, freq[1], 1, data)

    minimum = cupy.amin(data)
    maximum = cupy.amax(data)
    data[:] = (data - minimum) / (maximum - minimum)
    return data
Beispiel #18
0
def _run_cupy(d_data, azimuth, angle_altitude):
    # Precompute constant values shared between all threads
    altituderad = angle_altitude * np.pi / 180.
    sin_altituderad = np.sin(altituderad)
    cos_altituderad = np.cos(altituderad)
    azimuthrad = (360.0 - azimuth) * np.pi / 180.

    # Allocate output buffer and launch kernel with appropriate dimensions
    output = cupy.empty(d_data.shape, np.float32)
    griddim, blockdim = cuda_args(d_data.shape)
    _gpu_calc_numba[griddim, blockdim](d_data, output, sin_altituderad,
                                       cos_altituderad, azimuthrad)

    # Fill borders with nans.
    output[0, :] = cupy.nan
    output[-1, :] = cupy.nan
    output[:, 0] = cupy.nan
    output[:, -1] = cupy.nan

    return output
Beispiel #19
0
def _hotspots_cupy(raster, kernel):
    if not (issubclass(raster.data.dtype.type, cupy.integer)
            or issubclass(raster.data.dtype.type, cupy.floating)):
        raise ValueError("data type must be integer or float")

    data = raster.data.astype(cupy.float32)

    # apply kernel to raster values
    mean_array = convolve_2d(data, kernel / kernel.sum())

    # calculate z-scores
    global_mean = cupy.nanmean(data)
    global_std = cupy.nanstd(data)
    if global_std == 0:
        raise ZeroDivisionError(
            "Standard deviation of the input raster values is 0.")
    z_array = (mean_array - global_mean) / global_std

    out = cupy.zeros_like(z_array, dtype=cupy.int8)
    griddim, blockdim = cuda_args(z_array.shape)
    _run_gpu_hotspots[griddim, blockdim](z_array, out)
    return out
Beispiel #20
0
def _run_cupy(data: cupy.ndarray,
              cellsize_x: Union[int, float],
              cellsize_y: Union[int, float]) -> cupy.ndarray:

    cellsize_x_arr = cupy.array([float(cellsize_x)], dtype='f4')
    cellsize_y_arr = cupy.array([float(cellsize_y)], dtype='f4')

    pad_rows = 3 // 2
    pad_cols = 3 // 2
    pad_width = ((pad_rows, pad_rows),
                (pad_cols, pad_cols))

    slope_data = np.pad(data, pad_width=pad_width, mode="reflect")

    griddim, blockdim = cuda_args(slope_data.shape)
    slope_agg = cupy.empty(slope_data.shape, dtype='f4')
    slope_agg[:] = cupy.nan

    _run_gpu[griddim, blockdim](slope_data,
                                cellsize_x_arr,
                                cellsize_y_arr,
                                slope_agg)
    out = slope_agg[pad_rows:-pad_rows, pad_cols:-pad_cols]
    return out
def _gci_cupy(nir_data, green_data):
    griddim, blockdim = cuda_args(nir_data.shape)
    out = cupy.empty(nir_data.shape, dtype='f4')
    out[:] = cupy.nan
    _gci_gpu[griddim, blockdim](nir_data, green_data, out)
    return out
Beispiel #22
0
def aspect(agg, name='aspect', use_cuda=True, pad=True, use_cupy=True):
    """Returns downward slope direction in compass degrees (0 - 360) with 0 at 12 o'clock.

    Parameters
    ----------
    agg : DataArray

    Returns
    -------
    data: DataArray

    Notes:
    ------
    Algorithm References:
     - http://desktop.arcgis.com/en/arcmap/10.3/tools/spatial-analyst-toolbox/how-aspect-works.htm#ESRI_SECTION1_4198691F8852475A9F4BC71246579FAA
     - Burrough, P. A., and McDonell, R. A., 1998. Principles of Geographical Information Systems (Oxford University Press, New York), pp 406
    """

    if not isinstance(agg, DataArray):
        raise TypeError("agg must be instance of DataArray")

    if has_cuda() and use_cuda:

        if pad:
            pad_rows = 3 // 2
            pad_cols = 3 // 2
            pad_width = ((pad_rows, pad_rows),
                        (pad_cols, pad_cols))
        else:
            # If padding is not desired, set pads to 0
            pad_rows = 0
            pad_cols = 0
            pad_width = 0

        data = np.pad(agg.data, pad_width=pad_width, mode="reflect")

        griddim, blockdim = cuda_args(data.shape)
        out = np.empty(data.shape, dtype='f4')
        out[:] = np.nan

        if use_cupy:
            import cupy
            out = cupy.asarray(out)

        _horn_aspect_cuda[griddim, blockdim](data, out)
        if pad:
            out = out[pad_rows:-pad_rows, pad_cols:-pad_cols]

    elif isinstance(agg.data, da.Array):
        out = agg.data.map_overlap(_horn_aspect,
                                   depth=(1, 1),
                                   boundary=np.nan,
                                   meta=np.array(()))
    else:
        out = _horn_aspect(agg.data)

    return DataArray(out,
                     name=name,
                     dims=agg.dims,
                     coords=agg.coords,
                     attrs=agg.attrs)
def _ebbi_cupy(red_data, swir_data, tir_data):
    griddim, blockdim = cuda_args(red_data.shape)
    out = cupy.empty(red_data.shape, dtype='f4')
    out[:] = cupy.nan
    _ebbi_gpu[griddim, blockdim](red_data, swir_data, tir_data, out)
    return out
Beispiel #24
0
def _focal_stats_func_cupy(data, kernel, func=_focal_max_cuda):
    out = cupy.empty(data.shape, dtype='f4')
    out[:, :] = cupy.nan
    griddim, blockdim = cuda_args(data.shape)
    func[griddim, blockdim](data, kernel, cupy.asarray(out))
    return out
Beispiel #25
0
def convolve_2d(image: xr.DataArray,
                kernel,
                pad=True,
                use_cuda=True) -> xr.DataArray:
    """
    Calculates, for all inner cells of an array, the 2D convolution of
    each cell via Numba. To account for edge cells, a pad can be added
    to the image array. Convolution is frequently used for image
    processing, such as smoothing, sharpening, and edge detection of
    images by elimatig spurious data or enhancing features in the data.

    Parameters:
    ----------
    image: xarray.DataArray
        2D array of values to processed and padded.
    kernel: array-like object
        Impulse kernel, determines area to apply
        impulse function for each cell.
    pad: Boolean
        To compute edges set to True.
    use-cuda: Boolean
        For parallel computing set to True.

    Returns:
    ----------
    convolve_agg: xarray.DataArray
        2D array representation of the impulse function.
        All other input attributes are preserverd.
    
    Examples:
    ----------
    Imports
    >>> import numpy as np
    >>> import xarray as xr
    >>> from xrspatial import convolution, focal

    Create Data Array
    >>> agg = xr.DataArray(np.array([[0, 0, 0, 0, 0, 0, 0],
    >>>                              [0, 0, 2, 4, 0, 8, 0],
    >>>                              [0, 2, 2, 4, 6, 8, 0],
    >>>                              [0, 4, 4, 4, 6, 8, 0],
    >>>                              [0, 6, 6, 6, 6, 8, 0],
    >>>                              [0, 8, 8, 8, 8, 8, 0],
    >>>                              [0, 0, 0, 0, 0, 0, 0]]),
    >>>                     dims = ["lat", "lon"],
    >>>                     attrs = dict(res = 1))
    >>> height, width = agg.shape
    >>> _lon = np.linspace(0, width - 1, width)
    >>> _lat = np.linspace(0, height - 1, height)
    >>> agg["lon"] = _lon
    >>> agg["lat"] = _lat

        Create Kernel
    >>> kernel = focal.circle_kernel(1, 1, 1)

        Create Convolution Data Array
    >>> print(convolution.convolve_2d(agg, kernel))
    [[ 0.  0.  4.  8.  0. 16.  0.]
     [ 0.  4.  8. 10. 18. 16. 16.]
     [ 4.  8. 14. 20. 24. 30. 16.]
     [ 8. 16. 20. 24. 30. 30. 16.]
     [12. 24. 30. 30. 34. 30. 16.]
     [16. 22. 30. 30. 30. 24. 16.]
     [ 0. 16. 16. 16. 16. 16.  0.]]
    """
    # Don't allow padding on (1, 1) kernel
    if (kernel.shape[0] == 1 and kernel.shape[1] == 1):
        pad = False

    if pad:
        pad_rows = kernel.shape[0] // 2
        pad_cols = kernel.shape[1] // 2
        pad_width = ((pad_rows, pad_rows), (pad_cols, pad_cols))
    else:
        # If padding is not desired, set pads to 0
        pad_rows = 0
        pad_cols = 0
        pad_width = 0

    padded_image = np.pad(image, pad_width=pad_width, mode="reflect")
    result = np.empty_like(padded_image)

    if has_cuda() and use_cuda:
        griddim, blockdim = cuda_args(padded_image.shape)
        _convolve_2d_cuda[griddim, blockdim](result, kernel, padded_image)
    else:
        result = _convolve_2d(kernel, padded_image)

    if pad:
        result = result[pad_rows:-pad_rows, pad_cols:-pad_cols]

    if result.shape != image.shape:
        raise ValueError("Output and input rasters are not the same shape.")

    return result
def _savi_cupy(nir_data, red_data, soil_factor):
    griddim, blockdim = cuda_args(nir_data.shape)
    out = cupy.empty(nir_data.shape, dtype='f4')
    out[:] = cupy.nan
    _savi_gpu[griddim, blockdim](nir_data, red_data, soil_factor, out)
    return out
def _run_normalized_ratio_cupy(arr1, arr2):
    griddim, blockdim = cuda_args(arr1.shape)
    out = cupy.empty(arr1.shape, dtype='f4')
    out[:] = cupy.nan
    _normalized_ratio_gpu[griddim, blockdim](arr1, arr2, out)
    return out
def _arvi_cupy(nir_data, red_data, blue_data):
    griddim, blockdim = cuda_args(nir_data.shape)
    out = cupy.empty(nir_data.shape, dtype='f4')
    out[:] = cupy.nan
    _arvi_gpu[griddim, blockdim](nir_data, red_data, blue_data, out)
    return out