I've tried to come up with an open-source equivalent to the following process in ArcGIS 10.3:

  1. Spatial Analyst Toolbox > Extract by Mask
  2. target input: 1" SRTM DEM in EPSG 4019
  3. mask layer: single rectangular polygon, shapefile in EPSG 4283
  4. Environment Settings: Snap Raster to target input, output coordinate system EPSG 4283

This gets me a 'perfect' clip - no changes to pixel size or alignment, identical cell values in the output. The output doesn't align perfectly to the clipping polygon of course, but I don't need it to. Arc just extracts all the cells intersecting the polygon (although I note that the top-most and right-most columns are set to no-data, presumably because their upper-right corners were outside the bounding box).

I've worked out one solution using GRASS 7 and GDAL processing tools in QGIS 2.14.3:

  1. Create a mapset and import the raster to be clipped
  2. Run g.region.multiple.raster so that region settings match the imported dataset
  3. Use v.in.ogr to import the bounding box shapefile
  4. Use v.to.rast.constant to convert the bounding box to a raster with value 1 for all cells. The output is aligned with the input due to the region settings.
  5. Use g.region.zoom with the new raster boundary to shrink the region without altering cell size or alignment
  6. use r.out.gdal.geotiff to export the source dataset. Only the area within the updated region is exported.
  7. Use gdalwarp to re-project the output .tif in EPSG 4283

The output is nearly identical to the ESRI workflow, but where ESRI set the top-most and right-most columns to no-data, GRASS just didn't export them. Fine by me.

Can an equivalent procedure be run in QGIS without using GRASS?

  • This should be achievable with gdal_translate and gdal_warp - look under Raster > Extraction > Clipper – vinh Jun 21 '16 at 23:04
  • You certainly can use gdal_warp @vinh (QGIS's inbuilt raster clipper calls it when you choose a masking layer), but you have to leave the -crop-to-cutline tag off if you want to keep cell alignment. Under those circumstances, cell values outside the mask are simply replaced with nodata instead of being properly removed. This was...unexpected behaviour, and I can't find a way to remove the resultant halo of completely pointless nodata cells :/ – obrl_soil Jun 22 '16 at 0:10

This is a very good question. I have the same. Gdal do not have this feature and I don't understand why (it's explain here: https://trac.osgeo.org/gdal/ticket/3947). It's simple crop, it's basic I think and should be easy...

Anyway, there is one opensource option (not QGIS) I've found and it's to use R. It works, however it's slow and if you don't know R, it can be kind of a pain to learn... I write it here in case other people have this problem.

in R:

the_raster <- raster("yourfile.tif")
the_polygon <- readOGR("yourfolder","yourPol")
your_mask_raster <- mask(the_raster,the_polygon)
your_final_crop_raster <- trim(your_mask_raster)
writeRaster(your_final_crop_raster, file="crop_raster.tif")

Projection can be manage in R as well, or by gdal on extrated files.

  • Nice, that's very similar to a workflow I ended up using. I've come a long way since I asked this question, will post some options as an answer. – obrl_soil Oct 13 '16 at 7:27

Ok, having learnt a lot of stuff in the months since I asked this question, here are a couple of options:

In R, very similar to Bastien's answer:


rootdir <- 'C:/Users/obrl_soil/Downloads'
tinyraster <- raster('tinyrast.tif')
tinypolygon <- readOGR('tinypolygon.shp')

# alter your mask polygon to line up with the nearest pixel edges
tpoly_aligned <- alignExtent(tinypolygon, tinyraster, snap='near')

# clip and export in one hit
tinyclip <- crop(tinyraster, tpoly_aligned, filename='tinyclip.tif')

I noticed when checking the outputs in QGIS that writeRaster introduced some spurious data in the output tif, but crop didn't - e.g. input elevation for a pixel was 108.10545, output with crop was the same, but output with writeRaster was 108.10545349121094.

Alternate workflow - get the polygon bounding box coordinates and feed them into gdal_translate using -projwin. Just be careful which version of gdal_translate you use!. 1.11 is fine, and 2.1.2 should be when its released.

You can also do this in R, like

gtrans111 <- 'C:/Program Files/GDAL/gdal_translate.exe'
tinypolygon <- readOGR('tinypolygon.shp')
tpbb <- toString(c(tinypolygon@bbox[1], tinypolygon@bbox[4],
                   tinypolygon@bbox[3], tinypolygon@bbox[2]))
tpbb <- gsub(', ', ' ', tpbb)

system2(gtrans111, args= c('-projwin', tpbb, 'tinyraster.tif', 'tinyclip2.tif' ))

or even bypass creating any R objects by just inputting the polygon bounding coordinates directly

system2(gtrans111, args= c('-projwin', '148.665 -20.88 148.67 -20.884', 
                           'tinyraster.tif', 'tinyclip3.tif'))

The output extent is not identical to the raster package methods, but does align correctly. All of these methods are easy to loop across multiple datasets, which is the real advantage of R. You can do something similar in Python too.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.