Rule Based Post-Classification Techniques for Remotely Sensed Vegetation Data





Jeffery S. Nighbert





Creation of Vegetation themes for Geographic Information Systems (GIS) using remote sensing techniques and satellite imagery is time and cost effective, but not without problems. Even in the best circumstances, errors can occur due to statistical similarities of vegetative spectral responses in different lighting situations. These errors can be addressed systematically using a rule-based editing program, if the geographical basis for correction can be properly stated. The Arc/Grid GIS subsystem offers the DoCell programming language which can be used to construct rule-based reclassification programs.



The Interagency Vegetation Mapping Project (IVMP) is a significant effort between Forest Service and Bureau of Land Management to use Thematic Mapper satellite imagery to create a forest vegetation database for the range of the Spotted Owl in Oregon and Washington.

This area encompasses almost 43 million acres, and has been stratified into nine physiographic provinces, and will involve the processing 18 separate Landsat scenes. The mapping methods will utilize a regression analysis technique and the final database will include information about the vegetation cover, conifer and broadleaf densities, canopy structure, and over-story size class.

This presentation will discuss how rule based reclassification programs were defined and written using the Arc/Grid DoCell language to correct classification problems in this study. The presentation will not dwell on the source code for these programs, but will attempt to de-mystify the "rule based post-classification" process by providing several simple graphical examples of the results and impact of using this technique.




BACKGROUND



Creation of Vegetation themes for Geographic Information Systems (GIS) using remote sensing techniques and satellite imagery is time and cost effective, but not without problems. Even in the best circumstances, errors can occur due to statistical similarities of vegetative spectral responses in different lighting situations. These errors can be addressed systematically using a rule-based editing program, if the geographical basis for correction can be properly stated. The Arc/Grid GIS subsystem offers the DoCell programming language which can be used to construct rule-based reclassification programs.



The Interagency Vegetation Mapping Project (IVMP) is a significant effort between Forest Service and Bureau of Land Management to use Thematic Mapper satellite imagery to create a forest vegetation database for the range of the Spotted Owl in Oregon and Washington. This area encompasses almost 43 million acres, and has been stratified into nine physiographic provinces, and will involve the processing 18 separate Landsat scenes. The mapping methods will utilize a regression analysis technique and the final database will include information about the vegetation cover, conifer and broadleaf densities, canopy structure, and over-story size class. Figure 1 shows a map of the project area and the Coast Range Province.





The vegetation mapping for the IVMP project utilized a regression analysis technique for interpreting satellite imagery. Use of regression analysis assumes a linear relationship between vegetation cover and reflectance values in the imagery. This relationship is described by a regression equation. In most cases, this has been an effective technique. However, in the determination and classification of tree sizes as specified in Quadratic Mean Diameter (QMD) units, this technique over-predicted QMD values. After extensive investigation and error testing using other data sources, including aerial photography, field inventory data and speaking with forest resource specialists, it was determined that the regression model for the QMD tree size theme was erroneously labeling pixel values over 70 DBH (average diameter at breast height). This over prediction occurred because of spectral confusion between large "old growth" conifers and areas of shadow around topographic features, clearcut timber stands, or water. As a result, three special Arc Macro Language (AML) programs were written to "post-classify" the QMD theme. The Coast Range Province within Range of the Spotted Owl and IVMP study areas was the first area where these programs were applied and are the topic of discussion in this paper. Figure two shows the QMD theme and enlarged areas. Darker areas indicate low QMD or smaller tree sizes, whiter areas indicate larger tree sizes.







METHODS



Rule Based Post-Classification - What is it?



Rule based post-classification is essentially "editing pixels known to be wrong according to some applied criteria." In the IVMP application, QMD pixels were considered erroneous if they had a value of 70 or more. These bad values can be edited systematically according to a set of "rules" or criteria. Rules are formalized notions about how things behave or should behave. In this case, pixels values will be changed according to notions about each pixels geographic situation. For example, erroneous "old-growth" pixels could not exist withing a "recent clearcut" for obvious reasons. So a program could and was written to analyze a pixels neighboring values and determine a new value based on some rules.

The advantages of Rule based processing

The advantages of rule based editing are fairly apparent. By "fixing" erroneous pixel values within a image, the accuracy of that data set will be improved. This will lead to higher product confidence, greater product usability and user acceptance. When the edits are made according to predefined "rules," the outcomes are more defensible and replicable. Because the editing is controlled through programming, the techniques are cheaper and faster than hand editing, with less possibility of human error. Furthermore, AML processing code is highly flexible and can be adapted to many different rule scenarios.

Three Rule based AML Programs

The Arc/Info Grid system provides all the programming tools necessary for composing AML programs to preform rule-based edits. In particular, the grid IF and grid DOCELL functionality provided excellent capabilities for analyzing pixels on an individual basis when searching for compliance with neighborhood context rules. Arc/Grid also allows processing window functions, which allow programs to analyze a given pixel's neighbors within a specified neighborhood (e.g. a 3 x 3 cell window would look at 9 pixels, the center pixel the object and the adjoining 8 pixels). Addtionally, neighboring pixels can be queried on an individual basis using a local addressing or "neighborhood notation" scheme. See Arc Grid manual for an explanation of this capability. Additional functionality needed for rule-based reclassification was created through AML programming to build Neighborhood Topology table structures. This special functionality allows neighborhood analysis on a "grouped pixel" or "patch" basis by establishing a look-up table the relates individual patches with their neighbors.

In all, three AML programs (filter1.aml, filter2.aml, and filter3.aml) were written for the Rule based editing of the Coast Range QMD theme. They are progressive filters and are meant to be executed in sequence and perform increasingly complex tasks, as the data is refined.



Filter1.aml



Filter1.aml eliminates single isolated pixels that were mis-classified as water and represents most simple case of rule based editing. These pixels were originally classified water and appear as isolated pixels throughout the image. But they were in fact, dark shadow areas associated with topographic features or old growth timber. In filter1.aml these pixels are re-coded to a value of 10 or "unknown." They will be addressed by the rule-based codes in subsequent aml programs (filter2.aml or filter3.aml).

The rule applied in filter1.aml are as follows:

If a pixel with a value of 1 is surrounded by no other 1s in a 5 x 5 cell processing window, change that pixel value to 10 (unknown)







The figure above shows the processing model for filter1. The source code for filter1.aml is included in the Appendix in this paper, but a portion of the source code is show below. This part of the code illustrates a process known as "scoring," which is easily accomplished in a DOCELL process loop within the Arc/Grid system. Scoring simply examines every pixel within the processing window matrix and assigns a 1 to a Scalar Variable if that cell meets the criteria applied, and 0 if it does not. Then all of the Scalar Variables are Summed up and if the result is equal to 1, then the criteria is true and the new cell receives a value of 10, otherwise it keeps the original value.



DOCELL



if (%inmap% == 1)

{

i1 := 0

i2 := 0

i3 := 0...etc



if (%inmap%(-2,-2) == 1)

{

i1 := 1

}

if (%inmap%(-1,-2) == 1)

{

i2 := 1

}

if (%inmap%(0,-2) == 1)

{

i3 := 1

}...etc



score := scalar(i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9 + i10 + ~

i11 + i12 + i13 + i14 + i15 + i16 + i17 + i18 + i19 + i20 + ~

i21 + i22 + i23 + i24 + i25 )



if (score == 1 )

{

%outmap% = 10

}



}

else

{

%outmap% = %inmap%

}

endif

END



The figure below shows the results of filter1.aml.





Filter2.aml

Filter2.aml looks at multiple pixel configurations on a "pixel by pixel" basis. Its mission is to change "Unknown" pixels to new values based on the value of its neighboring pixels. The new value is determined according to rules and a precedence list. This AML still uses the Scoring method as in Filter1.aml, but now more questions are asked about the geographic context of each pixel and depending on the answers, a precedence list may be used to assign the new pixel's value. Because recoding takes place on a single pixel basis, the geographic context changes as the recode takes place. Therefore the program must iterate through the image many times until the rules no longer make any changes. This of course increases processing times greatly.

The rules for filter2.aml are as follows:

If the 'Unknown' Pixel has "forest" neighbors, then (QMD) of the forest pixels.

If neighboring pixels are water, urban, agriculture, barren, snow less that 70 percent vegetation cover, or less that 30 percent conifer cover, then depending on the numbers of pixels, a precedence order is followed to determine what the 'Unknown' pixel's value will be.

If more than 4 of a pixels Unknown pixel's neighbors are also Unknown; then do not recode the pixel.







The figures above show the processing model for filter2. The source code for filter2.aml is included in the Appendix in this paper, but a portion of the source code is show below. This part of the code illustrates a process known as "scoring," which is easily accomplished in a DOCELL process loop within the Arc/Grid system. But unlike the Scoring example shown in Filer1.aml above, this example shows how to use scoring, then check a precedence list to see if certain values are present. In the example shown below, the scalar "score2" is set to 1, when there is 1 neighbor in the set {1,2,3,4,5,8,9} of adjoining pixel values, thus the scalar variables "v1...v8" is set to value according is value determined by neighborhood notation. The scalar variables "vv1...vv8" are set according to the order as the given precedence list and depending on the evaluations, the target pixel value recieves that value via the "outmap = vv8" or the last true statement. (If vv3 were true then outmap would equal vv3, since this case has only 1 pixel value to evaluate.

if (score2 == 1)

{

v1 := %inmap%(-1,-1)

v8 := %inmap%(0,-1)...etc

vflag := 0

vtotal := 0

vv1 := 1...etc

vv8 := 8

if (vv1 in {v1,v2,v3,v4,v5,v6,v7,v8})

%outmap% = vv1...etc

if (vv8 in {v1,v2,v3,v4,v5,v6,v7,v8})

%outmap% = vv8

}

The figure below shows an example of the results from filter2.aml:







Filter3.aml

Filter3.aml eliminates unknown pixels on a group basis. It is the last filter in the sequence and obeys much the same rules as filter2.aml. Its mission is to re-code "unknown" pixels to new values based on the values of their neighboring pixels. The new value is determined according to rules and a precedence list. The difference between filter3.aml and filter2.aml is that filter3.aml utilizes a special "neighborhood topology table" which provides the linkage between each unique group of unknown pixels and its neighbors. It is a much more complex process than the previous two amls because the program has to establish and build the neighborhood topology tables. Once established, though queries can be made of this table for compliance with context rules and the proper new values can be assigned. This process is much faster than the filter2.aml process.

The rules for filter3.aml are as follows:

Use the most frequent cover type surrounding the region of 'Unknown' pixels

When ther is not a most frequent cover type, then a precedence order of cover types is followed based on what is most likely to be on the ground and what was originally likely to be classified as 'Unknown', depending on the new values position in the precedence list.

If no groups meet the above criteria, the keep them 'Unknown'





The figures above show the processing model for filter3.aml. The source code for this AML is included in the Appendix in this paper, but I would like to highlight the process for deriving a "Neighborhood Topology Table" for use with this process. This process basically runs the REGIONGROUP command on all unknown values and assigns them a unique region identifier. These regions are then expanded using the EXPAND grid function with the CELLSIZE set to one quarter of the original pixel cell size. Then using a CON function against the REGIONGROUP grid a loop is created. This loop in intersected with the original grid and a neighbors grid with a .VAT file is created. This .VAT is the neighborhood topology table. The figures below show this process graphically with the program commands:

The figure below shows an example of the results from filter3.aml

RESULTS

The application and results obtained from applying these three AML programs were well received and accepted by the scientific team on the IVMP project. They have encouraged the use and further refinement and application of this style of programming support for the remainder of the project. Below are listings of critical statistics which are the results of these programs:

Image size:

25 meter cells, 5630 columns x 14904 rows, 83,909,520 pixels, using 38,902,235 Mbytes



Computing resources:

Software: NT Arc/Info with Grid extension

Hardware: Dual cpu 450 megahertz Xenon Chips, 2 GB ram - 30 GB disc space.

Filter1.aml results:

Original image:

class 1 pixels: 2,510,599

class 10 pixels: 395,519

After Filter1.aml:

Class 1 pixels: 2,505,932

Class 10 pixels: 400,186

Fixed Pixels: 4667

Elapsed time: 15:23 minutes

Filter2.aml results:

Input image:

class 10 pixels: 400,186

After Filter1.aml:

Class 10 pixels: 21,380

Fixed Pixels: 378,758

Elapsed time: 6 hours 23 minutes

Filter3.aml results:

Input image:

class 10 pixels: 21,380

After Filter3.aml:

Class 10 pixels: 304

Fixed Pixels: 21,076

Elapsed time: 23:06 minutes



Total Fixes "Unknown" Pixels: 399,882





CONCLUSIONS

The Arc/Grid has proven to be an effective and highly capable tool for solving data problems in the IVMP project. The Rule Based Post Classification techniques described here have proven effective in improving the quality and usability of the final products delivered to the users from the project. The Arc DOCELL, IF, and CON functions have proved particularly valuable in facilitating this effective programming. The neighborhood topology table structures have also played an important role in allow sophisticated queries of pixels as a group entity.

This overall approach to image touch-ups will continue to be used, since it is an automated, repeatable and customizable process that can be applied to many situations effectively. I would recommend this type of programming be used in many other situations arising in complex spatial analysis. In the future, new areas will be explored using these techniques.


Author Information:

Jeffery S. Nighbert
Bureau of Land Management
Oregon State Office 955.2
1515 SW 5th Avenue

Portland, Oregon 97201
Phone:(503) 952-6399

Fax: (503) 952-6419
Email: jnighber@or.blm.gov


Bios:

Jeffery S. Nighbert has been a geographer with the Bureau of Land Management for over 20 years and is currently the Senior Technical Specialist for Geographic Information Systems (GIS) at the Oregon State Office, located in Portland, Oregon. He has extensive experience in GIS and holds a M.A. in Geography from University of New Mexico.


APPENDICES

Filter1.aml

/* ====================================================================

/* AML Name: QMD_STEP1.AML

/* AML Location: Oregon State Office

/* ====================================================================

/* Author:

/* jeffery s. nighbert

/* bureau of land management

/* 1515 sw 5th ave

/* portland oregon 97208

/* phone 503-952-6399

/* email jnighber@or.blm.gov

/* May 1999

/* ====================================================================

/* Purpose: Clean up single water pixels

/* --------------------------------------------------------------------

/* Usage: &run qmd_step1 <input grid> <output grid>

/* --------------------------------------------------------------------

/* I/O Files, Coverages:

/* (Input: required - qmd layer from ivmp project)

/* (Output: no naming scheme required)

/* --------------------------------------------------------------------

/* Other AML's Called:

/* --------------------------------------------------------------------

/* Other Programs Called:

/* --------------------------------------------------------------------

/* AML's Called By:

/* --------------------------------------------------------------------

/* AML History:

/* Created by: Jeff Nighbert May 1999

/* --------------------------------------------------------------------

/* Assumptions:

/* you're in arc/grid and your window and mapextent are set

/* --------------------------------------------------------------------

/* to run:

/* &r qmd_step1 <input> <output>

/* --------------------------------------------------------------------

/* arg definitions

/* input - qmd_grid

/* output - hardwired to: qmd_step1

/*

&args input output

&watch filter1.watch

&type [date -vfull]



&s inmap := %input%

&s outmap := %output%



&if [exists %outmap% -grid] &then kill %outmap%



DOCELL



if (%inmap% == 1)

{

i1 := 0

i2 := 0

i3 := 0

i4 := 0

i5 := 0

i6 := 0

i7 := 0

i8 := 0

i9 := 0

i10 := 0

i11 := 0

i12 := 0

i13 := 0

i14 := 0

i15 := 0

i16 := 0

i17 := 0

i18 := 0

i19 := 0

i20 := 0

i21 := 0

i22 := 0

i23 := 0

i24 := 0

i25 := 0

if (%inmap%(-2,-2) == 1)

{

i1 := 1

}

if (%inmap%(-1,-2) == 1)

{

i2 := 1

}

if (%inmap%(0,-2) == 1)

{

i3 := 1

}

if (%inmap%(1,-2) == 1)

{

i4 := 1

}

if (%inmap%(2,-2) == 1)

{

i5 := 1

}

if (%inmap%(-2,-1) == 1)

{

i6 := 1

}

if (%inmap%(-1,-1) == 1)

{

i7 := 1

}

if (%inmap%(0,-1) == 1)

{

i8 := 1

}

if (%inmap%(1,-1) == 1)

{

i9 := 1

}

if (%inmap%(2,-1) == 1)

{

i10 := 1

}

if (%inmap%(-2,0) == 1)

{

i11 := 1

}

if (%inmap%(-1,0) == 1)

{

i12 := 1

}

if (%inmap%(0,0) == 1)

{

i13 := 1

}

if (%inmap%(1,0) == 1)

{

i14 := 1

}

if (%inmap%(2,0) == 1)

{

i15 := 1

}

if (%inmap%(-2,1) == 1)

{

i16 := 1

}

if (%inmap%(-1,1) == 1)

{

i17 := 1

}

if (%inmap%(0,1) == 1)

{

i18 := 1

}

if (%inmap%(1,1) == 1)

{

i19 := 1

}

if (%inmap%(2,1) == 1)

{

i20 := 1

}

if (%inmap%(-2,2) == 1)

{

i21 := 1

}

if (%inmap%(-1,2) == 1)

{

i22 := 1

}

if (%inmap%(0,2) == 1)

{

i23 := 1

}

if (%inmap%(1,2) == 1)

{

i24 := 1

}

if (%inmap%(2,2) == 1)

{

i25 := 1

}



score := scalar(i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9 + i10 + ~

i11 + i12 + i13 + i14 + i15 + i16 + i17 + i18 + i19 + i20 + ~

i21 + i22 + i23 + i24 + i25 )



if (score == 1 )

{

%outmap% = 10

}

else

{

%outmap% = %inmap%

}

}

else

{

%outmap% = %inmap%

}

endif

END



&type [date -vfull]

Filter2.aml

/* ====================================================================

/* AML Name: QMD_STEP2.AML

/* AML Location: Oregon State Office

/* ====================================================================

/* Author:

/* jeffery s. nighbert

/* bureau of land management

/* 1515 sw 5th ave

/* portland oregon 97208

/* phone 503-952-6399

/* email jnighber@or.blm.gov

/* May 1999

/* ====================================================================

/* Purpose: Clean up single water pixels

/* --------------------------------------------------------------------

/* Usage: &run qmd_step2 <input grid>

/* --------------------------------------------------------------------

/* I/O Files, Coverages:

/* (Input: required - qmd_step1)

/* (Output: qmd_step2)

/* --------------------------------------------------------------------

/* Other AML's Called:

/* --------------------------------------------------------------------

/* Other Programs Called:

/* --------------------------------------------------------------------

/* AML's Called By:

/* --------------------------------------------------------------------

/* AML History:

/* Created by: Jeff Nighbert May 1999

/* --------------------------------------------------------------------

/* Assumptions:

/* you're in arc/grid and your window and mapextent are set

/* --------------------------------------------------------------------

/* to run:

/* &r qmd_step2 <input>

/* --------------------------------------------------------------------

/* arg definitions

/* input - qmd_step2

/* output - hardwired to: qmd_step2

/*







&args ingrid outgrid

&watch filter2.watch

&s inmap := %ingrid%

&s finalmap := %outgrid%

&s outmap := uuu

&s iteration := 0

&s cellcount_prev := 0

clearselect

reselect %inmap%.vat info value = 10

/* &r ramp %inmap%

/* &r plot_selected %inmap% yellow

&type ========================================

&type [date -vfull]

&type =======================================



&s selected := [extract 1 [show select %inmap%.vat info ]]

&s cellcount_orig := [extract 1 [show select %inmap%.vat info 1 item count]]

&type 'You have '%cellcount_orig%' Unkown Pixels'

&type

&type



clearselect

&s exist = .false.

&s i = 0

&do &until %exist% = .false.



&s exist := [exists outmap -grid]

&if %exist% = .TRUE. &then

&do

&type removing outmap

kill outmap

&end



&s i = %i% + 1

&end



&if [exists %outmap% -grid] &then kill %outmap%



&s selected := 1

&s quit := .false.

&do &until %selected% = 0 or %quit% = .true.

DOCELL



if (%inmap% == 10)

{

i1 := 0

i2 := 0

i3 := 0

i4 := 0

i5 := 0

i6 := 0

i7 := 0

i8 := 0



if (%inmap%(-1,-1) == 10)

{

i1 := 1

}

if (%inmap%(0,-1) == 10)

{

i2 := 1

}

if (%inmap%(1,-1) == 10)

{

i3 := 1

}

if (%inmap%(-1,0) == 10)

{

i4 := 1

}

if (%inmap%(1,0) == 10)

{

i5 := 1

}

if (%inmap%(-1,1) == 10)

{

i6 := 1

}

if (%inmap%(0,1) == 10)

{

i7 := 1

}

if (%inmap%(1,1) == 10)

{

i8 := 1

}

score := scalar(i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8)



if (score >= 4)

{

%outmap% = 10

}

if (score < 4)

{

j1 := 0

j2 := 0

j3 := 0

j4 := 0

j5 := 0

j6 := 0

j7 := 0

j8 := 0



if (%inmap%(-1,-1) in {1,2,3,4,5,8,9})

{

j1 := 1

}

if (%inmap%(0,-1) in {1,2,3,4,5,8,9})

{

j2 := 1

}

if (%inmap%(1,-1) in {1,2,3,4,5,8,9})

{

j3 := 1

}

if (%inmap%(-1,0) in {1,2,3,4,5,8,9})

{

j4 := 1

}

if (%inmap%(1,0) in {1,2,3,4,5,8,9})

{

j5 := 1

}

if (%inmap%(-1,1) in {1,2,3,4,5,8,9})

{

j6 := 1

}

if (%inmap%(0,1) in {1,2,3,4,5,8,9})

{

j7 := 1

}

if (%inmap%(1,1) in {1,2,3,4,5,8,9})

{

j8 := 1

}



score2 := scalar(j1 + j2 + j3 + j4 + j5 + j6 + j7 + j8)

if (score2 == 0)

{

v1 := %inmap%(-1,-1)

v2 := %inmap%(0,-1)

v3 := %inmap%(1,-1)

v4 := %inmap%(-1,0)

v5 := %inmap%(1,0)

v6 := %inmap%(-1,1)

v7 := %inmap%(0,1)

v8 := %inmap%(1,1)

vflag := 0

vtotal := 0



if (v1 >= 11)

{

vflag := 1 + vflag

vtotal := v1 + vtotal

}

if (v2 >= 11)

{

vflag := 1 + vflag

vtotal := v2 + vtotal

}

if (v3 >= 11)

{

vflag := 1 + vflag

vtotal := v3 + vtotal

}

if (v4 >= 11)

{

vflag := 1 + vflag

vtotal := v4 + vtotal

}

if (v5 >= 11)

{

vflag := 1 + vflag

vtotal := v5 + vtotal

}

if (v6 >= 11)

{

vflag := 1 + vflag

vtotal := v6 + vtotal

}

if (v7 >= 11)

{

vflag := 1 + vflag

vtotal := v7 + vtotal

}

if (v8 >= 11)

{

vflag := 1 + vflag

vtotal := v8 + vtotal

}



score3 := (vtotal / vflag)

%outmap% = score3

}

if (score2 == 1)

{

v1 := %inmap%(-1,-1)

v2 := %inmap%(0,-1)

v3 := %inmap%(1,-1)

v4 := %inmap%(-1,0)

v5 := %inmap%(1,0)

v6 := %inmap%(-1,1)

v7 := %inmap%(0,1)

v8 := %inmap%(1,1)

vflag := 0

vtotal := 0

vv1 := 1

vv2 := 2

vv3 := 3

vv4 := 4

vv5 := 5

vv8 := 8

vv9 := 9

if (vv1 in {v1,v2,v3,v4,v5,v6,v7,v8})

%outmap% = vv1

if (vv2 in {v1,v2,v3,v4,v5,v6,v7,v8})

%outmap% = vv2

if (vv3 in {v1,v2,v3,v4,v5,v6,v7,v8})

%outmap% = vv3

if (vv4 in {v1,v2,v3,v4,v5,v6,v7,v8})

%outmap% = vv4

if (vv5 in {v1,v2,v3,v4,v5,v6,v7,v8})

%outmap% = vv5

if (vv8 in {v1,v2,v3,v4,v5,v6,v7,v8})

%outmap% = vv8

if (vv9 in {v1,v2,v3,v4,v5,v6,v7,v8})

{

if (v1 >= 11)

{

vflag := 1 + vflag

vtotal := v1 + vtotal

}

if (v2 >= 11)

{

vflag := 1 + vflag

vtotal := v2 + vtotal

}

if (v3 >= 11)

{

vflag := 1 + vflag

vtotal := v3 + vtotal

}

if (v4 >= 11)

{

vflag := 1 + vflag

vtotal := v4 + vtotal

}

if (v5 >= 11)

{

vflag := 1 + vflag

vtotal := v5 + vtotal

}

if (v6 >= 11)

{

vflag := 1 + vflag

vtotal := v6 + vtotal

}

if (v7 >= 11)

{

vflag := 1 + vflag

vtotal := v7 + vtotal

}

if (v8 >= 11)

{

vflag := 1 + vflag

vtotal := v8 + vtotal

}



score3 := (vtotal / vflag)

%outmap% = score3

}





}

if (score2 > 1)

{

v1 := %inmap%(-1,-1)

v2 := %inmap%(0,-1)

v3 := %inmap%(1,-1)

v4 := %inmap%(-1,0)

v5 := %inmap%(1,0)

v6 := %inmap%(-1,1)

v7 := %inmap%(0,1)

v8 := %inmap%(1,1)

vflag := 0

vtotal := 0

vv1 := 1

vv2 := 2

vv3 := 3

vv4 := 4

vv5 := 5

vv8 := 8

vv9 := 9

if ((vv8 in {v1,v2,v3,v4,v5,v6,v7,v8}) and (vflag == 0))

{

%outmap% = vv8

vflag := 1

}

if ((vv9 in {v1,v2,v3,v4,v5,v6,v7,v8}) and (vflag == 0))

{

%outmap% = vv9

vflag := 1

}

if (( vv1 in {v1,v2,v3,v4,v5,v6,v7,v8}) and (vflag == 0))

{

%outmap% = vv1

vflag := 1

}

if ((vv4 in {v1,v2,v3,v4,v5,v6,v7,v8}) and (vflag == 0))

{

%outmap% = vv4

vflag := 1

}

if ((vv3 in {v1,v2,v3,v4,v5,v6,v7,v8}) and (vflag == 0))

{

%outmap% = vv3

vflag := 1

}

if ((vv2 in {v1,v2,v3,v4,v5,v6,v7,v8}) and (vflag == 0))

{

%outmap% = vv2

vflag := 1

}

if ((vv5 in {v1,v2,v3,v4,v5,v6,v7,v8}) and (vflag == 0 ))

{

%outmap% = vv5

vflag := 1

}

}



}

}

else

%outmap% = %inmap%

endif



END





/* clear

/* gridpaint %outmap%

/* /* gridnet %outmap% all

/* textoffset 0 0

/* textcolor blue

/* latticetext %outmap%

/* textcolor red

/* textoffset 0 -.25

/* latticetext %inmap%





&if [exists tmp123 -grid] &then; kill tmp123



&s inmap := tmp123

rename %outmap% %inmap%



reselect %inmap%.vat info value = 10

/* &r ramp %inmap%

/* &r plot_selected %inmap% yellow



&s selected := [extract 1 [show select %inmap%.vat info ]]

&s cellcount := [extract 1 [show select %inmap%.vat info 1 item count]]



&if ( %selected% = 0 ) &then

&do

&s cellcount := 0

&s cellcount_prev := 0

&end





&s iteration = %iteration% + 1

&type ===================================================

&type 'You started with '%cellcount_orig%' Unknown Pixels'

&type 'You have '%cellcount%' Unkown Pixels Remaining'

&type 'After '%iteration%' iterations...'

&type [date -vfull]

&type ====================================================

&type 'Records Selected: '%selected%

clearselect



&if ( %cellcount% = %cellcount_prev% ) &then

&do

&s quit = .true.

&s selected := 0

&if [exists %finalmap% -grid] &then; kill %finalmap%

rename %inmap% %finalmap%

&type ===================================================

&type 'FINISHED Processing...'

&type 'You have '%cellcount%' Pixels Remaining...'

&type 'After '%iteration%' iterations...'

&type [date -vfull]

&type ===================================================

&end



&s cellcount_prev := %cellcount%



&end

Filter3.aml

/* ====================================================================

/* AML Name: QMD_STEP3.AML

/* AML Location: Oregon State Office

/* ====================================================================

/* Author:

/* jeffery s. nighbert

/* bureau of land management

/* 1515 sw 5th ave

/* portland oregon 97208

/* phone 503-952-6399

/* email jnighber@or.blm.gov

/* May 1999

/* ====================================================================

/* Purpose: Clean up single water pixels

/* --------------------------------------------------------------------

/* Usage: &run qmd_step3 <input grid> <output grid>

/* --------------------------------------------------------------------

/* I/O Files, Coverages:

/* (Input: required - qmd_step2)

/* (Output: qmd_step3)

/* --------------------------------------------------------------------

/* Other AML's Called:

/* --------------------------------------------------------------------

/* Other Programs Called:

/* --------------------------------------------------------------------

/* AML's Called By:

/* --------------------------------------------------------------------

/* AML History:

/* Created by: Jeff Nighbert May 1999

/* --------------------------------------------------------------------

/* Assumptions:

/* you're in arc/grid and your window and mapextent are set

/* --------------------------------------------------------------------

/* to run:

/* &r qmd_step3 <input>

/* --------------------------------------------------------------------

/* arg definitions

/* input - qmd_step3

/* output - hardwired to: qmd_step3

/*







&args ingrid outgrid

&watch filter3.watch

&echo &off

clearselect

setwindow %ingrid%

setcell %ingrid%



&s input := %ingrid%

&s output := %outgrid%



&type [date -vfull]

&type ===============================================

&type box 1

&type ===============================================





&type setcell to .25 of original cellsize

setcell [calc 25 * .25]

&type ==================================================

&type 1. identify patches of unknown pixels (value = 10)

&type and add majority field to the .vat file

&type ==================================================

&if [exists finalreg -grid] &then; kill finalreg

finalreg = regiongroup(con(%input% == 10,10,0))

clearselect

reselect finalreg.vat info link eq 10

&s cont = [extract 1 [show select finalreg.vat info]]



&if %cont% < 1 &then &goto unknown





arc additem finalreg.vat finalreg.vat majority 10 10 i





&type =================================================

&type 2. expand 10s by 1 cell to establish neighbors

&type then assess if values 1,2,3,4,5,8,9 or >= 11

&type are present in the islands neighbors

&type =================================================





&type =================================================

&type establish neighbors - expand patches of 10

&type =================================================

&if [exists finalexp -grid] &then; kill finalexp

reselect finalreg.vat info link = 10

infofile finalreg.vat info neighbor_exp init

finalexp = expand(finalreg,1,table,neighbor_exp,value)



&type =================================================

&type establish neighbors - create neighbor rings

&type =================================================

&if [exists finaldif -grid] &then; kill finaldif

finaldif = con(finalreg ne finalexp,finalexp)



&type =====================================================

&type establish neighbors - combine with original map to

&type create neighbors grid and .vat

&type =====================================================



&if [exists zmean -grid] &then; kill zmean

&if [exists zvals -grid] &then; kill zvals

&if [exists newneighbors -grid] &then; kill newneighbors

&if [exists neighbors -grid] &then; kill neighbors



zmean = int(zonalmean(finaldif,con(%ingrid% ge 11,%ingrid%),data) + .5)

zvals = con(finaldif > 0,con(%ingrid% < 11,%ingrid%))

newneighbors = merge(zvals,zmean)



neighbors = combine(finaldif,newneighbors)

arc additem neighbors.vat neighbors.vat majority 10 10 i



clearselect

/* create infofile of 8,9,3 qmdfilt3 records

reselect neighbors.vat info newneighbors = 3

aselect neighbors.vat info newneighbors = 8

aselect neighbors.vat info newneighbors = 9

sort neighbors.vat info count

infofile neighbors.vat info tmp893 init



clearselect neighbors.vat info



reselect finaldif.vat info $recno > 0

&s selected := [extract 1 [show select finaldif.vat info ]]

&s index := 1

&do &while %index% le %selected%

&type ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

&type Now examining patch %index% - and its neighbors...



&s finaldif := [show select finaldif.vat info %index% item value ]

&type Finaldif = %finaldif%



reselect neighbors.vat info finaldif = %finaldif%

sort neighbors.vat info count descending

&s selected2 := [extract 1 [show select neighbors.vat info ]]

&s count_prev := -99999999



&s flag := 0

&s flag2 := 0



&type Was there a most frequent Value?...



&s qmdfilt3 := [show select neighbors.vat info 1 item newneighbors ]

&s count := [show select neighbors.vat info 1 item count]



&if %selected2% = 1 &then

&do

&s flag := 0

&end



&if %selected2% > 1 &then

&do

&s count2 := [show select neighbors.vat info 2 item count]

&if %count% gt %count2% &then

&s flag := 0

&if %count% eq %count2% &then

&do

&s flag := 1

&end



sort clear

&end





&if %flag% = 0 &then

&do

&type Yes!! A most frequent value was found!!!!

&if %qmdfilt3% = 4 &then

&do

&s index3 := 1

&s priority := 4

&type The majority was 4

/* look for 3,8, or 9

reselect tmp893 info finaldif = %finaldif%

&s selected3 := [extract 1 [show select tmp893 info ]]

sort tmp893 info count descending



&if %selected3% eq 0 &then

&s flag2 := 0

&if %selected3% > 0 &then

&type Is there a most frequent Value amoung 3,8, or 9?...







&s qmdfilt3a := [show select tmp893 info 1 item newneighbors ]

&s counta := [show select tmp893 info 1 item count]



&if %selected3% = 1 &then

&do

&s flag2 := 1

&end



&if %selected3% > 1 &then

&do

&s count2a := [show select tmp893 info 2 item count]

&if %counta% gt %count2a% &then

&s flag2 := 1

&if %counta% eq %count2a% &then

&do

&s flag2 := 2

&end



sort clear tmp893 info

&end



&if %flag2% eq 0 &then

&do

&type Values of 3,8, or 9 were not present

&type the majority = 4

&s majority := 4

&end



&if %flag2% eq 1 &then

&do

&type 3,8, or 9 are present

&s majority = %qmdfilt3a%

&end



&if %flag2% eq 2 &then





&do &while %index3% le %selected3%

&type No!!! There was most frequent value amoung 3 8 or 9...

&type Assigning Unknown according to Rules...

&s qmdfilt3a := [show select tmp893 info %index3% item newneighbors ]

&if %qmdfilt3a% eq 3 and %priority% ge 4 &then

&s priority := 3

&type priority %priority%

&if %qmdfilt3a% eq 9 and %priority% ge 3 &then

&s priority := 2

&if %qmdfilt3a% eq 8 and %priority% ge 2 &then

&s priority := 1



&s index3 = %index3% + 1

&end

&if %priority% = 3 &then

&s majority := 3

&if %priority% = 2 &then

&s majority := 9

&if %priority% = 1 &then

&s majority := 8



clearselect tmp893 info

&type the majority = %majority% priority = %priority%

&end

&if %qmdfilt3% < 11 and %qmdfilt3% ne 4 &then

&do

&s majority := %qmdfilt3%

&type The majority was ne 4 and less than 11

&if %qmdfilt3% eq 6 &then

&do

&type qmdfilt3 was eq 6, setting majority to 10....

&s majority := 10

&end



&if %qmdfilt3% eq 7 &then

&do

&type qmdfilt3 was eq 7, setting majority to 10....

&s majority := 10

&end

&end

&end

&if %qmdfilt3% >= 11 &then

&do

&type The majority was eq %qmdfilt3%,

&type Which was the average of cells ge 11...

&type setting majority to %qmdfilt3% right here!!!

&s majority := %qmdfilt3%

&end





&s index2 := 1



&if %flag% = 1 &then

&do &while %index2% le %selected2%

&type No!!! There was most frequent value...

&type Assigning Unknown according to Rules...

&s qmdfilt3 := [show select neighbors.vat info %index2% item newneighbors ]



&if %qmdfilt3% ge 11 &then

&s majority := %qmdfilt3%

&if %qmdfilt3% eq 6 &then

&s majority := 10

&if %qmdfilt3% eq 7 &then

&s majority := 10

&if %qmdfilt3% eq 5 &then

&s majority := 5

&if %qmdfilt3% eq 2 &then

&s majority := 2

&if %qmdfilt3% eq 3 &then

&s majority := 3

&if %qmdfilt3% eq 4 &then

&s majority := 4

&if %qmdfilt3% eq 1 &then

&s majority := 1

&if %qmdfilt3% eq 9 &then

&s majority := 9

&if %qmdfilt3% eq 8 &then

&s majority := 8



&s index2 = %index2% + 1

&end



&type

&type majority was set to %majority%

calc neighbors.vat info majority = %majority%

clearselect finalreg.vat info

reselect finalreg.vat info keyfile neighbors.vat value keyitem finaldif

calc finalreg.vat info majority = %majority%

clearselect finalreg.vat info

&type ===========================================

&type

&s index = %index% + 1

clearselect neighbors.vat info

&end







&if [exists %outgrid% -grid] &then; kill %outgrid%

setcell %ingrid%

%outgrid% = merge(setnull(finalreg.link == 0,finalreg.majority),%input%)

&goto end



&label end

&return





&label unknown

&type No unknown values are present in this window extent...

&return



&watch &off

&echo &off