[gdal-dev] Raster calculation optimalisation

Paul Meems bontepaarden at gmail.com
Tue Jun 13 04:20:24 PDT 2017


 I'm using GDAL v2.1.3 with the SWIG bindings in my custom C# application.

I've created a method to do some calculation of my raster file:
public bool GdalCalculate(string input, string output, string formula,
double? minValue = null)
{
    if (!File.Exists(input))
        throw new FileNotFoundException("Can't find the input file", new
Exception("Working with " + input));

    // 1. First copy the input file to create the output file
    try
    {
        /*
-------------------------------------------------------------------- */
        /*      Get driver
     */
        /*
-------------------------------------------------------------------- */
        using (var drv = Gdal.GetDriverByName("GTiff"))
        {
            if (drv == null)
            {
                throw new Exception("Can't get GTiff driver");
            }

            /*
-------------------------------------------------------------------- */
            /*      Open dataset.
        */
            /*
-------------------------------------------------------------------- */
            using (var ds = Gdal.Open(input, Access.GA_ReadOnly))
            {
                if (ds == null)
                {
                    throw new Exception("Can't open GDAL dataset: " +
input);
                }

                var options = new[] { "" };
                using (var newDataset = drv.CreateCopy(output, ds, 0,
options, null, "Sample Data"))
                {
                    if (newDataset == null)
                    {
                        throw new Exception("Can't create destination
dataset: " + output);
                    }

                    // Close input dataset:
                    ds.Dispose();

                    // 2. Loop through all pixels and perform formula on it:
                    using (var band = newDataset.GetRasterBand(1))
                    {
                        double noData;
                        int hasValue;
                        band.GetNoDataValue(out noData, out hasValue);
                        var sizeX = band.XSize;
                        var numLines = band.YSize;
                        var func = new Function("f(A) = " + formula);

                        // Loop through each line in turn.
                        for (var line = 0; line < numLines; line++)
                        {
                            var scanline = new float[sizeX];
                            // Read in data for the current line
                            var cplReturn = band.ReadRaster(0, line, sizeX,
1, scanline, sizeX, 1, 0, 0);
                            if (cplReturn != CPLErr.CE_None)
                            {
                                throw new Exception("band.ReadRaster
failed: " + Gdal.GetLastErrorMsg());
                            }

                            var outputLine = new List<float>();
                            foreach (var f in scanline)
                            {
                                var pixelValue = f;
                                if ((float)f != (float)noData)
                                {
                                    // Calculate
                                    pixelValue = (float)func.calculate(f);
                                    if (minValue.HasValue)
                                        pixelValue =
(float)Math.Max(pixelValue, minValue.GetValueOrDefault());
                                }
                                outputLine.Add(pixelValue);
                            }

                            // Rewrite line:
                            cplReturn = band.WriteRaster(0, line, sizeX, 1,
outputLine.ToArray(), sizeX, 1, 0, 0);
                            if (cplReturn != CPLErr.CE_None)
                            {
                                throw new Exception("band.WriteRaster
failed: " + Gdal.GetLastErrorMsg());
                            }
                        }

                        // 3. Save changes to file:
                        band.FlushCache();
                        newDataset.FlushCache();
                    }
                }
            }
        }
    }
    catch (Exception e)
    {
        throw new Exception("Can't open GDAL dataset: " + input, e);
    }

    return true;
}

This method is working fine, but is very slow.
I'm using a 3621x4466 tiff file, which has a size of 67MB.
It is taking around 10 minutes to process.
(float)func.calculate(f); is using http://mathparser.org/
An example of a function I'm using: 9.7E-05-e^(3.1 + 0.9 * A) where A is
the pixel value.

How can I optimize my function?

Thanks,

Paul
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osgeo.org/pipermail/gdal-dev/attachments/20170613/a514624c/attachment.html>


More information about the gdal-dev mailing list