Perceived WCS inaccuracy

Working with WCS I discovered a small but noticable shift of data in all three major OSS WCS applications:

  • Geoserver 2.0 (SNAPSHOT downloaded 8 december 10.19UTC)
  • Mapserver 5.6.0 (MS4W Base installer v3.0 Beta 7 + MapServer 5.6.0 release Upgrade)
  • Deegree 2.3rc1 (Apache Tomcat 5.5.28)

To find out what the problem exactly was I’ve done some testing. I’ve taken a GeoTiff and configured all three the WCS applications to serve it. Gdalinfo gives us the following information, basically it is a GeoTIFF in epsg:3035 with a native resolution of 100m/pixel.

My test sequence was:

  1. request the full extent in native resolution
  2. request the full extent in a 10th of the resolution
  3. request the full extent with the same size as the original data (256×256)
  4. request part of the data in native resolution
  5. request part of the data in non-native, non-multiple resolution

I’m not going to show all the results here, because that would result in an unhealthy long document ;)

To verify the results I loaded the original GeoTiff in Quantum GIS and highlighted a specific feature to show the possible offset of the different results.

Corine GeoTiff

Corine GeoTiff

1  request the full extent in native resolution:

deegree: http://localhost:8080/deegree-wcs1/services?service=WCS&version=1.0.0&request=GetCoverage&coverage=Corine&crs=EPSG:3035&BBOX=3539200,3402400,3564800,3428000&resx=100&resy=100&format=GeoTIFF gives a three band(!) GeoTiff of 262,674 bytes with a shift of around 40m:

deegreefull

Deegree result

MapServer: http://localhost/cgi-bin/mapserver56/mapserv.exe?map=maps/corine.map&service=WCS&version=1.0.0&request=GetCoverage&coverage=Corine&crs=EPSG:3035&BBOX=3539200,3402400,3564800,3428000&resx=100&resy=100&format=GTiff gives a three band(!) GeoTiff of 197,477 bytes without a shift:

Mapserver result

Mapserver result

GeoServer: http://localhsot:8081/geoserver/ows?service=WCS&version=1.0.0&request=GetCoverage&coverage=corine_merge_gtiff_proj_121_108&crs=EPSG:3035&BBOX=3539200,3402400,3564800,3428000&resx=100&resy=100&format=GeoTiff gives a single band GeoTiff of 8,848 bytes with a shift of  around 50m:

Geoserver result

Geoserver result

Note:

Deegree both shifts the data and returns a multi-band image; Mapserver doesn’t shift the data, but returns a multi-band image; Geoserver shifts the data 1/2 a pixel (50m), but does give a single band image.

2. request the full extent in a 10th of the resolution

deegree: http://localhost:8080/deegree-wcs1/services?service=WCS&version=1.0.0&request=GetCoverage&coverage=Corine&crs=EPSG:3035&BBOX=3539200,3402400,3564800,3428000&resx=10&resy=10&format=GeoTIFF produces a 26,237,726 multi band GeoTiff which shifts the data the other way than the first request:

Deegree result on a tenth of the resolution

Deegree result on a tenth of the resolution

Mapserver: http://localhost/cgi-bin/mapserver56/mapserv.exe?map=maps/corine.map&service=WCS&version=1.0.0&request=GetCoverage&coverage=Corine&crs=EPSG:3035&BBOX=3539200,3402400,3564800,3428000&resx=10&resy=10&format=GTiff produces a multi-band GeoTiff of 19,681,941 bytes with no shift.

Geoserver: http://localhost:8081/geoserver/ows?service=WCS&version=1.0.0&request=GetCoverage&coverage=corine_merge_gtiff_proj_121_108&crs=EPSG:3035&BBOX=3539200,3402400,3564800,3428000&resx=10&resy=10&format=GeoTiff gives a single band GeoTiff of 158,802 bytes with a shift of around 50m, though there is a small difference with the previous result.

Note:

Mapserver and Geoserver both produce a bigger result (as expected) with the same location as the previous request. Deegree shifts the data differently than previously and also produces a bigger result.

3. request the full extent with the same size as the original data (256×256)

geoserver: http://localhost:8081/geoserver/ows?service=WCS&version=1.0.0&request=GetCoverage&coverage=corine_merge_gtiff_proj_121_108&crs=EPSG:3035&BBOX=3539200,3402400,3564800,3428000&width=256&height=256&format=GeoTiff produces exactly the same image as in the first request.

mapserver: http://localhost/cgi-bin/mapserver56/mapserv.exe?map=maps/corine.map&service=WCS&version=1.0.0&request=GetCoverage&coverage=Corine&crs=EPSG:3035&BBOX=3539200,3402400,3564800,3428000&width=256&height=256&format=GTiff produces exactly the same image as in the first request.

deegree: http://localhost:8080/deegree-wcs1/services?service=WCS&version=1.0.0&request=GetCoverage&coverage=Corine&crs=EPSG:3035&BBOX=3539200,3402400,3564800,3428000&width=256&height=256&format=GeoTIFF produces a slightly smaller image than the first request (262,674 bytes) with no shift!.

Deegree result with width en height

Deegree result with width en height

Note:

Since the request is a different way of describing the same data one would expect that you get the same results. Mapserver and Geoserver do so, Deegree does not, somehow using resx and resy in the request results in shifted data.

4. request part of the data in native resolution

deegree: http://localhost:8080/deegree-wcs1/services?service=WCS&version=1.0.0&request=GetCoverage&coverage=Corine&resx=100&resy=100&crs=EPSG:3035&BBOX=3550000,3413200,3554000,3417200&format=GeoTIFF has the correct left-top location but the size of the pixels is wrong, producing a shift of the data which increases as you go right/down:

Deegree result for a part request

Deegree result for a part request

geoserver: http://localhost:8081/geoserver/ows?service=WCS&request=GetCoverage&format=GeoTiff&version=1.0.0&coverage=geodan:Corine&resx=100&resy=100&crs=EPSG:3035&BBOX=3550000,3413200,3554000,3417200 produces an image with almost exactly the same shift as the first request.
mapserver: http://localhost/cgi-bin/mapserver56/mapserv.exe?map=maps/corine.map&service=WCS&version=1.0.0&request=GetCoverage&coverage=Corine&resx=100&resy=100&crs=EPSG:3035&BBOX=3550000,3413200,3554000,3417200&format=GTiff produces an image with almost exactly the same location as the first request.

Note:

Mapserver and Geoserver shift (or not) the data similar to the first request, Deegree has once again a different shift than any of the previous ones.

5. request part of the data in non-native, non-multiple resolution

deegree: http://localhost:8080/deegree-wcs1/services?service=WCS&version=1.0.0&request=GetCoverage&coverage=Corine&resx=30.0&resy=30.0&crs=EPSG:3035&BBOX=3550000,3413200,3554000,3417200&format=GeoTIFF shifts data:

Deegree result for non native, non multiple=

geoserver: http://localhost:8081/geoserver/ows?service=WCS&request=GetCoverage&format=GeoTiff&version=1.0.0&coverage=geodan:Corine&resx=30.0&resy=30.0&crs=EPSG:3035&BBOX=3550000,3413200,3554000,3417200 shifts data and adds a black border to the left and top of the result:

Geoserver result for non-native, non-multiple resolution

Geoserver result for non-native, non-multiple resolution

mapserver: http://localhost/cgi-bin/mapserver56/mapserv.exe?map=maps/corine.map&service=WCS&version=1.0.0&request=GetCoverage&coverage=Corine&resx=30.0&resy=30.0&crs=EPSG:3035&BBOX=3550000,3413200,3554000,3417200&format=GTiff shifts data:

Mapserver result for non-native, non-multiple resolution

Mapserver result for non-native, non-multiple resolution

Note:

This request was my initial prompt to find out why all WCS applications shift the data in the results. However this is a false conclusion. What’s happening here is that the service has to extract 30m wide pixels from 100m wide source data, since 100 divided by 30 isn’t a whole number it will add the remaining 10m in an adjacent pixel. If you overlay the result and the source data you get a pixel problem, data of source pixel 2 will most likely end up in result pixel b, which is partly over source pixel 1, resulting in a data shift:

Overlapping 100m with 30m

Overlapping 100m with 30m

Conclusion:

Geoserver has a bug feature which offsets all the results by half a pixel, this is a known issue with the definition of the location of a pixel. Added to this there’s the no-data border which appears with non-native, non-multiple requests. I presume that will be gone once the pixel issue is resolved. (update: apparently I’ve misunderstood the Geoserver developers; there’s an issue between pixel placement according to standards and real world implementations, where Geoserver adheres to the standard).

Mapserver doesn’t offset the data unless it is physically impossible (non-native, non-multiple resolutions, extents which don’t snap to source data) but produces a multi-band (this was a configuration issue, thanks to FrankW for spotting this – proper config is IMAGEMODE BYTE) geotiff where the source data is single band.

Deegree has a bug which offsets some of the results, but I don’t know what causes it and although it is resolution-related I don’t see a pattern. It also produces a multi-band geotiff instead of a single band.

Configuration files and source data can be found here.

Geoserver 2.0 SNAPSHOT downloaded 8 december 10.19 UTC


Open Source, web