2011년 11월 6일 일요일

[ArcObjects]Raster Statistics & RasterCursor

ArcObjects에서 RasterDataset의 단순통계를 계산하는 C# 샘플 코드입니다.
 - IRasterStatistics 인터페이스를 이용하여 계산
 - IRasterCursor 인터페이스를 이용하여 계산, 이 코드에서는 Raster cursor를 이용해서 raster dataset의 pixel data에 어떻게 접근하는지도 잘 살펴 보시기 바랍니다.

▣ Code Snippet
■ Reference
using System;
using System.Diagnostics;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.DataSourcesRaster;
■ IRasterStatistics
void RasterStatistics1(IRasterDataset2 inputRasterDs, int bandIndex) {
    // Create a raster. 
    IRaster2 inputRaster = (IRaster2)inputRasterDs.CreateFullRaster();

    IRasterBandCollection bands = (IRasterBandCollection)inputRaster;
    IRasterBand rasterBand = bands.Item(bandIndex);

    // Get statistics
    IRasterStatistics rs = rasterBand.Statistics;

    Debug.WriteLine(string.Format("RasterDataset Path = {0}", inputRasterDs.CompleteName));
    Debug.WriteLine(string.Format("Minimum = {0}", rs.Minimum));
    Debug.WriteLine(string.Format("Maximum = {0}", rs.Maximum));
    Debug.WriteLine(string.Format("Mean = {0}", rs.Mean));
    
    // Population Standard Deviation = Default
    Debug.WriteLine(string.Format("Variance = {0}", Math.Pow(rs.StandardDeviation, 2)));
    Debug.WriteLine(string.Format("Standard Deviation = {0}", rs.StandardDeviation));
}
■ IRasterCursor
void RasterStatistics2(IRasterDataset2 inputRasterDs, int bandIndex) {
    // Create a raster. 
    IRaster2 inputRaster = (IRaster2)inputRasterDs.CreateFullRaster();

    // Create a raster cursor with a system-optimized pixel block size by passing a null.
    IRasterCursor rasterCursor = inputRaster.CreateCursorEx(null);
    IRasterBandCollection bandCol = (IRasterBandCollection)inputRaster;
    int bandCount = bandCol.Count;

    // Get NoDataValues
    IRasterProps rasterProps = (IRasterProps)inputRaster;
    System.Array noDataValue = (System.Array)rasterProps.NoDataValue;

    // Define variables
    double minVal = double.MaxValue;
    double maxVal = double.MinValue;
    double sumOfVals = 0;
    double sumOfSqrs = 0;
    int      rowCount = 0;
    double noData = double.NaN;

    do {
        IPixelBlock3 pixelblock3 = (IPixelBlock3)rasterCursor.PixelBlock;
        int blockwidth = pixelblock3.Width;
        int blockheight = pixelblock3.Height;                

        // Loop through each band and pixel block.
        for (int plane = 0; plane < bandCount; plane++) {
            if (bandIndex != plane) continue;

            // Get the pixel array.
            System.Array pixelData = (System.Array)pixelblock3.get_PixelData(plane);
            noData = Convert.ToDouble(noDataValue.GetValue(plane));

            for (int colIndex = 0; colIndex < blockwidth; colIndex++) {
                for (int rowIndex = 0; rowIndex < blockheight; rowIndex++) {
                    // Get the pixel value.
                    double val = Convert.ToDouble(pixelData.GetValue(colIndex, rowIndex));

                    // Check the nodata value
                    if (val != noData) {
                        // Do something with the value.
                        minVal = Math.Min(minVal, val);
                        maxVal = Math.Max(maxVal, val);
                        sumOfVals += val;
                        sumOfSqrs += Math.Pow(val, 2.0);

                        rowCount++;
                    }
                }
            }
        }
    } while (rasterCursor.Next() == true);
    System.Runtime.InteropServices.Marshal.ReleaseComObject(rasterCursor);

    Debug.WriteLine(string.Format("RasterDataset Path = {0}", inputRasterDs.CompleteName));
    Debug.WriteLine(string.Format("Count = {0}", rowCount));
    Debug.WriteLine(string.Format("NoDataValue = {0}", noData));
    Debug.WriteLine(string.Format("Minimum = {0}", minVal));
    Debug.WriteLine(string.Format("Maximum = {0}", maxVal));
    Debug.WriteLine(string.Format("Sum = {0}", sumOfVals));
    Debug.WriteLine(string.Format("Mean = {0}", sumOfVals / rowCount));

    // Population Standard Deviation
    double variance = (sumOfSqrs - Math.Pow(sumOfVals, 2) / rowCount) / rowCount;
    Debug.WriteLine(string.Format("Variance = {0}", variance));
    Debug.WriteLine(string.Format("Standard Deviation = {0}", Math.Sqrt(variance)));

    // Sample Standard Deviation
    variance = (sumOfSqrs - Math.Pow(sumOfVals, 2) / rowCount) / (rowCount - 1);
    Debug.WriteLine(string.Format("Variance = {0}", variance));
    Debug.WriteLine(string.Format("Standard Deviation = {0}", Math.Sqrt(variance)));
}
■ Output
* RasterStatistics1
RasterDataset Path = C:\Data\DEM30
Minimum = 0
Maximum = 1699
Mean = 388.118777090779
// Population Standard Deviation
Variance = 80229.6974359289
Standard Deviation = 283.248472963102
* RasterStatistics2
RasterDataset Path = C:\Data\DEM30
Count = 22522424
NoDataValue = 32767
Minimum = 0
Maximum = 1699
Sum = 8741375660
Mean = 388.118777090779
// Population Standard Deviation
Variance = 80229.6974359289
Standard Deviation = 283.248472963102
// Sample Standard Deviation
Variance = 80229.7009981432
Standard Deviation = 283.248479251245
▣ FeatureClass/FeatureLayer에 대한 통계정보 계산
 - [ArcObjects] ArcObjects에서 필드의 통계정보 계산하기

▣ 참고
 - ArcObjects 10 .NET SDK Help : IRasterCursor Interface
 - ArcObjects 10 .NET SDK Help : IRasterStatistics Interface