Search code examples
rimageimage-processingsplitraster

R raster package split image into multiples


I have an image as below. It is 2579*2388 pixels. Lets assume that it's bottom left corner is at 0,0. From that image I want to create multiple images as follows and save them in the working folder. Each image will have size of 100*100 pixels. Each image will be saved by it's bottom left hand coordinates.

  1. first image will have its bottom left hand corner at 0,0. Top right hand corner will be at 100,100 and the image will be saved as 0-0.jpg
  2. second will have its bottom left hand corner at 10,0. Top right hand corner will be at 110,100 and the image will be saved as 10-0.jpg
  3. Once the bottom row is completed, Y coordinate will move by 10. In case of second row, the first image will be at 0,10 and that image will be saved as 0-10.jpg

what is the fastest way to do this? is there any R package which could do it very fast?

I understand that in the case of the current image, it will split it into around 257*238 images. But I have sufficient disk space and i need each image to perform text detection.

enter image description here


Solution

  • Here another approach using "raster" package. The function spatially aggregates the raster to be chopped, the aggregated raster cells are turned into polygons, then each polygon's extent is used to crop the input raster.

    I am sure there are sophisticated and compact ways to do this but this approach works for me and I found it intuitive as well. I hope you find it useful too. Notice Part 4 & 5 below are only for testing and they are not part of the function.

    enter image description here

    Part 1: Load and plot sample raster data

    logo <- raster(system.file("external/rlogo.grd", package="raster"))
    plot(logo,axes=F,legend=F,bty="n",box=FALSE)
    

    Part 2: The function itself:

    # The function spatially aggregates the original raster
    # it turns each aggregated cell into a polygon
    # then the extent of each polygon is used to crop
    # the original raster.
    # The function returns a list with all the pieces
    # in case you want to keep them in the memory. 
    # it saves and plots each piece
    # The arguments are:
    # raster = raster to be chopped            (raster object)
    # ppside = pieces per side                 (integer)
    # save   = write raster                    (TRUE or FALSE)
    # plot   = do you want to plot the output? (TRUE or FALSE)
    SplitRas <- function(raster,ppside,save,plot){
      h        <- ceiling(ncol(raster)/ppside)
      v        <- ceiling(nrow(raster)/ppside)
      agg      <- aggregate(raster,fact=c(h,v))
      agg[]    <- 1:ncell(agg)
      agg_poly <- rasterToPolygons(agg)
      names(agg_poly) <- "polis"
      r_list <- list()
      for(i in 1:ncell(agg)){
        e1          <- extent(agg_poly[agg_poly$polis==i,])
        r_list[[i]] <- crop(raster,e1)
      }
      if(save==T){
        for(i in 1:length(r_list)){
          writeRaster(r_list[[i]],filename=paste("SplitRas",i,sep=""),
                      format="GTiff",datatype="FLT4S",overwrite=TRUE)  
        }
      }
      if(plot==T){
        par(mfrow=c(ppside,ppside))
        for(i in 1:length(r_list)){
          plot(r_list[[i]],axes=F,legend=F,bty="n",box=FALSE)  
        }
      }
      return(r_list)
    }
    

    Part 3: Test the function

    SplitRas(raster=logo,ppside=3,save=TRUE,plot=TRUE)
    # in this example we chopped the raster in 3 pieces per side
    # so 9 pieces in total
    # now the raster pieces should be ready 
    # to be processed in the default directory
    # A feature I like about this function is that it plots
    # the pieces in the original order. 
    

    Part 4: Run a code on each piece & save them back in directory

    # notice if you cropped a rasterbrick 
    # use "brick" instead of "raster" to read
    # the piece back in R
    list2 <- list()
    for(i in 1:9){ # change this 9 depending on your number of pieces
      rx <- raster(paste("SplitRas",i,".tif",sep=""))
      # piece_processed <- HERE YOU RUN YOUR CODE
      writeRaster(piece_processed,filename=paste("SplitRas",i,sep=""),
                  format="GTiff",datatype="FLT4S",overwrite=TRUE)
    }
    # once a code has been ran on those pieces
    # we save them back in the directory 
    # with the same name for convenience
    

    Part 5: Let us put the pieces back together

    # read each piece back in R
    list2 <- list()
    for(i in 1:9){ # change this 9 depending on your number of pieces
      rx <- raster(paste("SplitRas",i,".tif",sep=""))
      list2[[i]] <- rx
    }
    # mosaic them, plot mosaic & save output
    list2$fun   <- max
    rast.mosaic <- do.call(mosaic,list2)
    plot(rast.mosaic,axes=F,legend=F,bty="n",box=FALSE)
    writeRaster(rast.mosaic,filename=paste("Mosaicked_ras",sep=""),
                format="GTiff",datatype="FLT4S",overwrite=TRUE)