I have a DEM and I want to find each hill and create a polygon for its area, effectively the out closed contour that encloses the hill. I can do this visually but I'm about to work on a larger area so need to find a way of scanning the DEM for structural highs.

Is there a tool that does this, or a workflow that might get me close to my results. I've been looking through the hydrology tools in ArcGIS and they look promising but I'm not sure they can quite produce what I'm looking for - If there was one that would identify areas where lakes would formn that could work if I invert my DEM.

Has anyone done this before of do they know how to do it? I'm using ArcGIS desktop 10.2 at the moment but if you have a solution in other software I'm interested.

  • 1
    Actually, there are such functions in the hydrology tools. Check out Fill Sinks. With an inverted DEM I think it'll take you pretty close to what you need - areas that will be filled with water in a rain event. However, it'll also include very small hills/sinks, so you might need to experiment a bit with the settings. Can also recommend using the functions in (the free) ArcHydro Tools instead, more settings to change there :) – Martin Sep 11 '15 at 9:10
  • 1
    Have you tried extracting contours, and then converting those polylines to polygons? Then the challenge becomes selecting the right polygons, but that is significantly easier. – Mikkel Lydholm Rasmussen Sep 11 '15 at 9:22
  • A search on "arcgis local maximum" would likely turn up useful posts on this topic. – Vince Sep 11 '15 at 11:08
  • How about computing a slope raster and vectorize areas where slope is close to zero? It would find hilltops but also bottoms of valleys and lakes and other flat areas too so perhaps it is not a useful method. – user30184 Sep 11 '15 at 13:26
  • I like the idea of inverting the DEM and getting the 'sinks', which would be hill tops. You can always remove small areas by after converting to polygons and removing polygons smaller than some value. – Tangnar Sep 11 '15 at 13:44

One easy way of doing this would be to inverse your DEM by multiplying it by negative one (Raster Calculator) then running the Fill tool on the inverted DEM. Finally, subtract the filled DEM from the inverted and multiply by negative one again (putting it back to the original scale). This will effectively turn peaks into depressions and find the spill height of each closed depression, i.e. the height of the closed contour surrounding the peak/depression.


What I found worked best incorporated all of the answers so I thought I'd add it here rather than accept just one of them. I used the 'peak' tool suggested by Hornbydd to create points at each peak, then I inverted my raster and ran it again to find the low points. I contoured the DEM to a high resolution then converted the lines into polygons in ET Geowizards (or FME). I then took a high as being a polygon that contained a peak but no troughs, and found these using select by location then exported the selection and dissolved it to marge the concentric polygons.

The code is:

##add extra toolboxes
arcpy.AddToolbox("...\Spatial Analyst Supplemental Tools.pyt")
arcpy.AddToolbox("...\ET GeoWizards.tbx")

##use the peak tool to generate a point at each peak (which are areas of local maximum elevation)
arcpy.Peak_sas(myDEM, "peakrast.tif", "peakpoints.shp")
##Invert the raster and use the peak tool to fint troughs
invDEM = Raster(myDEM)*(-1)
arcpy.Peak_sas(invDEM, "troughrast.tif", "troughpoints.shp")
##create contours from the DEM - high res
##convert closed contours to polygons
##for small data sets this method will work but for larger there may not be enough ram - if this if the case use FME and use the AreaBuilder transformer and set create Doughnuts to no
arcpy.ET_GPPolylineToPolygon("Contours_L_1m.shp", "Contours_G_1m.shp", "FALSE")
##select closed contours containing peaks but no troughs and export to a new FC
arcpy.SelectLayerByLocation_management("Contours_G_1m", "CONTAINS", "peakpoints.shp")
arcpy.FeatureClassToFeatureClass_conversion("Contours_G_1m.shp", arcpy.env.workspace, "HIGHS_raw.shp")
##select closed contours containing peaks and export to a new FC
#arcpy.SelectLayerByLocation_management("Contours_G_1m.shp", "CONTAINS", "peakpoints.shp")
#arcpy.FeatureClassToFeatureClass_conversion("Contours_G_1m.shp", arcpy.env.workspace, "Peak_Areas.shp")
##select closed contours containing troughs but no peaks and export to a new FC
#arcpy.SelectLayerByLocation_management("Contours_G_1m.shp", "CONTAINS", "troughpoints.shp")
#arcpy.FeatureClassToFeatureClass_conversion("Contours_G_1m.shp", arcpy.env.workspace, "Low_Areas.shp")
##create a new featureclass that is the highs with the lows removed
#arcpy.Erase_analysis("Peak_Areas.shp", "Low_Areas.shp", "HIGHS_raw.shp")
##dissolve the feature as it is made of many concentric polygons
arcpy.Dissolve_management("HIGHS_raw.shp", "HIGHS_diss.shp")
##split The dissolved feature into single featues and add an area field
arcpy.MultipartToSinglepart_management("HIGHS_diss.shp", "final_HIGHS.shp")
arcpy.AddField_management("final_HIGHS.shp", "AREA_CALC", "DOUBLE","","","","Area")
arcpy.CalculateField_management("final_HIGHS.shp", "AREA_CALC","!Shape!.area","PYTHON_9.3")

What this doesn't do is find highs with a little low in the middle - thats what option 2 in the code is trying to do. I didnt quite get that to work because it would also create big donuts where there is a small high on the edge of a big low area. I think the perfect option would be option two then somehow checking that the inner and outer edges of the donuts are at the same height. For now though, I'm sticking with option 1.


You should always search Arcscripts website as there are many user community tools already written.

A quick search of the word "peak" threw up the Spatial Analyst Supplemental Tools.


Use the raster calculator where you create a new raster with the expression dgm_layer>=x where x is the height you need for your contour line. That will select all pixels that are located higher, necessarily on your hill tops.

You should be able to do a raster-to-vector conversion of those areas afterwards, if you need.

UPDATE: as pointed out by user30184 this is only valid for absolute heights, not local maxima.

  • Does not feel like a very good method because low hills have also their tops. It is not bound to absolute height but relative to surroundings. – user30184 Sep 11 '15 at 13:29
  • This is a good point. Of course this is valid only for absolute heights, not local maxima. So maybe thats not the precise solution for the question. – ulrich Sep 11 '15 at 13:49

Your Answer

