[gdal-dev] Proposed Block iterator API
Even Rouault
even.rouault at spatialys.com
Fri Nov 20 13:35:31 PST 2015
Hi,
I was wondering if there wasn't a need for a block iterator API for code that
wants to process raster efficiently and iterates over blocks from top to bottom,
and left to write. Currently you have to create 2 for loops and deal with
partial blocks at edges (see
https://trac.osgeo.org/gdal/browser/trunk/gdal/gcore/rasterio.cpp#L3576).
Nothing really fundamentaly complicated, but I guess people have to often
write that boring code and I'm sure there a lot of occurences of it inside
GDAL itself. The API just returns the coordinates of the window, but doesn't
do the pixel queries (people could use it to operate on a single band, or
multiple bands)
An example on how to use the API is :
int main(int argc, char* argv[])
{
GDALAllRegister();
GDALDatasetH hDS = GDALOpen(argv[1], GA_ReadOnly);
GDALBlockIteratorH hIter = GDALCreateBlockIterator(
GDALGetRasterBand(hDS, 1));
int nXOff, nYOff, nXSize, nYSize;
while( GDALBlockIteratorGetNext(hIter, &nXOff, &nYOff, &nXSize, &nYSize) )
{
double dfProgressStart, dfProgressEnd;
dfProgressStart = GDALBlockIteratorGetProgress(hIter, &dfProgressEnd);
printf("nXOff=%d nYOff=%d nXSize=%d nYSize=%d [%.2f->%.2f]\n",
nXOff, nYOff, nXSize, nYSize, dfProgressStart, dfProgressEnd);
}
GDALDestroyBlockIterator(hIter);
GDALClose(hDS);
return 0;
}
And if you run it on a 20x20 raster with blocks of size 16x16, it will
display:
nXOff=0 nYOff=0 nXSize=16 nYSize=16 [0.00->64.00]
nXOff=16 nYOff=0 nXSize=4 nYSize=16 [64.00->80.00]
nXOff=0 nYOff=16 nXSize=16 nYSize=4 [80.00->96.00]
nXOff=16 nYOff=16 nXSize=4 nYSize=4 [96.00->100.00]:
Thoughts ?
Best regards,
Even
PS: below the API and its implementation
#include <gdal_priv.h>
/* API */
CPL_C_START
typedef struct GDALBlockIterator *GDALBlockIteratorH;
GDALBlockIteratorH CPL_DLL GDALCreateBlockIterator(GDALRasterBandH hBand);
void CPL_DLL GDALDestroyBlockIterator(GDALBlockIteratorH hIter);
int CPL_DLL GDALBlockIteratorGetMaxXSize(GDALBlockIteratorH hIter);
int CPL_DLL GDALBlockIteratorGetMaxYSize(GDALBlockIteratorH hIter);
void GDALBlockIteratorSetBlockSize(GDALBlockIterator* poIter, int nBlockWidth,
int nBlockHeight);
int CPL_DLL GDALBlockIteratorGetNext(GDALBlockIteratorH hIter,
int* pnXOff,
int* pnYOff,
int* pnXSize,
int* pnYSize);
double CPL_DLL GDALBlockIteratorGetProgress(GDALBlockIteratorH hIter, double*
pdfNextProgress);
CPL_C_END
/* Impl */
struct GDALBlockIterator
{
int nXSize;
int nYSize;
int nXOff;
int nYOff;
int nBlockWidth;
int nBlockHeight;
bool bFinished;
};
typedef struct GDALBlockIterator GDALBlockIterator;
GDALBlockIterator* GDALCreateBlockIterator(GDALRasterBandH hBand)
{
GDALRasterBand* poBand = (GDALRasterBand*)hBand;
GDALBlockIterator* poIter = new GDALBlockIterator;
poIter->nXSize = poBand->GetXSize();
poIter->nYSize = poBand->GetYSize();
poBand->GetBlockSize( &(poIter->nBlockWidth), &(poIter->nBlockHeight) );
poIter->nXOff = -1;
poIter->nYOff = 0;
poIter->bFinished = false;
return poIter;
}
void GDALDestroyBlockIterator(GDALBlockIteratorH hIter)
{
delete hIter;
}
int GDALBlockIteratorGetMaxXSize(GDALBlockIterator* poIter)
{
return poIter->nBlockWidth;
}
int GDALBlockIteratorGetMaxYSize(GDALBlockIterator* poIter)
{
return poIter->nBlockHeight;
}
void GDALBlockIteratorSetBlockSize(GDALBlockIterator* poIter, int nBlockWidth,
int nBlockHeight)
{
poIter->nBlockWidth = nBlockWidth;
poIter->nBlockHeight = nBlockHeight;
}
int GDALBlockIteratorGetNext(GDALBlockIterator* poIter,
int* pnXOff,
int* pnYOff,
int* pnXSize,
int* pnYSize)
{
if( poIter->bFinished )
return FALSE;
if( poIter->nXOff < 0 )
poIter->nXOff = 0;
else
poIter->nXOff += poIter->nBlockWidth;
if( poIter->nXOff >= poIter->nXSize )
{
poIter->nXOff = 0;
poIter->nYOff += poIter->nBlockHeight;
if( poIter->nYOff >= poIter->nYSize )
{
poIter->bFinished = true;
return FALSE;
}
}
if( pnXOff )
*pnXOff = poIter->nXOff;
if( pnYOff )
*pnYOff = poIter->nYOff;
if( pnXSize )
{
*pnXSize = poIter->nBlockWidth;
if( poIter->nXOff + poIter->nBlockWidth >= poIter->nXSize )
{
*pnXSize = poIter->nXSize - poIter->nXOff;
}
}
if( pnYSize )
{
*pnYSize = poIter->nBlockHeight;
if(poIter->nYOff + poIter->nBlockHeight >= poIter->nYSize )
{
*pnYSize = poIter->nYSize - poIter->nYOff;
}
}
return TRUE;
}
double GDALBlockIteratorGetProgress(GDALBlockIterator* poIter, double*
pdfNextProgress)
{
if( poIter->bFinished )
{
if( pdfNextProgress != NULL )
*pdfNextProgress = 100.0;
return 100.0;
}
int nBlockHeight = poIter->nBlockHeight;
if( poIter->nYOff + nBlockHeight > poIter->nYSize )
nBlockHeight = poIter->nYSize - poIter->nYOff;
double dfProcessedPixels = (double)poIter->nYOff * poIter->nXSize + poIter-
>nXOff * nBlockHeight;
double dfRet = 100.0 * dfProcessedPixels / poIter->nXSize / poIter-
>nYSize;
if( pdfNextProgress != NULL )
{
GDALBlockIterator sIterDup = *poIter;
GDALBlockIteratorGetNext(&sIterDup, NULL, NULL, NULL, NULL);
*pdfNextProgress = GDALBlockIteratorGetProgress(&sIterDup, NULL);
}
return dfRet;
}
--
Spatialys - Geospatial professional services
http://www.spatialys.com
More information about the gdal-dev
mailing list