13

I have a binary raster containing boundary pixels with the value 1 (white) and no-boundary pixels with the value 0 (black):

enter image description here

I would like to vectorize the raster by keeping one center line trough the boundary pixels. However, most polygonize methods I tried (e.g., gdalogr:polygonize, result in two lines around the outline of the boundary pixels (red lines) or no output (saga:gridskeletonization): enter image description here

Did I miss any method with which this can be easily done? Or do I have to vectorize the raster first to a vector layer containing two parallel lines and find a way from there to skeletonize/centerline the two lines?

2 Answers 2

9

GRASS GIS is able do this.

You need two steps:

  1. r.thin

Thins non-null cells that denote linear features in a raster map layer.

  1. r.to.vect

Converts a raster map into a vector map.

5
  • Works for me after setting a nodata value to the raster with gdal_translate -a_nodata.
    – AndreJ
    Aug 8, 2017 at 14:02
  • @RoVo s solution didn't entirely work for me. I was able to start r.thin after converting the binary raster with gdal_translate -ot INT32 src_dataset dst_dataset. It seems that similar conversions are often required before applying r.thin to avoid the error ERROR: Input raster must be of type CELL [see following link] (gis.stackexchange.com/questions/197145/…). However, when running r.to.vect on the raster created with r.thin, GRASS always stops working even when applied to small extents of the raster. Sep 12, 2017 at 7:30
  • That seems to be a different problem.
    – pLumo
    Sep 14, 2017 at 15:47
  • Now it worked for me as @RoVo suggested. The problem were the no-data values. I changed these not with gdal_translate as @AndreJ suggests, but with mapcalc. I will post my answer containing the modules I used as a separate answer below. Sep 19, 2017 at 12:23
  • Came here with this issue some time later, having tried various centerline processes - but this GRASS solution worked PERFECTLY - thanks @RoVo
    – AlecZ
    Nov 21, 2017 at 20:14
7

Now it worked for me as @RoVo suggested before. The problem were the no-data values in my input raster. I changed these not with gdal_translate as @AndreJ suggests (in comments of answer above), but with GRASS r.mapcalc. Here the modules that I used:

Replace all no data values:

processing.runalg('grass:r.mapcalculator',
                  {"amap": gPb_rlayer,
                   "formula": "if(A>0, 1, null())",
                   "GRASS_REGION_PARAMETER": "%f,%f,%f,%f" % (xmin, xmax, ymin, ymax),
                   "GRASS_REGION_CELLSIZE_PARAMETER": 1,
                   "outfile": mapcalc})

Thin raster layer to thin non-null cells:

processing.runalg('grass7:r.thin',
                  {"input": mapcalc,
                   "GRASS_REGION_PARAMETER": "%f,%f,%f,%f" % (xmin, xmax, ymin, ymax),
                   "output": thinned})

Raster to vector conversion:

processing.runalg('grass7:r.to.vect',
                  {"input": thinned,
                   "type": 0,
                   "GRASS_OUTPUT_TYPE_PARAMETER": 2,
                   "GRASS_REGION_PARAMETER": "%f,%f,%f,%f" % (xmin, xmax, ymin, ymax),
                   "output": centerlines})

enter image description here

2
  • This worked in QGIS as well, although r.thin took like an hour to complete. Feb 8, 2022 at 0:57
  • Thank you so much! This finally worked for me!
    – Ian Moffit
    Jun 10, 2023 at 1:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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