1

I am trying to access the array of point values(mainly height and intensity) from a raster through C# without looping through values. I am looking for a direct pointer to the array of values inside of the Raster. I have already tried using methods such as IRaster2.getVal and ConversionOp.RasterDataToPointFeature data but they all take way to longand we should just be able to access the Array of points directly. When using PixelBlock3.get_PixelData we recieve an array filled with zeros. This could be because I am not casting the Array correctly.

Here is the source for the function I am trying to write:

    public double[,] RasterizeLASDByEnvelope(string Name, IGeometry geometry, IRaster pRaster)
    {
        Debug.WriteLine("[RasterizeLASD]");
        Stopwatch sw = new Stopwatch();
        Debug.WriteLine("RasterizeLASD: Start Process... ");
        sw.Start();
        Debug.WriteLine("RasterizeLASD: Defining Geoprocessor.");
        IGeoProcessor2 gp = new GeoProcessorClass();
        gp.OverwriteOutput = true;
        IGeoProcessorResult2 result = new GeoProcessorResultClass();
        IVariantArray parameters = new VarArrayClass();

        object sev = null;
        try
        {

            IRasterProps pRasterProps = pRaster as IRasterProps;

            Debug.WriteLine("RasterizeLASD: Initializing Point Value
            Lists...");
            int width = pRasterProps.Width;
            int height = pRasterProps.Height;
            Stopwatch cpsw = new Stopwatch();
            Debug.WriteLine("RasterizeLASD: Start Point Transfer...");
            cpsw.Start();
            IConversionOp conversionOp = new
            RasterConversionOpClass();
            IFieldChecker fieldChecker = new FieldCheckerClass();
            string name = "pnt" + Program.gdbAdapter.DateTimeStamp();
            string finalname;
            fieldChecker.ValidateTableName(name, out finalname);
            IGeoDataset featClass = conversionOp.RasterDataToPointFeatureData((IGeoDataset)pRaster, Program.gdbAdapter.getWorkspace(), finalname);
            IFeatureCursor fc = ((IFeatureClass)featClass).Search(null, false);
            IFeature feature = fc.NextFeature();
            double[,] solution = new double[width, height];

            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++)
                {
                    object pntval = feature.Value[3];
                    double value = (double)pntval;
                    solution[x, y] = value;
                    feature = fc.NextFeature();
                }
            }
            Debug.WriteLine("RasterizeLASD: End Point Tranfer... Transfer Time: " + cpsw.Elapsed);
            sw.Stop();
            Debug.WriteLine("RasterizeLASD: End Process... Process Time: " + sw.Elapsed);
            return solution;
        }
        catch (Exception ex)
        {
            // Print a generic exception message
            Debug.WriteLine(ex.Message);
        }
        return null;
    }
  • Have you considered GDAL c# bindings? I find it much simpler than the Esri method. Yes, you can mix Esri and GDAL objects (I do frequently). I can't see anything here accessing the raster by pixel block, rather by points, which is definitely the slow way. – Michael Stimson Dec 15 '15 at 22:06
  • Theres gotta be a way to do it through arcmaps – Michael Collins Dec 15 '15 at 22:10
  • Yes, there is, but it's quite convoluted. Would you like an example of accessing raster cell values using ArcObjects? and then a comparison of a similar operation using GDAL? – Michael Stimson Dec 15 '15 at 22:13
  • Yes that would be excellent. – Michael Collins Dec 15 '15 at 22:23
  • Cross-posted as stackoverflow.com/q/34300125/820534 – PolyGeo Jan 28 '16 at 20:00
3

Here is some working Esri code that shows accessing a block of pixels as Float data:

// the Esri way
// reading a block of cells into a Float[,] array
IRaster ReadRaster = InRasters[pImageCnt].CreateDefaultRaster(); // InRasters is an array of IRasterDataset
IRasterProps InImProps = (IRasterProps)ReadRaster;
IEnvelope ThisExtent = new EnvelopeClass();

ThisExtent.PutCoords(InImProps.Extent.XMin, InImProps.Extent.YMin, InImProps.Extent.XMax, InImProps.Extent.YMax);
ThisExtent.SpatialReference = SR;
ThisExtent.Intersect(ThisBlockExtent); // finding common area between the image extent and a predefined AOI
if (!(ThisExtent.IsEmpty))
{

    int pRowOffset = (int)((ULpoint.Y - ThisExtent.YMax) / CellY);
    int pColOffset = (int)((ThisExtent.XMin - Xmin) / CellX);
    int pRows = (int)(ThisExtent.Height / CellY);
    int pCols = (int)(ThisExtent.Width / CellX);
    float[,] ReadDataFloat = null;
    Pnt InRasBlk = new Pnt();
    Pnt ThisBlockSize = new Pnt();

    InRasBlk.X = 0;
    InRasBlk.Y = (int)((InImProps.Extent.YMax - ULpoint.Y) / CellY);
    ThisBlockSize.X = pCols;
    ThisBlockSize.Y = pRows;

    IPixelBlock3 ReadBlock = (IPixelBlock3)ReadRaster.CreatePixelBlock(ThisBlockSize);
    ReadRaster.Read(InRasBlk, (IPixelBlock)ReadBlock);
    ReadDataFloat = (float[,])ReadBlock.get_PixelData(0);

}

and for comparison some GDAL/ArcObjects code for reading one cell on a mouse down:

// opens a GDAL dataset using pRasterLayer (an Esri IRasterLayer)
// and reads one cell... this is from a 'value picker/changer' tool that I wrote.

Gdal.AllRegister(); // very important
OSGeo.GDAL.Dataset gDataset = OSGeo.GDAL.Gdal.OpenShared(pRasterLayer.FilePath, Access.GA_Update); // or GA_ReadOnly
double[] gGeoTrans = new double[6];
gDataset.GetGeoTransform(gGeoTrans);

gCurrentPoint = gActiveView.ScreenDisplay.DisplayTransformation.ToMapPoint(arg.X, arg.Y); // from OnMouseMove but can also be from OnMouseDown
int row = (int)((gGeoTrans[3] - gCurrentPoint.Y) / -gGeoTrans[5]); // ULY - xcoord / -N-S CellSize;
int col = (int)((gCurrentPoint.X - gGeoTrans[0]) / gGeoTrans[1]); // xcoord - ULX / E-W CellSize

if ((col < gDataset.RasterXSize) && col >= 0)
{
    if ((row < gDataset.RasterYSize) && row >= 0)
    {
        if (gBandType == DataType.GDT_Float64)
        {
            double[] buff = new double[1];
            gThisBand.ReadRaster(col, row, 1, 1, buff, 1, 1, 0, 0);
            PickedDoubleValue = buff[0];
            pForm.PickedValue.Text = buff[0].ToString();
            pForm.Update();
        }
        else
        {
            pForm.PickedValue.Text = "Data type not supported";
            pForm.Update();
        }
    }
}

I hope this helps you.

I prefer GDAL for Raster read/write as it's a lot more direct and it also plays nice with Esri objects (I haven't seen them bump into each other) but you need to remember that Esri is strictly a 32bit application so you must use 32bit GDAL bindings.

  • +1 Nice comparison. I've compiled C# into custom 64 bit geoprocessing tools (IGPTool). Would you be able to do the same with gdal and run it in a separate Background process as 64 bit? – Kirk Kuykendall Dec 16 '15 at 4:42
  • I've not tried what you're suggesting but I think so @KirkKuykendall, the GDAL C# bindings come in 32 and 64 bit so if the rest of the application is 64bit it should still work the same. As ArcGis Desktop is a 32bit application I work mostly in x86 except where I'm using only GDAL/OGR objects then I can work in 64bit (or is it when I want to work in 64bit to use more memory I abandon Esri objects and stick with GDAL/OGR). – Michael Stimson Dec 16 '15 at 5:30
  • This is an incredible answer. The first solution has worked and I haven't tried the GDAL solution yet. Quite frankly I don't know what GDAL bindings are used for or how to install it. – Michael Collins Dec 16 '15 at 14:46
  • GDAL/OGR is another 'feather in your cap', for times you don't have or don't want to use Esri, it's open source and fairly easy to use. The GDAL library is for reading rasters and OGR is for geometries. I found my bindings at GisInternals (have a read of gis.stackexchange.com/questions/138184/…) which also installs for C++. Of late I suspect that ArcGis is using the GDAL library to read its rasters (or at least some of them) rather than the old ArcInfo libraries. – Michael Stimson Dec 16 '15 at 21:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.