Giter Site home page Giter Site logo

danieljdufour / geowarp Goto Github PK

View Code? Open in Web Editor NEW
36.0 4.0 2.0 218 KB

Super Low-Level Raster Reprojection and Resampling Library

License: Creative Commons Zero v1.0 Universal

JavaScript 78.56% TypeScript 20.88% Shell 0.56%
gis maps geospatial imagery geotiff

geowarp's Introduction

Hi there ๐Ÿ‘‹

Here are Some Things that I'm Working on:

GeoSpatial ๐ŸŒ geotiff.io, georaster, georaster-layer-for-leaflet, geoblaze, geoblaze-cli, geotiff-stats, get-epsg-code, proj4-fully-loaded, reproject-bbox, and geowarp

Language Processing ๐Ÿ“š date-extractor, language-detector

Compression ๐Ÿ“€ dynachar, fast-bin, fast-rle, rle-serializers, fast-max, fast-min, fast-counter

Environment Management ๐ŸŒฑ djenv, simple-env

Small Python Libraries: ๐Ÿ prune, shear

Small JavaScript Libraries : ๐Ÿฅ easy-script-loader, easy-file-saver, flug, get-byte, xml-utils

geowarp's People

Contributors

danieljdufour avatar tomerigal avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

geowarp's Issues

take proj-turbo to the next level

might be able to use proj-turbo to discover simple affine translation/scale between image points (i.e. [I, J]) in input data to image points in output data

bilinear resampling method outputs a distorted image

Hi,
I have found that the bilinear resampling method outputs a distorted image.
I have included a comparison image (left: using geotiff.js, right: using geotiff-tile) to demonstrate the issue.

(open in new window)
image

Test script to reproduce (using geotiff-tile):

<!DOCTYPE html>
<html>
  <head>
    <script src="./node_modules/chroma-js/chroma.min.js"></script>
    <script src="./node_modules/flug/index.js"></script>
    <script src="./node_modules/geotiff/dist-browser/geotiff.js"></script>
    <script src="./dist/web/geotiff-tile.min.js"></script>
    <script>
      window.process = {
        env: {
          // TEST_NAME: "pulling tile from 3-band Geographic GeoTIFF as layout [row][column][band]"
        }
      }
    </script>
  </head>
  <body>
    <script>
      function three_to_four_bands({ tile, height, width }) {
        const data = new Array(4 * height * width).fill(255);
        for (let b = 0; b <= 2; b++) {
          for (let r = 0; r < height; r++) {
            for (let c = 0; c < width; c++) {
              data[(r * 4 * width) + (4 * c) + b] = tile[b][r][c];
            }
          }
        }
        return data;
      }

      function displayTile({ tile, height, width }) {
        const data = Uint8ClampedArray.from(tile);
        const imageData = new ImageData(data, width, height);
        const canvas = document.createElement("CANVAS");
        canvas.height = imageData.height;
        canvas.width = imageData.width;
        const context = canvas.getContext("2d");
        context.webkitImageSmoothingEnabled = false;
        context.mozImageSmoothingEnabled = false;
        context.imageSmoothingEnabled = false;
        context.putImageData(imageData, 0, 0);
        context.webkitImageSmoothingEnabled = false;
        context.mozImageSmoothingEnabled = false;
        context.imageSmoothingEnabled = false;
        document.body.appendChild(canvas);
        canvas.style.background = "darkred";
        canvas.style.border = "5px solid chartreuse";
        canvas.style.margin = "10px";
        // canvas.style.height = "512px";
      }

      test("resampling", async ({ eq }) => {
        const geotiff = await GeoTIFF.fromUrl("./ndvi2.tiff");
        const scale = 5;
        const _image = await geotiff.getImage();
        const rasters = await geotiff.readRasters({
          window: [0, 0, _image.getWidth(), _image.getHeight()],
          interleave: true,
          width: _image.getWidth() * scale,
          height: _image.getHeight() * scale,
          resampleMethod: "bilinear"
        });
        
        displayTile({ tile: rasters, height: _image.getHeight() * scale, width: _image.getWidth() * scale });

        const { height, width, tile } = await geotiff_tile.createTile({
          debug_level: 0,
          geotiff,
          bbox: _image.getBoundingBox(),
          bbox_srs: _image.geoKeys.ProjectedCSTypeGeoKey,
          method: "bilinear",
          round: true,
          tile_height: _image.getHeight() * scale,
          tile_array_types_strategy: "auto",
          tile_srs: _image.geoKeys.ProjectedCSTypeGeoKey,
          tile_width: _image.getWidth() * scale,
          timed: true
        });
        
        eq(tile[0].constructor.name, "Uint8Array");
        const data = new Uint8Array(tile[0].length * 4);

        for (let i = 0; i < tile[0].length; i++) {
          data[i * 4] = tile[0][i];
          data[i * 4 + 1] = tile[1][i];
          data[i * 4 + 2] = tile[2][i];
          data[i * 4 + 3] = tile[3][i];
        }


        displayTile({ tile: data, height: _image.getHeight() * scale, width: _image.getWidth() * scale });
      });
    </script>
  </body>
</html>

cache functions

useful if functions need to make a call to another thread

perhaps, turn off by default for performance reasons and add flag for it like
{
...
cache_functions: true
...
}

Add forward and inverse as params

So if you don't specify the out_bbox, it can use forward to reproject the in_bbox to out_srs

reproject will be deprecated and aliased to inverse

Output Viewport Does Not Match out_bbox

I am trying to warp this GeoTiff into EPSG:4326 to generate a tile for Mapbox.

input

Parsing with georaster seems to give the expected result:

  height: 570,
  width: 501,
  pixelHeight: 56,
  pixelWidth: 56,
  xmin: 450278,
  xmax: 478334,
  ymax: 1891090,
  ymin: 1859170,

When I geowarp() with these params, I get a correctly sized result that looks like the projection of a small piece of the top left corner of the source raster:

  const georaster = await parseGeoraster('https://nassgeodata.gmu.edu/webservice/nass_data_cache/CDL_2008_clip_20220323194315_1211782049.tif')

  const options = {
    left: 0,
    top: 0,
    right: georaster.width,
    bottom: georaster.height,
    width: georaster.width,
    height: georaster.height,
  }

  const values = await georaster.getValues(options)

  const result = geowarp({
    debug_level: 2,
    forward: albersConicalEqualArea.inverse,
    inverse: albersConicalEqualArea.forward,
    in_data: values[0],
    in_bbox: [xmin, ymin, xmax, ymax],
    in_layout: '[row][column,band]',
    in_pixel_depth: 1,
    in_srs: ALBERS_CONICAL_EQUAL_AREA,
    in_width: georaster.pixelWidth,
    in_height: georaster.pixelHeight,
    out_bbox: [west, south, east, north],
    out_layout: '[row][column,band]',
    out_srs: 4326,
    out_height: 256,
    out_width: 256,
    method: 'near',
    round: false,
    theoretical_min: 0,
    theoretical_max: 255,
  })

The requested output bbox is a direct projection of the bbox in the source tiff:

[geowarp] out_xmin: -90.703125
[geowarp] out_ymin: 39.6395375643667
[geowarp] out_xmax: -90.3515625
[geowarp] out_ymax: 39.909736234537185

The result is the correct size, but does not appear to match the requested output bbox:
temp

The result looks to be a projected version of a small, top left piece of the input tiff:
Screen Shot 2022-03-23 at 7 04 12 PM

enable proj4js objects / wkt

Maybe users should be able to pass in projection information for in_srs and out_srs instead of providing forward and inverse. Pro would be wouldn't need to rpc back up to main thread if running in a worker (without another library intercepting requests). Con would be increased maintenance cost and complexity. Not sure if this should be handled by a plugin/decorator or not.

warp from whole earth in 3857 to whole earth in 4326

{
    "cutline_srs": 4326,
    "debug_level": 9,
    "in_data": [...],
    "in_bbox": [
        -20057076.25595305,
        -10058531.080539025,
        20057076.18809704,
        12640208.839021027
    ],
    "in_geotransform": [
        -20057076.25595305,
        39135.75848200009,
        0,
        12640208.839021027,
        0,
        -39135.75848200009
    ],
    "in_layout": "[band][row,column]",
    "in_srs": 3857,
    "in_width": 1025,
    "in_height": 580,
    "method": "near-vectorize",
    "out_array_types": [
        "Array",
        "Array",
        "Uint8Array"
    ],
    "out_bbox": [
        -180,
        -90,
        180,
        90
    ],
    "out_height": 180,
    "out_layout": "[band][row][column]",
    "out_no_data": null,
    "out_resolution": [
        1,
        1
    ],
    "out_srs": 4326,
    "out_width": 360,
    "round": true,
    "theoretical_max": 255,
    "theoretical_min": 0,
    "turbo": false
}

expr returning null, undefined, or NaN strategy

if an expr returns null or undefined or NaN, we should follow a defined strategy

expr_nullish_strategy
"skip" - just skip inserting
"no-data" - replace with out_no_data if available and proceed as normal
"none" - don't do anything, pass along value to everything else

add mask as option

mask should probably use dufour-peyton intersection algorithm

would also need mask_srs and mask_forward to project from mask_srs to out_srs

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.