module GDAL::RasterBand::AlgorithmExtensions

RasterBand methods for doing warp-like things, but not using GDAL’s Warp API.

Public Instance Methods

simple_erase!() { |pixel_num, line_num, pixel_value| ... } click to toggle source

A method that doesn’t use GDAL’s Warp API for erasing pixels (setting to NODATA) in the method-owning RasterBand. It simply iterates over all of the valued pixels (ones that aren’t NODATA pixels) and yields them to a block. The return value of the block tells the method whether to keep the pixel or not: a truthy return value keeps the pixel; a false value sets the pixel value to the band’s NODATA value. If there’s no NODATA value set, it will raise an exception.

A typical clip operation would be from checking to see if the RasterBand’s pixel is within some Polygon. Doing so would look like:

@example Clipping by polygon

contrived_wkt = 'POLYGON ((0 0, 0 20, 20 20, 20 0, 0 0))'
polygon = OGR::Geometry.create_from_wkt(contrived_wkt)

# Note the 'w' to open for writing!
dataset = GDAL::Dataset.open('my.tif', 'w')
geo_transform = dataset.geo_transform
test_point = OGR::Point.new

dataset.raster_band(1).simple_erase! do |pixel_num, line_num|
  # Project the pixel using the dataset's GeoTransform
  projected_point_values = geo_transform.apply_geo_transform(pixel_num, line_num)
  test_point.set_point(projected_point_values[:x_geo], projected_point_values[:y_geo])

  test_point.within? polygon
end

# Make sure to close the dataset so the changes get flushed to disk.
dataset.close

You could, however use any other criteria in the block for erasing points away. The method also the pixel value in case you can use it for erasing. Perhaps, for example, you want to remove all pixels in the upper left quadrant of your raster that have a value less than 0. That would look like:

@example Erasing using pixel location and values

dataset = GDAL::Dataset.open('my.tif', 'w')
raster_band = dataset.raster_band(1)

raster_band.simple_erase! do |x, y, value|
  if x < (raster_band.x_size / 2) && y < (raster_band.y_size / 2) && value.negative?
    false
  else
    true
  end
end

@return [Integer] The number of pixels that were erased.

# File lib/gdal/extensions/raster_band/algorithm_extensions.rb, line 62
def simple_erase!
  erase_value = no_data_value[:value]
  write_buffer = GDAL._buffer_from_data_type(data_type, x_size)
  erased_pixel_count = 0

  unless erase_value
    raise GDAL::NoRasterEraseValue,
          "Cannot erase values, RasterBand does not have a NODATA value set"
  end

  y_size.times do |line_num|
    pixel_row = raster_io("r", x_size: x_size, y_size: 1, x_offset: 0, y_offset: line_num)
    pixel_values = GDAL._read_pointer(pixel_row, data_type, x_size)
    row_changed = false
    pixel_num = 0

    while pixel_num < pixel_values.length
      pixel_value = pixel_values[pixel_num]
      next if pixel_value == no_data_value[:value]

      keep_in_raster = yield(pixel_num, line_num, pixel_value)
      next if keep_in_raster

      erased_pixel_count += 1
      pixel_values[pixel_num] = erase_value
      row_changed = true
      pixel_num += 1
    end

    rewrite_pixel_row(write_buffer, pixel_values, line_num) if row_changed
  end

  erased_pixel_count
end

Private Instance Methods

rewrite_pixel_row(write_buffer, pixel_values, line_number) click to toggle source

@param write_buffer [FFI::Buffer] @param pixel_values [Array<Number>] @param line_number [Integer]

# File lib/gdal/extensions/raster_band/algorithm_extensions.rb, line 102
def rewrite_pixel_row(write_buffer, pixel_values, line_number)
  GDAL._write_pointer(write_buffer, data_type, pixel_values)
  raster_io("w", write_buffer, x_size: x_size, y_size: 1, y_offset: line_number)
  write_buffer.clear
end