question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

using `cog_translate` on netCDF4 with improper georeferencing

See original GitHub issue

I am trying to use cog_translate to convert some netCDF4 datasets to COG, and it appears these files do not have proper georeferencing.

I have modified cogeo.py to accept vrt_params, so that I can manually pass the src_crs and src_transform via the WarpedVRTReaderBase mixin of WarpedVRT, as you can see here:

https://github.com/ryanjdillon/rio-cogeo/blob/cog_translate_vrt_params/rio_cogeo/cogeo.py#L87-L99

Then I’m passing the following vrt_params:

vrt_params = dict(src_transform=Affine(gdal_geotransform), src_crs='EPSG:4326')

This get’s me past the CRS is None error, but it doesn’t seem to acknowledge the Affine transform I pass to src_transform, resulting in the following error:

CPLE_AppDefinedError: The transformation is already “north up” or a transformation between pixel/line and georeferenced coordinates cannot be computed for /home/ryan/data/webstep/kvt/NVE_Sorlandet/NVE_Sorlandet_wslev0_xyt_synth.nc4. There is no affine transformation and no GCPs. Specify transformation option SRC_METHOD=NO_GEOTRANSFORM to bypass this check.

Any suggestions on how I might get this to work?

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:12 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
vincentsaragocommented, Nov 14, 2019

@ryanjdillon Long time no see 😄 I finally had to work with netcdf recently and thanks to some recent change in rio-cogeo we can now pass Memory or VRT files to cog_translate.

  • Latest version
def translate(
    src_path,
    cog_path,
    cogeo_profile="deflate",
    cogeo_options={"blockxsize": 128, "blockysize": 128, "predictor": 2, "zlevel": 7},
):
    """Convert a netcdf to COG."""
    config = dict(GDAL_NUM_THREADS="ALL_CPUS", GDAL_TIFF_OVR_BLOCKSIZE="128")

    with rasterio.Env(**config):
        with rasterio.open(src_path) as src_dst:
            with WarpedVRT(
                src_dst,
                crs="epsg:4326",
                warp_mem_limit=0.1,   # Reduce chunk size, see: https://github.com/OSGeo/gdal/issues/1989
                num_threads=8
            ) as vrt:
                profile = cog_profiles.get(cogeo_profile)
                profile.update(cogeo_options)
                cog_translate(
                    vrt,
                    cog_path,
                    profile,
                    config=config,
                    in_memory=True,
                    quiet=True,
                )
  • First version
def translate(
    src_path,
    cog_path,
    cogeo_profile="deflate",
    cogeo_options={"blockxsize": 128, "blockysize": 128, "predictor": 2, "zlevel": 7},
):
    """Convert a netcdf to COG."""
    config = dict(GDAL_NUM_THREADS="ALL_CPUS", GDAL_TIFF_OVR_BLOCKSIZE="128")

    with rasterio.Env(**config):
        with rasterio.open(src_path) as src_dst:
            dst_transform, dst_width, dst_height = calculate_default_transform(
                src_dst.crs, "epsg:4326", src_dst.width, src_dst.height, *src_dst.bounds
            )
            meta = dict(
                driver="GTiff",
                dtype=src_dst.dtypes[0],
                count=src_dst.count,
                height=dst_height,
                width=dst_width,
                crs="epsg:4326",
                transform=dst_transform,
                nodata=-999,
                tiled=True,
                compress="deflate",
                blockxsize=256,
                blockysize=256,
            )
            with MemoryFile() as memfile:
                with memfile.open(**meta) as mem:
                    reproject(
                        rasterio.band(src_dst, 1),
                        rasterio.band(mem, 1),
                        resampling=rasterio.enums.Resampling.nearest,
                        warp_mem_limit=1,  # Reduce chunk size, see: https://github.com/OSGeo/gdal/issues/1989
                        num_threads=8,
                    )
                    mem.update_tags(**src_dst.tags(1))
                    profile = cog_profiles.get(cogeo_profile)
                    profile.update(cogeo_options)
                    cog_translate(
                        mem,
                        cog_path,
                        profile,
                        config=config,
                        in_memory=True,
                        quiet=True,
                    )

since we can use MemoryFile or VRT, we can now fix the data upfront and pass it to cog_translate so I think we can close this issue.

1reaction
vincentsaragocommented, Apr 10, 2019

🤔 thanks @ryanjdillon,

I also tried using cog_validate on the generated tiff, and it bugged out when src.get_tag_item(“BLOCK_OFFSET_0_0”, “TIFF”, bidx=1) was None.

Can you checkout what https://svn.osgeo.org/gdal/trunk/gdal/swig/python/samples/validate_cloud_optimized_geotiff.py gives you ?

I could submit a PR if you want to look over / incorporate these changes

Allowing vrt_params as input might complicated a lot the code (especially with the changes from https://github.com/cogeotiff/rio-cogeo/pull/62). That said, I think we could document it and tell how to generate a proper temporary file from the netCDF4 before passing it to rio-cogeo.

I’m no expert with netCDF so I’m may be missing some knowledge here

Read more comments on GitHub >

github_iconTop Results From Across the Web

Converting a netCDF4 file to (georeferenced) GeoTIFF ...
It appears the approximately command line to do this is gdal_translate -ot float32 -unscale -CO COMPRESS=deflate -of GTiff -a_srs EPSG:4326 ...
Read more >
Fundamentals of georeferencing a raster dataset—Help
When you georeference your raster data, you define its location using map coordinates and assign the coordinate system of the data frame.
Read more >
netCDF4 API documentation
netCDF defines the sizes of all variables in terms of dimensions, so before any variables can be created the dimensions they use must...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found