[Geoserver-devel] Raster Reprojection

I am trying (unsuccessfully) to add raster reprojection support into uDig. I am not quite sure what I am doing wrong. I tried to look at the raster reprojection support in GeoServer-WCS, but I couldn't see anything revealing there -- perhaps I missed it.

Here is my basic workflow:

1. Transform the viewport's bounding box ("viewportBBox") into something the WMS will understand ("requestBBox")

2. Retrieve image from WMS

3. Wrap the image up in a GridCoverage2D, giving it the "requestBBox" and the request's CRS

4. Create a map context and set its AreaOfInterest to the viewportBBox/CRS

5. Call paint on LiteRenderer2, giving it the bounding box of the viewport. (I am unsure what BBox to give it here - the javadocs say nothing!)

However, this doesn't seem to actually reproject the raster. The image that appears on screen is exactly the same as I get back from the WMS.

(See attached image)

Here is what my code looks like:

GridCoverageFactory factory = new GridCoverageFactory();

GridCoverage gc = factory.create(
  "GridCoverage",
  image,
  CRS.decode(findRequestCRS()), //is this right?
  gtRequestBBox); //or should this be viewportBBox??

Rectangle paintArea = new Rectangle(getOffset().x, getOffset().y, dimension.width, dimension.height);

MapContext mapContext = new DefaultMapContext();
mapContext.addLayer(gc, style);
mapContext.setAreaOfInterest(getViewportBBox(), getViewportCRS()); //is this right?

LiteRenderer2 lite = new LiteRenderer2(mapContext);
lite.paint(destination, paintArea, getViewportBBox());

Thanks for any help,

Richard

(attachments)

Screenshot.png

Hi Richard,
I think that the problem is that actually Literenderer2 does not support reprojection for raster. In other words, when you tell to the Literenderer2 to render a raster, it rendres the raster as is without anything else. It actually uses GridCoverageRenderer. I have inspected it, but I didn’t find any code for raster reprojection.

Another problem is : is it correct to reproject raster on the fly? This operation may require a lot of time … maybe the client should reproject rasters? I don’t know … however even in the GeoServer-WCS we will have to support raster reprojection in some way … we don’t at the moment.

On 6/4/05, Richard Gould <rgould@anonymised.com> wrote:

I am trying (unsuccessfully) to add raster reprojection support into
uDig. I am not quite sure what I am doing wrong. I tried to look at the
raster reprojection support in GeoServer-WCS, but I couldn’t see
anything revealing there – perhaps I missed it.

Here is my basic workflow:

  1. Transform the viewport’s bounding box (“viewportBBox”) into something
    the WMS will understand (“requestBBox”)

  2. Retrieve image from WMS

  3. Wrap the image up in a GridCoverage2D, giving it the “requestBBox”
    and the request’s CRS

  4. Create a map context and set its AreaOfInterest to the viewportBBox/CRS

  5. Call paint on LiteRenderer2, giving it the bounding box of the
    viewport. (I am unsure what BBox to give it here - the javadocs say
    nothing!)

However, this doesn’t seem to actually reproject the raster. The image
that appears on screen is exactly the same as I get back from the WMS.

(See attached image)

Here is what my code looks like:

GridCoverageFactory factory = new GridCoverageFactory();

GridCoverage gc = factory.create(
“GridCoverage”,
image,
CRS.decode(findRequestCRS()), //is this right?
gtRequestBBox); //or should this be viewportBBox??

Rectangle paintArea = new Rectangle(getOffset().x, getOffset().y,
dimension.width, dimension.height);

MapContext mapContext = new DefaultMapContext();
mapContext.addLayer(gc, style);
mapContext.setAreaOfInterest(getViewportBBox(), getViewportCRS()); //is
this right?

LiteRenderer2 lite = new LiteRenderer2(mapContext);
lite.paint(destination, paintArea, getViewportBBox());

Thanks for any help,

Richard

Alessio Fabiani wrote:

Hi Richard,
I think that the problem is that actually Literenderer2 does not support reprojection for raster. In other words, when you tell to the Literenderer2 to render a raster, it rendres the raster as is without anything else. It actually uses GridCoverageRenderer. I have inspected it, but I didn't find any code for raster reprojection.

I have not had a look at your code yet, but I here is what I thought was going on.
1. A GridCoverage needs to be rendererd
2. For every pixel on screen calculate there is a mapping through JAI down to the pixel information (possibly split into bands)

The "mapping" is the interesting part, and the part where "raster reprojection" fits in. So what we need is to insert our reprojection code in the middle of step two.

If LiteRenderer2 does not yet do this we can search in the codebase for where J2D does this kind of work (as you can see when you run the spearfish demo).

Another problem is : is it correct to reproject raster on the fly?

I am fairly sure it is - after all the alternative would be to load the whole image into memory - and we have the occasional 60 meg image file to play with.

operation may require a lot of time ... maybe the client should reproject rasters? I don't know ... however even in the GeoServer-WCS we will have to support raster reprojection in some way ... we don't at the moment.

If you think about it as a bandwidth problem, either between disk and the screen, or between geoserver WCS and clients it is fairly clear that we should be doing reprojection on the fly.

My understanding is the MapServer code base does a few tricks in terms of reprojecting scan line end points and doing a bit of a comparison to see where a linear approximentation would be able to pay off.

Jody Garnett

Alession is right; LiteRenderer do not yet reproject rasters as far as I know. J2D implements that, but the real work is actually done by the GridCoverage "Resample" operation. J2D renderer doesn't do much more than just invoking this "Resample" operation and cache the result.

The "Resample" operation is documented here:

http://modules.geotools.org/main/apidocs/org/geotools/coverage/processing/package-summary.html#Resample

There is an example about how to reproject a raster to targetCRS:

GridCoverage2D raster = ...
CoordinateReferenceSystem targetCRS = ...
GridCoverageProcessor2D processor = GridCoverageProcessor2D.getDefault();
GridCoverage2D projected = processor.doOperation("Resample", raster, "CoordinateReferenceSystem", targetCRS);

You can have more control if you also provide the "GridGeometry" argument. If you don't, a default GridGeometry will be infered from the source raster.

You may also try to play with the "InterpolationType" argument and see if it improves the projection quality.

Jody Garnett a écrit :

Another problem is : is it correct to reproject raster on the fly?

I am fairly sure it is - after all the alternative would be to load the whole image into memory - and we have the occasional 60 meg image file to play with.

JAI (which is used for most GridCoverage2D operations) splits images in tiles. Only the required tiles will be loaded and computed. However, it will work only if GridCoverageExchange (or Format, or whatever code is used for loading images) take tiles in account. I have not yet looked at the GridCoverageExchange code to see if it is the case, but we should be able to improve the code in that direction.

  Martin.

Alessio Fabiani wrote:

Hi Richard,
I think that the problem is that actually Literenderer2 does not support reprojection for raster. In other words, when you tell to the Literenderer2 to render a raster, it rendres the raster as is without anything else. It actually uses GridCoverageRenderer. I have inspected it, but I didn't find any code for raster reprojection.

As far as I remember, you just have to set the destination CRS in the rendered layer.

Another problem is : is it correct to reproject raster on the fly? This operation may require a lot of time ... maybe the client should reproject rasters? I don't know ... however even in the GeoServer-WCS we will have to support raster reprojection in some way ... we don't at the moment.

No, it's not so bad, provided that the GridCoverageRenderer doesn't get disposed (but gets reused, instead).
The reprojection is performed by JAI, this means that resulting tiles will be cached, as long as the complete
JAI operator chain that leads to the reprojected tiles is not disposed. This means that you'll have at
least to keep a weak cache of GridCoverageRenderers in the lite renderer to allow for reuse.
Sorry I don't remember the details, it has been six months since I've last worked on lite2.

Best regards
Andrea Aime