Select to view content in your preferred language

Is there a way to increase the search radius of nearest neighbors for the Nibble tool

1325
5
Jump to solution
03-12-2013 11:32 AM
MaritzaMallek
Occasional Contributor
I am working with a raster map vegetation types. I have about 20 types with unique raster code values that can be sorted into three classes:

1 - vegetation types I want to expand using the nibble function (e.g. forest)

2 - vegetation types I consider static that I do not want to either nibble or be nibbled (e.g. water, developed areas)

3 - vegetation types that I want to eliminate through the nibble function (early seral stages, such as grass and chaparral)

The first time I ran this I was under a deadline and didn't have time to figure out a better solution, and wasn't able to find one googling/searching. I'm hoping to find a way to make this a shorter geoprocessing slog.

As inputs to the Nibble, I reclassified my veg layer so that the type 2 (static) values were nodata, since I didn't want them to nibble. That was my input layer. For the input MASK, I reclassified the original raster but made the type 3 values nodata, since they are the ones I want to eliminate through nibbling.

The catch is that I tend to have large amounts of type 3 clustered together, and on top of that there are several places where the type 2 and type 3 values are clustered near each other. The upshot is that the nibble gave me an incomplete output. It ran correctly, as far as I could tell, but it would stop before nibbling away all of the masked values.

I think the problem is that the nibble function has some predetermined search radius for the nearest neighbor, and if a cell is surrounded by type 2 and 3 cells then it can be so far away from a type 1 cell that the nibble doesn't reach it. However, looking into the tools, the whole Nibble tool is just one function that is called with those two inputs, so I can't modify the python code to change the search radius. I am not skilled enough in python to write a loop that would run the nibble over and over again.

So, is there a way to get the Nibble to fill in more of the masked values at a time? Is there a place I can get the Nibble code to try and modify it? I would imagine at some point a distance threshold was specified.

Thanks in advance!
0 Kudos
1 Solution

Accepted Solutions
curtvprice
MVP Alum
UPDATE: it gets better, you can do this in one raster calculator expression that is easy to tweak if you change your mind about how to handle your classes. This all goes on one line -- I have separated it to make it easier to read:

Con("landcover","landcover",   Nibble("landcover",SetNull("landcover","landcover","VALUE NOT IN (1,2)")),   "VALUE IN (3,4,5)")


1. Keep 3,4,5 cells as-is
2. Expand 1,2 cells everywhere else
(All values not mentioned will be overwritten by values 1 or 2)

View solution in original post

0 Kudos
5 Replies
curtvprice
MVP Alum
I am working with a raster map vegetation types. I have about 20 types with unique raster code values that can be sorted into three classes:

1 - vegetation types I want to expand using the nibble function (e.g. forest)
2 - vegetation types I consider static that I do not want to either nibble or be nibbled (e.g. water, developed areas)
3 - vegetation types that I want to eliminate through the nibble function (early seral stages, such as grass and chaparral)


Nibble is tricky.

Nibble doesn't use a search radius - it requires adjacency to grow raster zones. It can't "jump" across a non-NoData area in your mask.

Assume:

Forest = 1 (expand)
Forest2 = 2 (expand)
Water = 3 (keep)
Developed = 4 (keep)
(Other - to be nibbled - deleted)

I'm assuming you're using the Raster Calculator tool here.

1. Set all cells to NoData except 1 and 2 cells

SetNull("landcover" != 1 and "landcover" != 2, "landcover")    -> "maskras"

2.  (nibble 1,2 cells into all nodata areas)

Nibble("landcover","maskras")  -> "nibras"

3. "burn" class 3 and 4 cells back into raster results at their original locations

Con("landcover" == 3 or "landcover" == 4, "landcover", "nibras")
0 Kudos
MaritzaMallek
Occasional Contributor
Hi, thanks for responding to my question.

Thanks for the tip about Nibble - I wasn't sure because there isn't really detailed information on how it works and the source code isn't posted. It wouldn't necessarily need to jump across a noData area, but I want it to continue Nibbling farther than it does, I guess, especially when a cell is surrounded half by nodata and half by some other value. I get to the point where only one or two cells are nibbled at a time, which is very tedious (diminishing returns).

I have not been using Raster Calculator, just doing a reclassify in between Nibble operations? Is this ill-advised for any reason. I haven't used the Raster Calculator ever before, actually, but it doesn't look too bad. Perhaps it might be more efficient?

I was trying to be concise earlier, but it seems my original post was a little misleading. I have classes that can be roughly though about as 3 overall types, but there are more than just those listed in my original post. What I really have are 14 vegetation types I want to nibble into 6 other vegetation types, while avoiding 6 distinct "other" types. Water is just one example of those 6 "other" types.

Still, I am basically using the method you describe below (I think that is the standard method for using Nibble, right?). The problem is that the nibble doesn't fill in all of the nodata. It stops short, and then I have to rerun the Nibble over and over and over again (10-15 times) and it gets to the point where each Nibble is taking away one pixel across my entire database (which has millions). I was hoping there is a method to provoke the Nibble function to nibble more pixels at a time.

Nibble is tricky.

Nibble doesn't use a search radius - it requires adjacency to grow raster zones. It can't "jump" across a non-NoData area in your mask.

Assume:

Forest = 1 (expand)
Forest2 = 2 (expand)
Water = 3 (keep)
Developed = 4 (keep)
(Other - to be nibbled - deleted)

I'm assuming you're using the Raster Calculator tool here.

1. Set all cells to NoData except 1 and 2 cells

SetNull("landcover" != 1 and "landcover" != 2, "landcover")    -> "maskras"

2.  (nibble 1,2 cells into all nodata areas)

Nibble("landcover","maskras")  -> "nibras"

3. "burn" class 3 and 4 cells back into raster results at their original locations

Con("landcover" == 3 or "landcover" == 4, "landcover", "nibras")
0 Kudos
curtvprice
MVP Alum
  I want it to continue Nibbling farther than it does, I guess, especially when a cell is surrounded half by nodata and half by some other value. I get to the point where only one or two cells are nibbled at a time, which is very tedious (diminishing returns).... I was hoping there is a method to provoke the Nibble function to nibble more pixels at a time


Does the input raster (first argument to Nibble) have any NoData in it? If you want all the NoData filled in, the first input should be all data cells. The NoData in the second raster defines where Nibble will go. (In my example, I was assuming that all of the landcover raster had all data cells, at least everywhere you wanted to fill in.)

I have not been using Raster Calculator, just doing a reclassify in between Nibble operations? Is this ill-advised for any reason. I haven't used the Raster Calculator ever before, actually, but it doesn't look too bad. Perhaps it might be more efficient?


Raster Calculator is a lot more efficient if you are nesting functions. I think for your problem Con is easier to work with than Reclassify, but that's just a personal preference.


I was trying to be concise earlier, but it seems my original post was a little misleading. I have classes that can be roughly though about as 3 overall types, but there are more than just those listed in my original post. What I really have are 14 vegetation types I want to nibble into 6 other vegetation types, while avoiding 6 distinct "other" types. Water is just one example of those 6 "other" types.


My example should still work for you.

The Con function can be used with a list of values using its "where_expr" to form more complicated queries. So, for example to "keep" classes 3,4,8,11,12, and 13, replace the last step with:

Con("landcover", "landcover", "nibras", "VALUE IN (3,4,8,11,12,13)")

In the above example, "landcover" cells for the listed classes will be "True" so they will be burned into the output, i.e. they will be the same value as the same cell in "landcover". All other cells (where_expr evaluated to "False")  will pick up the value of your nibble output ("nibras").

As you can see this less work than filling out the Reclassify tool dialog, especially if you need to change things and re-run it.
0 Kudos
curtvprice
MVP Alum
UPDATE: it gets better, you can do this in one raster calculator expression that is easy to tweak if you change your mind about how to handle your classes. This all goes on one line -- I have separated it to make it easier to read:

Con("landcover","landcover",   Nibble("landcover",SetNull("landcover","landcover","VALUE NOT IN (1,2)")),   "VALUE IN (3,4,5)")


1. Keep 3,4,5 cells as-is
2. Expand 1,2 cells everywhere else
(All values not mentioned will be overwritten by values 1 or 2)
0 Kudos
MaritzaMallek
Occasional Contributor
UPDATE: it gets better, you can do this in one raster calculator expression that is easy to tweak if you change your mind about how to handle your classes. This all goes on one line -- I have separated it to make it easier to read:

Con("landcover","landcover",
  Nibble("landcover",SetNull("landcover","landcover","VALUE NOT IN (1,2)")),
  "VALUE IN (3,4,5)")


1. Keep 3,4,5 cells as-is
2. Expand 1,2 cells everywhere else
(All values not mentioned will be overwritten by values 1 or 2)


Wow, this is amazing. This is exactly what I have been trying to do. This will literally save me hours, if not days. Thank you SO much. I suppose I should invest some more time in learning Raster Calculator tricks.
0 Kudos