How to implement neighborhood-notation using PixelBlock


This sample code demonstrates how to implement neighborhood-notation processing using PixelBlock. This sub creates an output equivalent to OutRas = InRas + (InRas(-1,-1) - InRas(1,1))

How to use

  1. Call this sub in VBA or VB.
  2. Make sure to add reference to ESRI DataSourceRaster Object Library.
[VBA]
Sub NeighborhoodNotation(sInPath As String, sInRasDSName As String, sOutPath As String, sOutRasDSName As String)
    'sInPath: path of the input raster dataset
    'sInRasDSName: name of the input raster dataset
    'sOutPath: path of the output raster dataset
    'sOutRasDSName: name of the output raster dataset'Open input raster dataset
    Dim pRWS As IRasterWorkspace2
    Dim pWSF As IWorkspaceFactory
    Set pWSF = New RasterWorkspaceFactory
    If Not pWSF.IsWorkspace(sInPath) Then
        Exit Sub
    End If
    Set pRWS = pWSF.OpenFromFile(sInPath, 0)
    
    Dim pInRasDS As IRasterDataset
    Set pInRasDS = pRWS.OpenRasterDataset(sInRasDSName)
    
    'Get the forst band from the input raster
    Dim pInBand As IRasterBand
    Dim pInputBandCol As IRasterBandCollection
    Set pInputBandCol = pInRasDS
    Set pInBand = pInputBandCol.Item(0)
    
    'QI raster properties
    Dim pInRasProps As IRasterProps
    Set pInRasProps = pInBand
    
    'Create a default raster from input raster dataset
    Dim pInputRaster As IRaster
    Set pInputRaster = pInRasDS.CreateDefaultRaster
    
    'Create output raster dataset
    Dim fsObj, fl
    Set fsObj = CreateObject("Scripting.FileSystemObject")
    If fsObj.FolderExists(sOutPath) Then
        Set fl = fsObj.GetFolder(sOutPath)
        If fl.Attributes And 1 Then Exit Sub
    Else
        Exit Sub
    End If
    
    Set pRWS = pWSF.OpenFromFile(sOutPath, 0)
    
    Dim pOrigin As IPoint
    Set pOrigin = New Point
    pOrigin.X = pInRasProps.Extent.XMin
    pOrigin.Y = pInRasProps.Extent.YMin
    
    'Find out the pixel type of the input raster dataset
    Dim outPixelType As rstPixelType
    Select Case pInRasProps.PixelType
        Case PT_CHAR
            outPixelType = PT_LONG
        Case PT_COMPLEX
            MsgBox "Operation not supported on complex data", vbOKOnly, "Neighborhood Notation"
            Exit Sub
        Case PT_DCOMPLEX
            MsgBox "Operation not supported on complex data", vbOKOnly, "Neighborhood Notation"
            Exit Sub
        Case PT_DOUBLE
            outPixelType = PT_FLOAT
        Case PT_FLOAT
            outPixelType = PT_FLOAT
        Case PT_LONG
            outPixelType = PT_LONG
        Case PT_SHORT
            outPixelType = PT_LONG
        Case PT_U1
            outPixelType = PT_LONG
        Case PT_U2
            outPixelType = PT_LONG
        Case PT_U4
            outPixelType = PT_LONG
        Case PT_UCHAR
            outPixelType = PT_LONG
        Case PT_ULONG
            outPixelType = PT_LONG
        Case PT_USHORT
            outPixelType = PT_LONG
    End Select
    
    Dim pOutRasDS As IRasterDataset
    Set pOutRasDS = pRWS.CreateRasterDataset(sOutRasDSName, "GRID", pOrigin, _
                    pInRasProps.Width, pInRasProps.Height, pInRasProps.MeanCellSize.X, _
                    pInRasProps.MeanCellSize.Y, 1, outPixelType, pInRasProps.SpatialReference, True)
    
    'Create a default raster from the output raster dataset
    Dim pOutRaster As IRaster
    Set pOutRaster = pOutRasDS.CreateDefaultRaster
    
    'Get the first band from the output raster
    Dim pOutBand As IRasterBand
    Dim pOutputBandCol As IRasterBandCollection
    Set pOutputBandCol = pOutRasDS
    Set pOutBand = pOutputBandCol.Item(0)
    
    'QI IRawPixels interface for input
    Dim pInRawPixels As IRawPixels
    Set pInRawPixels = pInBand
    
    'QI IRawPixels interface for output
    Dim pOutRawPixel As IRawPixels
    Set pOutRawPixel = pOutBand
    
    'Create a DblPnt to hold the PixelBlock size
    Dim pPnt As IPnt
    Set pPnt = New DblPnt
    pPnt.SetCoords pInRasProps.Width, pInRasProps.Height
    
    'Creates PixelBlock from input
    Dim pInPixelBlock As IPixelBlock3
    Set pInPixelBlock = pInRawPixels.CreatePixelBlock(pPnt)
    
    'Creates PixelBlock from output
    Dim pOutPixelBlock As IPixelBlock3
    Set pOutPixelBlock = pOutRawPixel.CreatePixelBlock(pPnt)
    
    'Read input PixelBlock
    pPnt.X = 0
    pPnt.Y = 0
    pInRawPixels.Read pPnt, pInPixelBlock
    
    'Get the SafeArray associated with the first band of the output
    Dim vSafeArray As Variant
    vSafeArray = pOutPixelBlock.PixelDataByRef(0)
    
    'QI RasterProps for output for NoData handling
    Dim pOutRasProps As IRasterProps
    Set pOutRasProps = pOutBand
    
    'Loop through the SafeArray and calculate each pixel value according to the neighborhood-notation
    Dim i, j As Long
    For i = 0 To pInRasProps.Width - 1
        For j = 0 To pInRasProps.Height - 1
            If (i - 1) >= 0 And (i + 1) <= pInRasProps.Width - 1 And _
                (j - 1) >= 0 And (j + 1) <= pInRasProps.Height - 1 Then
                If (Not CDbl(pInPixelBlock.GetVal(0, i, j)) = CDbl(pInRasProps.NoDataValue)) And _
                       (Not CDbl(pInPixelBlock.GetVal(0, i - 1, j - 1)) = CDbl(pInRasProps.NoDataValue)) And _
                       (Not CDbl(pInPixelBlock.GetVal(0, i + 1, j + 1)) = CDbl(pInRasProps.NoDataValue)) Then
                    vSafeArray(i, j) = CDbl(pInPixelBlock.GetVal(0, i, j)) + _
                               (CDbl(pInPixelBlock.GetVal(0, i - 1, j - 1)) - CDbl(pInPixelBlock.GetVal(0, i + 1, j + 1)))
                Else
                    vSafeArray(i, j) = CDbl(pOutRasProps.NoDataValue)
                End If
            Else
                vSafeArray(i, i) = CDbl(pOutRasProps.NoDataValue)
            End If
        Next j
    Next i
    
    'Write out the result
    pOutRawPixel.Write pPnt, pOutPixelBlock
End Sub