-
Notifications
You must be signed in to change notification settings - Fork 95
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conduct focal over part of a SpatRaster [FEATURE REQUEST] #1391
Comments
One way to achieve that could perhaps be by setting windows. I have added a new function |
Thanks @rhijmans, that definitely makes creating the tiles easier, though a bit more description what library(terra)
#> Warning: package 'terra' was built under R version 4.3.2
#> terra 1.7.70
r <- rast(ncols=100, nrows=100)
values(r) <- 1:ncell(r)
x <- rast(ncols=10, nrows=10)
w<- c(3,3) # window size
filename <- paste0(tempfile(), "_.tif")
ff <- makeTiles(r, x, buffer= (w[1]-1)/2, filename)
fname<- vector(mode = "character", length= length(ff))
for (i in 1:length(ff)) {
fname[i]<- tempfile(fileext = ".tif")
focal(rast(ff[i]), filename=fname[i], fun=mean, na.rm=TRUE)
}
z_ref<- focal(r, fun=mean, na.rm=TRUE) #Reference of correct surface
z_vrt<- vrt(fname) #Combine with vrt
z_merge<- do.call(merge, lapply(fname, rast)) #Combine with merge
plot(z_ref-z_vrt, main = "Reference - VRT") plot(z_ref-z_merge, main = "Reference - Merge") plot(z_merge-z_vrt, main="Merge - VRT") Created on 2024-01-30 with reprex v2.0.2 |
I have added a little bit
That was already possible for both
That is correct
Yes, but it would easy to use crop on the tile extents created the same way, but with |
It would also be possible to add a "cores" argument to I think that would also be possible for |
Thanks @rhijmans. Using library(terra)
#> Warning: package 'terra' was built under R version 4.3.2
#> terra 1.7.71
r <- rast(ncols=100, nrows=100)
values(r)<- 1:ncell(r)
x <- rast(ncols=10, nrows=10)
w<- c(3,3) # window size
ff <- makeTiles(r, x, buffer= (w-1)/2, filename= paste0(tempfile(), "_.tif"))
tile_exts_names<- makeTiles(r, x, buffer= 0, filename= paste0(tempfile(), "_.tif"))
tile_exts<- lapply(lapply(tile_exts_names, rast), ext)
invisible(file.remove(tile_exts_names)) #Clear up disk space because only need extents of these rasters
fname<- vector(mode = "character", length= length(ff))
for (i in 1:length(ff)) {
fname[i]<- tempfile(fileext = ".tif")
crop(focal(rast(ff[i]), fun=mean, na.rm=TRUE), y = tile_exts[[i]], filename=fname[i])
}
z_ref<- focal(r, fun=mean, na.rm=TRUE) #Reference of correct surface
z_vrt<- vrt(fname) #Combine with vrt
z_merge<- do.call(merge, lapply(fname, rast)) #Combine with merge
plot(z_ref!=z_vrt, main = "Reference vs VRT") plot(z_ref!=z_merge, main = "Reference vs Merge") Created on 2024-01-31 with reprex v2.0.2 |
@rhijmans, having cores built into library(terra)
#> Warning: package 'terra' was built under R version 4.3.2
#> terra 1.7.71
r <- rast(ncols=99, nrows=99)
values(r)<- rep(1:nrow(r), each=ncol(r)) #Values correspond to row numbers
w<-c(3,3)
buffer<- (w[1]-1)/2
ff <- makeTiles(r, c(33,ncol(r)), buffer= (w[1]-1)/2, filename= paste0(tempfile(), "_.tif"))
length(ff) # 3 tiles
#> [1] 3
#With no buffer, each tile should be 33 rows
tile2<- rast(ff[2]) #Middle tile
fv<- focalValues(tile2, row=buffer+1, nrow= nrow(tile2)-(2*buffer)) # Start at row after buffer on top, and number of rows based on total in tile minus top and bottom buffer
cv<- fv[,ceiling(prod(w)/2)] #Center value of each window
min(cv) # Start from row 34 b/c tile 1 goes
#> [1] 34
max(cv) # End at row 66 b/c tile 3 starts at 67
#> [1] 66 Created on 2024-01-31 with reprex v2.0.2 |
This would require a bit of an overhaul to library(terra)
#> Warning: package 'terra' was built under R version 4.3.2
#> terra 1.7.71
r <- rast(ncols=100, nrows=100)
values(r)<- 1:ncell(r) #Values correspond to row numbers
w<-c(3,3)
focal_rast<- rast(r) #Initialize raster
nlyr(focal_rast)<- prod(w) # Make number of layers equal to number of elements in focal window
fv<- focalValues(r) # Get focal values (not memory safe)
values(focal_rast)<- fv # Each cell contains values from focal window corresponding to that cell in original raster
fv[1,]
#> [1] NA NA NA 100 1 2 200 101 102
focal_rast[1,1,] #Values across layers correspnd to first row of fv
#> lyr.1 lyr.2 lyr.3 lyr.4 lyr.5 lyr.6 lyr.7 lyr.8 lyr.9
#> 1 NA NA NA 100 1 2 200 101 102
z_ref<- focal(r, w=w, fun=mean, na.rm=TRUE) #Reference of correct surface
z_app<- app(focal_rast, fun="mean", na.rm=TRUE)
plot(z_ref==z_app) # Tile focal_rast
x <- rast(ncols=10, nrows=10)
ff <- makeTiles(focal_rast, x, buffer= 0, filename= paste0(tempfile(), "_.tif")) #Tile focal_rast with no buffer because cells include the information needed across layers
fname<- vector(mode = "character", length= length(ff))
for (i in 1:length(ff)) {
fname[i]<- tempfile(fileext = ".tif")
app(rast(ff[i]), fun="mean", na.rm=TRUE, filename=fname[i]) # apply function using app
}
z_app_vrt<- vrt(fname) #Combine with vrt
z_app_merge<- do.call(merge, lapply(fname, rast)) #Combine with merge
plot(z_app_vrt!=z_ref) plot(z_app_merge!=z_ref) Created on 2024-01-31 with reprex v2.0.2 A simple version of this wrapped into a function would be
|
@rhijmans, perhaps a more general option would be to allow for library(terra)
#> Warning: package 'terra' was built under R version 4.3.2
#> terra 1.7.71
r<- rast(volcano,
extent= ext(2667400, 2667400 + ncol(volcano)*10,
6478700, 6478700 + nrow(volcano)*10),
crs = "EPSG:27200")
AOI_shp<- vect(structure(c(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2667400.28, 2667770.32,
2667850.36, 2667990.72, 2667401.44, 2667400.28, 6479302.96, 6479569.76,
6479268.16, 6478699.76, 6478891.16, 6479302.96, 0, 0, 0, 0, 0,
0), dim = 6:5, dimnames = list(NULL, c("geom", "part", "x", "y",
"hole"))), type="polygons", crs=crs(r))
r<- mask(r, AOI_shp)
r<- crop(r, AOI_shp)
plot(r) # 37 percent of cells are NA
round(100*(freq(r, value=NA)$count/ncell(r)))
#> [1] 37
AOI<- rast(r, vals=1)
AOI<- mask(AOI, AOI_shp, updatevalue=0)
plot(AOI) #Maybe focal/focalCpp could use this as an index band to know which cells to calculate over and which ones to skip Created on 2024-03-19 with reprex v2.0.2 |
I'm working on parallelizing focal operations by breaking large rasters into smaller chunk/tiles by row and then sending out each chunk to a different core (ailich/GLCMTextures#25). However, since focal operations require the context of surrounding cells, the first/last row of a chunk that I want to calculate values for requires information from the rows above/below it (I'll call these buffer rows). Conducting
focal
on each of these chunks, trimming them accordingly and merging them back together works; however, sincefocal
goes through all the cells in a raster, the focal calculations are conducted on these buffer rows that themselves do not have the needed context for focal calculations. These are later overwritten by values calculated with the full focal context when merging chunks since there is overlap between chunks. Since these values will be overwritten, there is no need to calculate them and with larger window sizes, more chunks/cores, and more columns, this added computational burden increases. I noticedfocalValues
you can specify where to start and and end extracting values viarow
andnrow
. I was wondering if something similar could be implemented infocalCpp
andfocal
where focal operations would only be conducted for a portion of the raster and things beyond the specified range would just be filled withNA
or a specified fill value.The text was updated successfully, but these errors were encountered: