On 09/19/2014 01:50 PM, Peter Hopfgartner wrote:
On 09/18/2014 10:30 PM, Even Rouault wrote:
Le jeudi 18 septembre 2014 22:23:06, Peter Hopfgartner a écrit :
Salut Evan,

thanks for you recipe. Unfortunately, what I am really interested in is to use this from MapServer. Could you give me a pointer in the source where
the resampling takes place?
In gcore/rasterio.cpp : GDALRasterBand::IRasterIO(). I must warn you : quite
tricky code

But perhaps you don't need code change. In MapServer did you try to define
PROCESSING "RESAMPLE=BILINEAR" ?

Thanks,

Peter

Am 18.09.2014 um 22:11 schrieb Even Rouault <even.roua...@spatialys.com>:
Le jeudi 18 septembre 2014 17:40:11, Peter Hopfgartner a écrit :
Hi, everybody

we are using the GDAL WMS driver for getting maps from a public WMTS
service, http://www.basemap.at. Anyway, the resulting image does not
look smooth. In particular, I would guess that the the image was scaled
with something like a nearest neighbor algorithm.
So my question is simply, if I can switch the interpolation method in
some place.

The XML file, taken from
http://gisforge.wordpress.com/2012/11/06/basemap-at-wmts-layer-in-qgis/,
is:

<GDAL_WMS>

  <Service name="TMS">

<ServerUrl>http://maps.wien.gv.at/basemap/geolandbasemap/normal/google38
57/ ${z}/${y}/${x}.jpeg</ServerUrl> </Service>

  <DataWindow>
     <UpperLeftX>-20037508.34</UpperLeftX>
   <UpperLeftY>20037508.34</UpperLeftY>
   <LowerRightX>20037508.34</LowerRightX>
   <LowerRightY>-20037508.34</LowerRightY>
   <TileLevel>18</TileLevel>
   <TileCountX>1</TileCountX>
   <TileCountY>1</TileCountY>
   <YOrigin>top</YOrigin>
    </DataWindow>
  <Projection>EPSG:3857</Projection>
  <BlockSizeX>256</BlockSizeX>
  <BlockSizeY>256</BlockSizeY>
  <BandsCount>3</BandsCount>
  <Cache />

</GDAL_WMS>

The command is:

gdal_translate -srcwin 35500000 23500000 100000 100000 -of JPEG -outsize
250 250 basemap_at.xml basemap_at.jpg
Peter,

Resampling done by gdal_translate is nearest neighbour, so not always
that great.

What you can do is select an outsize that is compatible with the source overviews. In TMS, the ratio between sucessive overviews work with factor
of 2, so you should select an outsize of 10000 / 2^N. The closest is
10000 / 256 = 390.625 -> 391

So

gdal_translate -srcwin 35500000 23500000 100000 100000 -outsize
391 391 basemap_at.xml tmp.tif

and then:

gdalwarp tmp.tif tmp2.tif -r lanczos -ts 250 250 (you can try different
resampling kernel)
gdal_translate tmp2.tif basemap_at.jpg -of JPEG

Best regards,

Even
I've tried to simulate the result of different algorithms to further investigate the idea of having a configurable resampling step. The original tile is 256 x 256 pixels and I've rescaled it to rescale it to 200x200 using Gimp.

The original tile was taken from http://maps.wien.gv.at/basemap/geolandbasemap/normal/google3857/8/89/137.jpg, a copy is stored at https://dl.dropboxusercontent.com/u/4935329/resampling_tests/137.jpg.

Results
no interpolation, (nearest neighbor?): https://dl.dropboxusercontent.com/u/4935329/resampling_tests/137.resampled_to_200.px-noint.png bilinear: https://dl.dropboxusercontent.com/u/4935329/resampling_tests/137.resampled_to_200.px-linear.png bicubic: https://dl.dropboxusercontent.com/u/4935329/resampling_tests/137.resampled_to_200.px-cubic.png lanczos: https://dl.dropboxusercontent.com/u/4935329/resampling_tests/137.resampled_to_200.px-lanczos.png

I'd say that the quality of the resampling respects the obove order, with lanczos being the best.

Regards,

Peter

I finally took the time to have a better look at this.

The attached patch is only for our special case, where data arrives in 8 bit bands and is certainly far from being decent (I've written my last C++ code approx. 15 years ago). Anyway, the image quality seems indeed to improve sensibly.

I used the current SVN version as a base for the development.

Applying the patch I get from https://dl.dropboxusercontent.com/u/4935329/resampling_tests/basemap.2000x2000-quasiorig.jpg to this https://dl.dropboxusercontent.com/u/4935329/resampling_tests/basemap.2000x2000.bilinear.jpg .

Anyway, the execution time approximatly doubles (on my 2011 notebook it passes from ~ 1.8 s to ~ 3.4 s), which in our case is not really an issue, but probaly for almost everybody else.

The command line is, starting from the compilation dir:

apps/gdal_translate -srcwin 35555000 23538000 2500 2500 -of JPEG -outsize 2000 2000 basemap.xml basemap.2000x2000.bilinear.jpg .

Any comment is highly appreciated.

Regards and a nice weekend,

Peter

--
Peter Hopfgartner
R3 GIS
web  : http://www.r3-gis.com

Index: gcore/rasterio.cpp
===================================================================
--- gcore/rasterio.cpp	(revision 27739)
+++ gcore/rasterio.cpp	(working copy)
@@ -70,7 +70,7 @@
     GByte       *pabySrcBlock = NULL;
     GDALRasterBlock *poBlock = NULL;
     int         nLBlockX=-1, nLBlockY=-1, iBufYOff, iBufXOff, iSrcY;
-    
+
     if( eRWFlag == GF_Write && eFlushBlockErr != CE_None )
     {
         CPLError(eFlushBlockErr, CPLE_AppDefined,
@@ -368,7 +368,7 @@
 
             for( iDstX = nXOff; iDstX < nXOff + nXSize; iDstX ++)
             {
-                iBufXOff = (int)((iDstX - nXOff) / dfSrcXInc);
+                iBufXOff = (int)((iDstX - nXOff) / dfSrcXInc);                
                 iBufOffset = (size_t)iBufYOff * nLineSpace + iBufXOff * nPixelSpace;
 
     /* -------------------------------------------------------------------- */
@@ -448,10 +448,10 @@
 
             dfSrcY = (iBufYOff+0.5) * dfSrcYInc + nYOff;
             dfSrcX = 0.5 * dfSrcXInc + nXOff;
+            double dFracY = fmod(dfSrcY, 1.0);
             iSrcY = (int) dfSrcY;
 
             iBufOffset = (size_t)iBufYOff * nLineSpace;
-
             if( iSrcY >= nLimitBlockY )
             {
                 nLBlockY = iSrcY / nBlockYSize;
@@ -462,12 +462,22 @@
                 nStartBlockX = -nBlockXSize; /* make sure a new block is loaded */
 
             size_t iSrcOffsetCst = (iSrcY - nLBlockY*nBlockYSize) * (size_t)nBlockXSize;
+            size_t iSrcOffsetCstTop;
+            
+            size_t iSrcYTop;
+            if ( iSrcY <  nLimitBlockY - 1 ) {
+                iSrcYTop = iSrcY + 1;
+                iSrcOffsetCstTop = (iSrcYTop - nLBlockY*nBlockYSize) * (size_t)nBlockXSize;
+            } else {
+                iSrcYTop = iSrcY;
+                iSrcOffsetCstTop = iSrcOffsetCst;
+            }
 
             for( iBufXOff = 0; iBufXOff < nBufXSize; iBufXOff++, dfSrcX += dfSrcXInc )
             {
                 iSrcX = (int) dfSrcX;
+                double dFracX = fmod(dfSrcX, 1.0);
                 int nDiffX = iSrcX - nStartBlockX;
-
     /* -------------------------------------------------------------------- */
     /*      Ensure we have the appropriate block loaded.                    */
     /* -------------------------------------------------------------------- */
@@ -494,15 +504,37 @@
                         return CE_Failure;
                     }
                 }
+                int nDiffXRight;
+                if (nDiffXRight < nBlockXSize - 1) {
+                    nDiffXRight = nDiffX + 1;
+                } else {
+                    nDiffXRight = nDiffX;
+                }
 
     /* -------------------------------------------------------------------- */
     /*      Copy over this pixel of data.                                   */
     /* -------------------------------------------------------------------- */
                 iSrcOffset = ((size_t)nDiffX + iSrcOffsetCst)*nBandDataSize;
-
                 if( bByteCopy )
                 {
-                    ((GByte *) pData)[iBufOffset] = pabySrcBlock[iSrcOffset];
+                    size_t iSrcOffsetBR = ((size_t)nDiffXRight + iSrcOffsetCst)*nBandDataSize;
+                    size_t iSrcOffsetTL = ((size_t)nDiffX + iSrcOffsetCstTop)*nBandDataSize;
+                    size_t iSrcOffsetTR = ((size_t)nDiffXRight + iSrcOffsetCstTop)*nBandDataSize;
+
+                    unsigned char ucVal;
+                    if (eDataType == GDT_Byte) {
+                        unsigned char v00, v01, v10, v11;
+                        v00 = pabySrcBlock[iSrcOffset];
+                        v01 = pabySrcBlock[iSrcOffsetBR];
+                        v10 = pabySrcBlock[iSrcOffsetTL];
+                        v11 = pabySrcBlock[iSrcOffsetTR];
+
+                        double valY0 = double(v00) * (1 - dFracX) + double(v01) * dFracX;
+                        double valY1 = double(v10) * (1 - dFracX) + double(v11) * dFracX;
+                        double dVal = valY0 * (1 - dFracY) + valY1 * dFracY;
+                        ucVal = (unsigned char)round(dVal);
+                    }
+                    ((GByte *) pData)[iBufOffset] = ucVal;
                 }
                 else if( eDataType == eBufType )
                 {
_______________________________________________
gdal-dev mailing list
gdal-dev@lists.osgeo.org
http://lists.osgeo.org/mailman/listinfo/gdal-dev

Reply via email to