[{"data":1,"prerenderedAt":1741},["ShallowReactive",2],{"doc:\u002Fspatial-data-processing-automation\u002Fraster-analysis-workflows\u002Fpolygonize-raster-to-vector-pyqgis":3},{"id":4,"title":5,"body":6,"description":1730,"extension":1731,"meta":1732,"navigation":240,"path":1737,"seo":1738,"stem":1739,"__hash__":1740},"docs\u002Fspatial-data-processing-automation\u002Fraster-analysis-workflows\u002Fpolygonize-raster-to-vector-pyqgis\u002Findex.md","Polygonize a Raster to Vector in PyQGIS",{"type":7,"value":8,"toc":1715},"minimark",[9,13,17,31,173,178,193,197,200,465,472,476,481,610,619,623,626,694,697,701,704,798,806,810,813,854,1076,1090,1094,1097,1321,1335,1339,1342,1562,1571,1575,1593,1597,1623,1627,1630,1634,1640,1646,1656,1662,1672,1678,1682,1711],[10,11,5],"h1",{"id":12},"polygonize-a-raster-to-vector-in-pyqgis",[14,15,16],"p",{},"Classified rasters — land cover, flood extent, a reclassified slope map, a suitability score in bands — are often needed as polygons: to compute areas per class within districts, to overlay with parcels, to publish as vector data, or to edit by hand. Polygonizing turns each connected group of same-valued pixels into a polygon carrying that value. Done naively on raw output it produces hundreds of thousands of tiny polygons with staircase edges; done with a little preparation it produces a clean, usable layer.",[14,18,19,20,25,26,30],{},"This recipe belongs to ",[21,22,24],"a",{"href":23},"\u002Fspatial-data-processing-automation\u002Fraster-analysis-workflows\u002F","Raster Analysis Workflows",". It prepares the raster, runs ",[27,28,29],"code",{},"gdal:polygonize",", removes NoData and speckle, dissolves by class, smooths edges and computes areas.",[14,32,33],{},[34,35,40,44,48,55,72,81,90,96,101,105,112,117,121,124,127,131,136,139,142,145,149,155,161,165,169],"svg",{"viewBox":36,"role":37,"ariaLabel":38,"xmlns":39},"0 0 760 226","img","Classified raster sieved to remove speckle, polygonized into class polygons, then cleaned by dropping NoData, dissolving and simplifying","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg",[41,42,43],"title",{},"Prepare, polygonize, clean",[45,46,47],"desc",{},"A classified raster with scattered single pixels is first smoothed with a sieve filter that merges regions smaller than a threshold into their neighbours. gdal:polygonize then turns each connected region into a polygon with its class value. The result is cleaned by dropping NoData polygons, dissolving by class if needed, and simplifying or smoothing staircase edges before areas are computed.",[49,50],"rect",{"x":51,"y":51,"width":52,"height":53,"fill":54},"0","760","226","#f6f3ea",[56,57,58],"defs",{},[59,60,67],"marker",{"id":61,"viewBox":62,"refX":63,"refY":64,"markerWidth":65,"markerHeight":65,"orient":66},"polyFlowArrow","0 0 10 10","8","5","7","auto-start-reverse",[68,69],"path",{"d":70,"fill":71},"M0 0 L10 5 L0 10 z","#2f3b35",[73,74,80],"text",{"x":75,"y":76,"style":77,"fill":78,"textAnchor":79},"380","28","text-anchor:middle;font-size:14px;font-family:sans-serif;font-weight:bold","#17211d","middle","Fewer, cleaner polygons start in the raster",[49,82],{"x":83,"y":84,"width":85,"height":86,"rx":63,"fill":87,"stroke":88,"style":89},"24","60","160","150","#fffdf7","#59645f","stroke-width:2",[73,91,95],{"x":92,"y":93,"style":94,"fill":78,"textAnchor":79},"104","112.78","text-anchor:middle;font-size:11.5px;font-family:sans-serif;font-weight:bold","classified",[73,97,100],{"x":92,"y":98,"style":99,"fill":71,"textAnchor":79},"138.78","text-anchor:middle;font-size:10.5px;font-family:sans-serif","raster",[73,102,104],{"x":92,"y":103,"style":99,"fill":88,"textAnchor":79},"164.78","with speckle",[106,107],"line",{"x1":108,"y1":109,"x2":110,"y2":109,"stroke":71,"style":111},"184","135","220","stroke-width:1.8;marker-end:url(#polyFlowArrow)",[49,113],{"x":114,"y":84,"width":85,"height":86,"rx":63,"fill":115,"stroke":116,"style":89},"224","#fdf2e2","#b45309",[73,118,120],{"x":119,"y":93,"style":94,"fill":116,"textAnchor":79},"304","gdal:sieve",[73,122,123],{"x":119,"y":98,"style":99,"fill":88,"textAnchor":79},"merge regions",[73,125,126],{"x":119,"y":103,"style":99,"fill":88,"textAnchor":79},"\u003C N pixels",[106,128],{"x1":129,"y1":109,"x2":130,"y2":109,"stroke":71,"style":111},"384","420",[49,132],{"x":133,"y":84,"width":85,"height":86,"rx":63,"fill":134,"stroke":135,"style":89},"424","#eef7f4","#0f766e",[73,137,29],{"x":138,"y":93,"style":94,"fill":135,"textAnchor":79},"504",[73,140,141],{"x":138,"y":98,"style":99,"fill":88,"textAnchor":79},"one polygon per",[73,143,144],{"x":138,"y":103,"style":99,"fill":88,"textAnchor":79},"connected region",[106,146],{"x1":147,"y1":109,"x2":148,"y2":109,"stroke":71,"style":111},"584","620",[49,150],{"x":151,"y":84,"width":152,"height":86,"rx":63,"fill":153,"stroke":154,"style":89},"624","112","#e8efe6","#15803d",[73,156,160],{"x":157,"y":158,"style":94,"fill":159,"textAnchor":79},"680","102.78","#166534","clean",[73,162,164],{"x":157,"y":163,"style":99,"fill":88,"textAnchor":79},"126.78","NoData",[73,166,168],{"x":157,"y":167,"style":99,"fill":88,"textAnchor":79},"150.78","dissolve",[73,170,172],{"x":157,"y":171,"style":99,"fill":88,"textAnchor":79},"174.78","simplify",[174,175,177],"h2",{"id":176},"prerequisites","Prerequisites",[179,180,181,185],"ul",{},[182,183,184],"li",{},"QGIS 3.34 LTR or newer, or the QGIS 4 series, with the GDAL provider.",[182,186,187,188,192],{},"A classified integer raster: land-cover codes, flood\u002Fno-flood, suitability classes. Continuous rasters such as elevation must be reclassified first, as in ",[21,189,191],{"href":190},"\u002Fspatial-data-processing-automation\u002Fraster-analysis-workflows\u002Freclassify-raster-values-pyqgis\u002F","reclassifying raster values",".",[174,194,196],{"id":195},"remove-speckle-before-polygonizing","Remove speckle before polygonizing",[14,198,199],{},"Classification output is noisy: isolated pixels and tiny clusters that become thousands of meaningless polygons. A sieve filter merges regions smaller than a pixel threshold into their largest neighbour, in the raster, where it is fast.",[201,202,207],"pre",{"className":203,"code":204,"language":205,"meta":206,"style":206},"language-python shiki shiki-themes github-dark","import processing\nfrom qgis.core import QgsRasterLayer\n\nsrc = \"\u002Fdata\u002Flandcover\u002Fclassified_2026.tif\"\nlayer = QgsRasterLayer(src, \"classified\")\npx_area = layer.rasterUnitsPerPixelX() * layer.rasterUnitsPerPixelY()\nmin_area_m2 = 500\nthreshold = max(1, int(min_area_m2 \u002F px_area))\nprint(f\"pixel {px_area:.0f} m² → sieve threshold {threshold} pixels\")\n\nsieved = processing.run(\"gdal:sieve\", {\n    \"INPUT\": src, \"THRESHOLD\": threshold, \"EIGHT_CONNECTEDNESS\": False,\n    \"NO_MASK\": False, \"MASK_LAYER\": None,\n    \"OUTPUT\": \"\u002Fdata\u002Flandcover\u002Fclassified_2026_sieved.tif\"})[\"OUTPUT\"]\n","python","",[27,208,209,221,235,242,255,272,289,301,333,374,379,396,423,445],{"__ignoreMap":206},[210,211,213,217],"span",{"class":106,"line":212},1,[210,214,216],{"class":215},"snl16","import",[210,218,220],{"class":219},"s95oV"," processing\n",[210,222,224,227,230,232],{"class":106,"line":223},2,[210,225,226],{"class":215},"from",[210,228,229],{"class":219}," qgis.core ",[210,231,216],{"class":215},[210,233,234],{"class":219}," QgsRasterLayer\n",[210,236,238],{"class":106,"line":237},3,[210,239,241],{"emptyLinePlaceholder":240},true,"\n",[210,243,245,248,251],{"class":106,"line":244},4,[210,246,247],{"class":219},"src ",[210,249,250],{"class":215},"=",[210,252,254],{"class":253},"sU2Wk"," \"\u002Fdata\u002Flandcover\u002Fclassified_2026.tif\"\n",[210,256,258,261,263,266,269],{"class":106,"line":257},5,[210,259,260],{"class":219},"layer ",[210,262,250],{"class":215},[210,264,265],{"class":219}," QgsRasterLayer(src, ",[210,267,268],{"class":253},"\"classified\"",[210,270,271],{"class":219},")\n",[210,273,275,278,280,283,286],{"class":106,"line":274},6,[210,276,277],{"class":219},"px_area ",[210,279,250],{"class":215},[210,281,282],{"class":219}," layer.rasterUnitsPerPixelX() ",[210,284,285],{"class":215},"*",[210,287,288],{"class":219}," layer.rasterUnitsPerPixelY()\n",[210,290,292,295,297],{"class":106,"line":291},7,[210,293,294],{"class":219},"min_area_m2 ",[210,296,250],{"class":215},[210,298,300],{"class":299},"sDLfK"," 500\n",[210,302,304,307,309,312,315,318,321,324,327,330],{"class":106,"line":303},8,[210,305,306],{"class":219},"threshold ",[210,308,250],{"class":215},[210,310,311],{"class":299}," max",[210,313,314],{"class":219},"(",[210,316,317],{"class":299},"1",[210,319,320],{"class":219},", ",[210,322,323],{"class":299},"int",[210,325,326],{"class":219},"(min_area_m2 ",[210,328,329],{"class":215},"\u002F",[210,331,332],{"class":219}," px_area))\n",[210,334,336,339,341,344,347,350,353,356,359,362,364,367,369,372],{"class":106,"line":335},9,[210,337,338],{"class":299},"print",[210,340,314],{"class":219},[210,342,343],{"class":215},"f",[210,345,346],{"class":253},"\"pixel ",[210,348,349],{"class":299},"{",[210,351,352],{"class":219},"px_area",[210,354,355],{"class":215},":.0f",[210,357,358],{"class":299},"}",[210,360,361],{"class":253}," m² → sieve threshold ",[210,363,349],{"class":299},[210,365,366],{"class":219},"threshold",[210,368,358],{"class":299},[210,370,371],{"class":253}," pixels\"",[210,373,271],{"class":219},[210,375,377],{"class":106,"line":376},10,[210,378,241],{"emptyLinePlaceholder":240},[210,380,382,385,387,390,393],{"class":106,"line":381},11,[210,383,384],{"class":219},"sieved ",[210,386,250],{"class":215},[210,388,389],{"class":219}," processing.run(",[210,391,392],{"class":253},"\"gdal:sieve\"",[210,394,395],{"class":219},", {\n",[210,397,399,402,405,408,411,414,417,420],{"class":106,"line":398},12,[210,400,401],{"class":253},"    \"INPUT\"",[210,403,404],{"class":219},": src, ",[210,406,407],{"class":253},"\"THRESHOLD\"",[210,409,410],{"class":219},": threshold, ",[210,412,413],{"class":253},"\"EIGHT_CONNECTEDNESS\"",[210,415,416],{"class":219},": ",[210,418,419],{"class":299},"False",[210,421,422],{"class":219},",\n",[210,424,426,429,431,433,435,438,440,443],{"class":106,"line":425},13,[210,427,428],{"class":253},"    \"NO_MASK\"",[210,430,416],{"class":219},[210,432,419],{"class":299},[210,434,320],{"class":219},[210,436,437],{"class":253},"\"MASK_LAYER\"",[210,439,416],{"class":219},[210,441,442],{"class":299},"None",[210,444,422],{"class":219},[210,446,448,451,453,456,459,462],{"class":106,"line":447},14,[210,449,450],{"class":253},"    \"OUTPUT\"",[210,452,416],{"class":219},[210,454,455],{"class":253},"\"\u002Fdata\u002Flandcover\u002Fclassified_2026_sieved.tif\"",[210,457,458],{"class":219},"})[",[210,460,461],{"class":253},"\"OUTPUT\"",[210,463,464],{"class":219},"]\n",[14,466,467,471],{},[468,469,470],"strong",{},"Breakdown:"," Expressing the threshold as a minimum area in square metres and converting it to pixels makes the setting meaningful and independent of resolution: 500 m² is five pixels at 10 m resolution and 125 at 2 m. The sieve replaces small regions with the value of their largest neighbour, so it changes the raster — keep the original. Without a sieve, a 10,000 × 10,000 classified image can produce millions of polygons and take hours to polygonize; with one, often a few tens of thousands.",[174,473,475],{"id":474},"polygonize","Polygonize",[14,477,478,480],{},[27,479,29],{}," walks the raster and builds a polygon for each connected region of equal value, storing the value in a field.",[201,482,484],{"className":203,"code":483,"language":205,"meta":206,"style":206},"polys = processing.run(\"gdal:polygonize\", {\n    \"INPUT\": sieved, \"BAND\": 1, \"FIELD\": \"class\",\n    \"EIGHT_CONNECTEDNESS\": False, \"EXTRA\": \"\",\n    \"OUTPUT\": \"\u002Fdata\u002Flandcover\u002Flandcover_2026.gpkg\"})[\"OUTPUT\"]\n\nfrom qgis.core import QgsVectorLayer\nlc = QgsVectorLayer(polys, \"land cover polygons\", \"ogr\")\nprint(lc.featureCount(), \"polygons;\", lc.fields().names())\n",[27,485,486,500,526,547,562,566,577,597],{"__ignoreMap":206},[210,487,488,491,493,495,498],{"class":106,"line":212},[210,489,490],{"class":219},"polys ",[210,492,250],{"class":215},[210,494,389],{"class":219},[210,496,497],{"class":253},"\"gdal:polygonize\"",[210,499,395],{"class":219},[210,501,502,504,507,510,512,514,516,519,521,524],{"class":106,"line":223},[210,503,401],{"class":253},[210,505,506],{"class":219},": sieved, ",[210,508,509],{"class":253},"\"BAND\"",[210,511,416],{"class":219},[210,513,317],{"class":299},[210,515,320],{"class":219},[210,517,518],{"class":253},"\"FIELD\"",[210,520,416],{"class":219},[210,522,523],{"class":253},"\"class\"",[210,525,422],{"class":219},[210,527,528,531,533,535,537,540,542,545],{"class":106,"line":237},[210,529,530],{"class":253},"    \"EIGHT_CONNECTEDNESS\"",[210,532,416],{"class":219},[210,534,419],{"class":299},[210,536,320],{"class":219},[210,538,539],{"class":253},"\"EXTRA\"",[210,541,416],{"class":219},[210,543,544],{"class":253},"\"\"",[210,546,422],{"class":219},[210,548,549,551,553,556,558,560],{"class":106,"line":244},[210,550,450],{"class":253},[210,552,416],{"class":219},[210,554,555],{"class":253},"\"\u002Fdata\u002Flandcover\u002Flandcover_2026.gpkg\"",[210,557,458],{"class":219},[210,559,461],{"class":253},[210,561,464],{"class":219},[210,563,564],{"class":106,"line":257},[210,565,241],{"emptyLinePlaceholder":240},[210,567,568,570,572,574],{"class":106,"line":274},[210,569,226],{"class":215},[210,571,229],{"class":219},[210,573,216],{"class":215},[210,575,576],{"class":219}," QgsVectorLayer\n",[210,578,579,582,584,587,590,592,595],{"class":106,"line":291},[210,580,581],{"class":219},"lc ",[210,583,250],{"class":215},[210,585,586],{"class":219}," QgsVectorLayer(polys, ",[210,588,589],{"class":253},"\"land cover polygons\"",[210,591,320],{"class":219},[210,593,594],{"class":253},"\"ogr\"",[210,596,271],{"class":219},[210,598,599,601,604,607],{"class":106,"line":303},[210,600,338],{"class":299},[210,602,603],{"class":219},"(lc.featureCount(), ",[210,605,606],{"class":253},"\"polygons;\"",[210,608,609],{"class":219},", lc.fields().names())\n",[14,611,612,614,615,618],{},[468,613,470],{}," The ",[27,616,617],{},"FIELD"," name holds the pixel value of each polygon. Writing to GeoPackage rather than shapefile avoids field-name limits and gives a spatial index. Polygon edges follow pixel boundaries exactly, so the output has right-angled \"staircase\" edges at the raster's resolution — faithful to the data and often ugly; the smoothing section below addresses it. The output CRS is the raster's CRS.",[174,620,622],{"id":621},"choose-4-or-8-connectedness","Choose 4- or 8-connectedness",[14,624,625],{},"Connectedness decides whether pixels that touch only at a corner belong to the same region. The choice changes both polygon count and shape.",[14,627,628],{},[34,629,632,635,638,641,644,649,652,655,657,662,666,669,671,673,676,681,686,690],{"viewBox":630,"role":37,"ariaLabel":631,"xmlns":39},"0 0 760 210","Two diagonally touching pixels forming two polygons with 4-connectedness and one self-touching polygon with 8-connectedness",[41,633,634],{},"Four versus eight neighbours",[45,636,637],{},"Two diagonal pixels of the same class touching only at a corner. With 4-connectedness they are separate regions and become two polygons. With 8-connectedness they are one region, and the resulting polygon touches itself at the shared corner, which some tools treat as invalid. Four-connectedness is the safer default for clean geometry.",[49,639],{"x":51,"y":51,"width":52,"height":640,"fill":54},"210",[73,642,643],{"x":75,"y":76,"style":77,"fill":78,"textAnchor":79},"Do corner-touching pixels connect?",[49,645],{"x":646,"y":646,"width":647,"height":647,"rx":51,"fill":135,"stroke":78,"style":648},"80","40","stroke-width:1",[49,650],{"x":651,"y":651,"width":647,"height":647,"rx":51,"fill":135,"stroke":78,"style":648},"120",[49,653],{"x":651,"y":646,"width":647,"height":647,"rx":51,"fill":654,"stroke":78,"style":648},"#f0ebdd",[49,656],{"x":646,"y":651,"width":647,"height":647,"rx":51,"fill":654,"stroke":78,"style":648},[73,658,661],{"x":651,"y":659,"style":660,"fill":135,"textAnchor":79},"190","text-anchor:middle;font-size:11.0px;font-family:sans-serif","4: two polygons",[49,663],{"x":664,"y":646,"width":647,"height":647,"rx":51,"fill":665,"stroke":78,"style":648},"330","#2563eb",[49,667],{"x":668,"y":651,"width":647,"height":647,"rx":51,"fill":665,"stroke":78,"style":648},"370",[49,670],{"x":668,"y":646,"width":647,"height":647,"rx":51,"fill":654,"stroke":78,"style":648},[49,672],{"x":664,"y":651,"width":647,"height":647,"rx":51,"fill":654,"stroke":78,"style":648},[73,674,675],{"x":668,"y":659,"style":660,"fill":665,"textAnchor":79},"8: one, self-touching",[49,677],{"x":678,"y":679,"width":680,"height":651,"rx":63,"fill":87,"stroke":88,"style":89},"500","70","236",[73,682,685],{"x":683,"y":684,"style":94,"fill":78,"textAnchor":79},"618","107.78","default: 4",[73,687,689],{"x":683,"y":688,"style":99,"fill":88,"textAnchor":79},"133.78","valid geometry",[73,691,693],{"x":683,"y":692,"style":99,"fill":88,"textAnchor":79},"159.78","more polygons",[14,695,696],{},"Four-connectedness (the default) joins pixels only through shared edges; diagonal neighbours stay separate. That produces a few more polygons but always valid geometry. Eight-connectedness joins diagonal neighbours too, which suits thin diagonal features such as streams classified at coarse resolution — but the resulting polygons can touch themselves at a single corner, which strict validators flag as invalid. Use the same setting for the sieve and the polygonize steps so they agree on what a region is.",[174,698,700],{"id":699},"drop-nodata-and-unwanted-classes","Drop NoData and unwanted classes",[14,702,703],{},"NoData areas become polygons too, unless the raster's NoData value is set — and some classes, such as \"unclassified\" or \"water\" in a land analysis, may not be wanted.",[201,705,707],{"className":203,"code":706,"language":205,"meta":206,"style":206},"from qgis.core import QgsFeatureRequest, edit\n\ndrop = lc.getFeatures(QgsFeatureRequest().setFilterExpression('\"class\" IN (0, 255)'))\nids = [f.id() for f in drop]\nwith edit(lc):\n    lc.deleteFeatures(ids)\nprint(len(ids), \"NoData\u002Funclassified polygons removed;\", lc.featureCount(), \"remain\")\n",[27,708,709,720,724,740,762,770,775],{"__ignoreMap":206},[210,710,711,713,715,717],{"class":106,"line":212},[210,712,226],{"class":215},[210,714,229],{"class":219},[210,716,216],{"class":215},[210,718,719],{"class":219}," QgsFeatureRequest, edit\n",[210,721,722],{"class":106,"line":223},[210,723,241],{"emptyLinePlaceholder":240},[210,725,726,729,731,734,737],{"class":106,"line":237},[210,727,728],{"class":219},"drop ",[210,730,250],{"class":215},[210,732,733],{"class":219}," lc.getFeatures(QgsFeatureRequest().setFilterExpression(",[210,735,736],{"class":253},"'\"class\" IN (0, 255)'",[210,738,739],{"class":219},"))\n",[210,741,742,745,747,750,753,756,759],{"class":106,"line":244},[210,743,744],{"class":219},"ids ",[210,746,250],{"class":215},[210,748,749],{"class":219}," [f.id() ",[210,751,752],{"class":215},"for",[210,754,755],{"class":219}," f ",[210,757,758],{"class":215},"in",[210,760,761],{"class":219}," drop]\n",[210,763,764,767],{"class":106,"line":257},[210,765,766],{"class":215},"with",[210,768,769],{"class":219}," edit(lc):\n",[210,771,772],{"class":106,"line":274},[210,773,774],{"class":219},"    lc.deleteFeatures(ids)\n",[210,776,777,779,781,784,787,790,793,796],{"class":106,"line":291},[210,778,338],{"class":299},[210,780,314],{"class":219},[210,782,783],{"class":299},"len",[210,785,786],{"class":219},"(ids), ",[210,788,789],{"class":253},"\"NoData\u002Funclassified polygons removed;\"",[210,791,792],{"class":219},", lc.featureCount(), ",[210,794,795],{"class":253},"\"remain\"",[210,797,271],{"class":219},[14,799,800,802,803,805],{},[468,801,470],{}," When the raster declares a NoData value, ",[27,804,29],{}," skips those pixels automatically; when it does not — common with classification outputs that use 0 or 255 for \"nothing\" — they become polygons and must be removed. Deleting by class in one call is fast. Doing it before dissolving and simplifying saves work on polygons that would be discarded anyway.",[174,807,809],{"id":808},"dissolve-and-simplify","Dissolve and simplify",[14,811,812],{},"Polygonize produces one polygon per connected region, so a class appears as many separate polygons. For area statistics per class, dissolving merges them; for display and further vector work, simplifying removes the staircase.",[14,814,815],{},[34,816,819,822,825,828,831,837,842,845,848,851],{"viewBox":817,"role":37,"ariaLabel":818,"xmlns":39},"0 0 760 230","A staircase pixel edge simplified with a half-pixel tolerance into a cleaner line, with smoothing as a further optional step",[41,820,821],{},"Smoothing staircase edges",[45,823,824],{},"A polygon edge following pixel boundaries forms a staircase. Simplification with a tolerance of about half a pixel removes most steps while keeping the shape; a larger tolerance distorts it. Smoothing adds curvature for a natural look but moves edges slightly. Areas should be computed before smoothing if they must match pixel counts.",[49,826],{"x":51,"y":51,"width":52,"height":827,"fill":54},"230",[73,829,830],{"x":75,"y":76,"style":77,"fill":78,"textAnchor":79},"Remove the steps, keep the shape",[832,833],"polyline",{"points":834,"fill":835,"stroke":116,"style":836},"60,190 60,160 100,160 100,130 140,130 140,100 180,100 180,70 220,70","none","stroke-width:3",[73,838,841],{"x":839,"y":840,"style":99,"fill":116,"textAnchor":79},"140","214","staircase (pixel edges)",[832,843],{"points":844,"fill":835,"stroke":665,"style":836},"300,190 340,160 380,130 420,100 460,70",[73,846,847],{"x":75,"y":840,"style":99,"fill":665,"textAnchor":79},"simplified (½ pixel)",[68,849],{"d":850,"fill":835,"stroke":154,"style":836},"M 540 190 C 570 170 600 140 630 115 C 660 90 680 75 700 70",[73,852,853],{"x":148,"y":840,"style":99,"fill":159,"textAnchor":79},"smoothed",[201,855,857],{"className":203,"code":856,"language":205,"meta":206,"style":206},"dissolved = processing.run(\"native:dissolve\", {\n    \"INPUT\": lc, \"FIELD\": [\"class\"], \"SEPARATE_DISJOINT\": False,\n    \"OUTPUT\": \"memory:by_class\"})[\"OUTPUT\"]\n\npixel = layer.rasterUnitsPerPixelX()\nsimplified = processing.run(\"native:simplifygeometries\", {\n    \"INPUT\": lc, \"METHOD\": 0, \"TOLERANCE\": pixel * 0.5,\n    \"OUTPUT\": \"memory:landcover_simplified\"})[\"OUTPUT\"]\n\nwith_area = processing.run(\"native:fieldcalculator\", {\n    \"INPUT\": simplified, \"FIELD_NAME\": \"area_ha\", \"FIELD_TYPE\": 0,\n    \"FIELD_LENGTH\": 12, \"FIELD_PRECISION\": 3, \"FORMULA\": \"$area \u002F 10000\",\n    \"OUTPUT\": \"memory:landcover_final\"})[\"OUTPUT\"]\n",[27,858,859,873,899,914,918,928,942,970,985,989,1003,1029,1061],{"__ignoreMap":206},[210,860,861,864,866,868,871],{"class":106,"line":212},[210,862,863],{"class":219},"dissolved ",[210,865,250],{"class":215},[210,867,389],{"class":219},[210,869,870],{"class":253},"\"native:dissolve\"",[210,872,395],{"class":219},[210,874,875,877,880,882,885,887,890,893,895,897],{"class":106,"line":223},[210,876,401],{"class":253},[210,878,879],{"class":219},": lc, ",[210,881,518],{"class":253},[210,883,884],{"class":219},": [",[210,886,523],{"class":253},[210,888,889],{"class":219},"], ",[210,891,892],{"class":253},"\"SEPARATE_DISJOINT\"",[210,894,416],{"class":219},[210,896,419],{"class":299},[210,898,422],{"class":219},[210,900,901,903,905,908,910,912],{"class":106,"line":237},[210,902,450],{"class":253},[210,904,416],{"class":219},[210,906,907],{"class":253},"\"memory:by_class\"",[210,909,458],{"class":219},[210,911,461],{"class":253},[210,913,464],{"class":219},[210,915,916],{"class":106,"line":244},[210,917,241],{"emptyLinePlaceholder":240},[210,919,920,923,925],{"class":106,"line":257},[210,921,922],{"class":219},"pixel ",[210,924,250],{"class":215},[210,926,927],{"class":219}," layer.rasterUnitsPerPixelX()\n",[210,929,930,933,935,937,940],{"class":106,"line":274},[210,931,932],{"class":219},"simplified ",[210,934,250],{"class":215},[210,936,389],{"class":219},[210,938,939],{"class":253},"\"native:simplifygeometries\"",[210,941,395],{"class":219},[210,943,944,946,948,951,953,955,957,960,963,965,968],{"class":106,"line":291},[210,945,401],{"class":253},[210,947,879],{"class":219},[210,949,950],{"class":253},"\"METHOD\"",[210,952,416],{"class":219},[210,954,51],{"class":299},[210,956,320],{"class":219},[210,958,959],{"class":253},"\"TOLERANCE\"",[210,961,962],{"class":219},": pixel ",[210,964,285],{"class":215},[210,966,967],{"class":299}," 0.5",[210,969,422],{"class":219},[210,971,972,974,976,979,981,983],{"class":106,"line":303},[210,973,450],{"class":253},[210,975,416],{"class":219},[210,977,978],{"class":253},"\"memory:landcover_simplified\"",[210,980,458],{"class":219},[210,982,461],{"class":253},[210,984,464],{"class":219},[210,986,987],{"class":106,"line":335},[210,988,241],{"emptyLinePlaceholder":240},[210,990,991,994,996,998,1001],{"class":106,"line":376},[210,992,993],{"class":219},"with_area ",[210,995,250],{"class":215},[210,997,389],{"class":219},[210,999,1000],{"class":253},"\"native:fieldcalculator\"",[210,1002,395],{"class":219},[210,1004,1005,1007,1010,1013,1015,1018,1020,1023,1025,1027],{"class":106,"line":381},[210,1006,401],{"class":253},[210,1008,1009],{"class":219},": simplified, ",[210,1011,1012],{"class":253},"\"FIELD_NAME\"",[210,1014,416],{"class":219},[210,1016,1017],{"class":253},"\"area_ha\"",[210,1019,320],{"class":219},[210,1021,1022],{"class":253},"\"FIELD_TYPE\"",[210,1024,416],{"class":219},[210,1026,51],{"class":299},[210,1028,422],{"class":219},[210,1030,1031,1034,1036,1039,1041,1044,1046,1049,1051,1054,1056,1059],{"class":106,"line":398},[210,1032,1033],{"class":253},"    \"FIELD_LENGTH\"",[210,1035,416],{"class":219},[210,1037,1038],{"class":299},"12",[210,1040,320],{"class":219},[210,1042,1043],{"class":253},"\"FIELD_PRECISION\"",[210,1045,416],{"class":219},[210,1047,1048],{"class":299},"3",[210,1050,320],{"class":219},[210,1052,1053],{"class":253},"\"FORMULA\"",[210,1055,416],{"class":219},[210,1057,1058],{"class":253},"\"$area \u002F 10000\"",[210,1060,422],{"class":219},[210,1062,1063,1065,1067,1070,1072,1074],{"class":106,"line":425},[210,1064,450],{"class":253},[210,1066,416],{"class":219},[210,1068,1069],{"class":253},"\"memory:landcover_final\"",[210,1071,458],{"class":219},[210,1073,461],{"class":253},[210,1075,464],{"class":219},[14,1077,1078,1080,1081,1084,1085,1089],{},[468,1079,470],{}," Dissolving by class gives one (multi)polygon per class — the right input for \"how many hectares of forest\", but too coarse for most mapping. Simplifying with a tolerance of half a pixel removes the steps without moving edges by more than the data's own resolution; much larger tolerances visibly distort shapes. ",[27,1082,1083],{},"native:smoothgeometry"," gives a softer look for display but moves edges further. Simplifying polygons independently can open small gaps between neighbours; for a strict coverage, simplify with topology-aware tools or accept the staircase. ",[21,1086,1088],{"href":1087},"\u002Fspatial-data-processing-automation\u002Fgeometry-operations-and-predicates\u002Fsimplify-geometry-pyqgis\u002F","Simplifying geometry"," compares the methods.",[174,1091,1093],{"id":1092},"summarise-classes-within-districts","Summarise classes within districts",[14,1095,1096],{},"The usual reason to polygonize is to combine the classes with other vector data: hectares of each land-cover class per municipality, flooded area per parcel. Once the classes are polygons, an overlay and a group-by answer it.",[201,1098,1100],{"className":203,"code":1099,"language":205,"meta":206,"style":206},"districts = QgsVectorLayer(\"\u002Fdata\u002Fadmin\u002Fdistricts.gpkg|layername=districts\", \"districts\", \"ogr\")\npieces = processing.run(\"native:intersection\", {\n    \"INPUT\": with_area, \"OVERLAY\": districts,\n    \"INPUT_FIELDS\": [\"class\"], \"OVERLAY_FIELDS\": [\"district\"],\n    \"OUTPUT\": \"memory:\"})[\"OUTPUT\"]\n\ntable = defaultdict(float)\nfor f in pieces.getFeatures():\n    table[(f[\"district\"], f[\"class\"])] += f.geometry().area() \u002F 1e4\nfor (district, cls), ha in sorted(table.items())[:12]:\n    print(f\"{district:\u003C20} class {cls:>3}  {ha:8.1f} ha\")\n",[27,1101,1102,1126,1140,1153,1175,1190,1194,1209,1220,1246,1272],{"__ignoreMap":206},[210,1103,1104,1107,1109,1112,1115,1117,1120,1122,1124],{"class":106,"line":212},[210,1105,1106],{"class":219},"districts ",[210,1108,250],{"class":215},[210,1110,1111],{"class":219}," QgsVectorLayer(",[210,1113,1114],{"class":253},"\"\u002Fdata\u002Fadmin\u002Fdistricts.gpkg|layername=districts\"",[210,1116,320],{"class":219},[210,1118,1119],{"class":253},"\"districts\"",[210,1121,320],{"class":219},[210,1123,594],{"class":253},[210,1125,271],{"class":219},[210,1127,1128,1131,1133,1135,1138],{"class":106,"line":223},[210,1129,1130],{"class":219},"pieces ",[210,1132,250],{"class":215},[210,1134,389],{"class":219},[210,1136,1137],{"class":253},"\"native:intersection\"",[210,1139,395],{"class":219},[210,1141,1142,1144,1147,1150],{"class":106,"line":237},[210,1143,401],{"class":253},[210,1145,1146],{"class":219},": with_area, ",[210,1148,1149],{"class":253},"\"OVERLAY\"",[210,1151,1152],{"class":219},": districts,\n",[210,1154,1155,1158,1160,1162,1164,1167,1169,1172],{"class":106,"line":244},[210,1156,1157],{"class":253},"    \"INPUT_FIELDS\"",[210,1159,884],{"class":219},[210,1161,523],{"class":253},[210,1163,889],{"class":219},[210,1165,1166],{"class":253},"\"OVERLAY_FIELDS\"",[210,1168,884],{"class":219},[210,1170,1171],{"class":253},"\"district\"",[210,1173,1174],{"class":219},"],\n",[210,1176,1177,1179,1181,1184,1186,1188],{"class":106,"line":257},[210,1178,450],{"class":253},[210,1180,416],{"class":219},[210,1182,1183],{"class":253},"\"memory:\"",[210,1185,458],{"class":219},[210,1187,461],{"class":253},[210,1189,464],{"class":219},[210,1191,1192],{"class":106,"line":274},[210,1193,241],{"emptyLinePlaceholder":240},[210,1195,1196,1199,1201,1204,1207],{"class":106,"line":291},[210,1197,1198],{"class":219},"table ",[210,1200,250],{"class":215},[210,1202,1203],{"class":219}," defaultdict(",[210,1205,1206],{"class":299},"float",[210,1208,271],{"class":219},[210,1210,1211,1213,1215,1217],{"class":106,"line":303},[210,1212,752],{"class":215},[210,1214,755],{"class":219},[210,1216,758],{"class":215},[210,1218,1219],{"class":219}," pieces.getFeatures():\n",[210,1221,1222,1225,1227,1230,1232,1235,1238,1241,1243],{"class":106,"line":335},[210,1223,1224],{"class":219},"    table[(f[",[210,1226,1171],{"class":253},[210,1228,1229],{"class":219},"], f[",[210,1231,523],{"class":253},[210,1233,1234],{"class":219},"])] ",[210,1236,1237],{"class":215},"+=",[210,1239,1240],{"class":219}," f.geometry().area() ",[210,1242,329],{"class":215},[210,1244,1245],{"class":299}," 1e4\n",[210,1247,1248,1250,1253,1256,1259,1261,1264,1267,1269],{"class":106,"line":376},[210,1249,752],{"class":215},[210,1251,1252],{"class":219}," (district, ",[210,1254,1255],{"class":299},"cls",[210,1257,1258],{"class":219},"), ha ",[210,1260,758],{"class":215},[210,1262,1263],{"class":299}," sorted",[210,1265,1266],{"class":219},"(table.items())[:",[210,1268,1038],{"class":299},[210,1270,1271],{"class":219},"]:\n",[210,1273,1274,1277,1279,1281,1284,1286,1289,1292,1294,1297,1300,1303,1305,1308,1311,1314,1316,1319],{"class":106,"line":381},[210,1275,1276],{"class":299},"    print",[210,1278,314],{"class":219},[210,1280,343],{"class":215},[210,1282,1283],{"class":253},"\"",[210,1285,349],{"class":299},[210,1287,1288],{"class":219},"district",[210,1290,1291],{"class":215},":\u003C20",[210,1293,358],{"class":299},[210,1295,1296],{"class":253}," class ",[210,1298,1299],{"class":299},"{cls",[210,1301,1302],{"class":215},":>3",[210,1304,358],{"class":299},[210,1306,1307],{"class":299},"  {",[210,1309,1310],{"class":219},"ha",[210,1312,1313],{"class":215},":8.1f",[210,1315,358],{"class":299},[210,1317,1318],{"class":253}," ha\"",[210,1320,271],{"class":219},[14,1322,1323,1325,1326,1329,1330,1334],{},[468,1324,470],{}," Intersecting the class polygons with district boundaries splits each polygon where it crosses a boundary and keeps one attribute from each side. Recomputing area on the pieces, rather than reusing the ",[27,1327,1328],{},"area_ha"," field from before the overlay, gives the area inside each district. For this particular question there is also a raster-only route — ",[21,1331,1333],{"href":1332},"\u002Fspatial-data-processing-automation\u002Fraster-analysis-workflows\u002Fzonal-statistics-pyqgis\u002F","zonal statistics"," with a categorical histogram counts pixels per class per district without polygonizing at all, and is faster on large rasters. Polygonizing pays off when the polygons themselves are needed afterwards: for overlay with parcels, for editing, or for publication.",[174,1336,1338],{"id":1337},"check-areas-against-pixel-counts","Check areas against pixel counts",[14,1340,1341],{},"Polygon areas should agree with pixel counts per class. Comparing them catches lost polygons, unexpected NoData and distortion from simplification.",[201,1343,1345],{"className":203,"code":1344,"language":205,"meta":206,"style":206},"from collections import defaultdict\n\narea_by_class = defaultdict(float)\nfor f in lc.getFeatures():\n    area_by_class[f[\"class\"]] += f.geometry().area()\n\nstats = processing.run(\"native:rasterlayeruniquevaluesreport\", {\n    \"INPUT\": sieved, \"BAND\": 1, \"OUTPUT_TABLE\": \"memory:\"})[\"OUTPUT_TABLE\"]\nfor row in stats.getFeatures():\n    cls, m2 = row[\"value\"], row[\"count\"] * px_area\n    poly = area_by_class.get(cls, 0)\n    print(f\"class {cls:>3}: raster {m2 \u002F 1e4:10.1f} ha  polygons {poly \u002F 1e4:10.1f} ha\")\n",[27,1346,1347,1359,1363,1376,1387,1402,1406,1420,1447,1459,1489,1507],{"__ignoreMap":206},[210,1348,1349,1351,1354,1356],{"class":106,"line":212},[210,1350,226],{"class":215},[210,1352,1353],{"class":219}," collections ",[210,1355,216],{"class":215},[210,1357,1358],{"class":219}," defaultdict\n",[210,1360,1361],{"class":106,"line":223},[210,1362,241],{"emptyLinePlaceholder":240},[210,1364,1365,1368,1370,1372,1374],{"class":106,"line":237},[210,1366,1367],{"class":219},"area_by_class ",[210,1369,250],{"class":215},[210,1371,1203],{"class":219},[210,1373,1206],{"class":299},[210,1375,271],{"class":219},[210,1377,1378,1380,1382,1384],{"class":106,"line":244},[210,1379,752],{"class":215},[210,1381,755],{"class":219},[210,1383,758],{"class":215},[210,1385,1386],{"class":219}," lc.getFeatures():\n",[210,1388,1389,1392,1394,1397,1399],{"class":106,"line":257},[210,1390,1391],{"class":219},"    area_by_class[f[",[210,1393,523],{"class":253},[210,1395,1396],{"class":219},"]] ",[210,1398,1237],{"class":215},[210,1400,1401],{"class":219}," f.geometry().area()\n",[210,1403,1404],{"class":106,"line":274},[210,1405,241],{"emptyLinePlaceholder":240},[210,1407,1408,1411,1413,1415,1418],{"class":106,"line":291},[210,1409,1410],{"class":219},"stats ",[210,1412,250],{"class":215},[210,1414,389],{"class":219},[210,1416,1417],{"class":253},"\"native:rasterlayeruniquevaluesreport\"",[210,1419,395],{"class":219},[210,1421,1422,1424,1426,1428,1430,1432,1434,1437,1439,1441,1443,1445],{"class":106,"line":303},[210,1423,401],{"class":253},[210,1425,506],{"class":219},[210,1427,509],{"class":253},[210,1429,416],{"class":219},[210,1431,317],{"class":299},[210,1433,320],{"class":219},[210,1435,1436],{"class":253},"\"OUTPUT_TABLE\"",[210,1438,416],{"class":219},[210,1440,1183],{"class":253},[210,1442,458],{"class":219},[210,1444,1436],{"class":253},[210,1446,464],{"class":219},[210,1448,1449,1451,1454,1456],{"class":106,"line":335},[210,1450,752],{"class":215},[210,1452,1453],{"class":219}," row ",[210,1455,758],{"class":215},[210,1457,1458],{"class":219}," stats.getFeatures():\n",[210,1460,1461,1464,1467,1469,1472,1475,1478,1481,1484,1486],{"class":106,"line":376},[210,1462,1463],{"class":299},"    cls",[210,1465,1466],{"class":219},", m2 ",[210,1468,250],{"class":215},[210,1470,1471],{"class":219}," row[",[210,1473,1474],{"class":253},"\"value\"",[210,1476,1477],{"class":219},"], row[",[210,1479,1480],{"class":253},"\"count\"",[210,1482,1483],{"class":219},"] ",[210,1485,285],{"class":215},[210,1487,1488],{"class":219}," px_area\n",[210,1490,1491,1494,1496,1499,1501,1503,1505],{"class":106,"line":381},[210,1492,1493],{"class":219},"    poly ",[210,1495,250],{"class":215},[210,1497,1498],{"class":219}," area_by_class.get(",[210,1500,1255],{"class":299},[210,1502,320],{"class":219},[210,1504,51],{"class":299},[210,1506,271],{"class":219},[210,1508,1509,1511,1513,1515,1518,1520,1522,1524,1527,1529,1532,1534,1537,1540,1542,1545,1547,1550,1552,1554,1556,1558,1560],{"class":106,"line":398},[210,1510,1276],{"class":299},[210,1512,314],{"class":219},[210,1514,343],{"class":215},[210,1516,1517],{"class":253},"\"class ",[210,1519,1299],{"class":299},[210,1521,1302],{"class":215},[210,1523,358],{"class":299},[210,1525,1526],{"class":253},": raster ",[210,1528,349],{"class":299},[210,1530,1531],{"class":219},"m2 ",[210,1533,329],{"class":215},[210,1535,1536],{"class":299}," 1e4",[210,1538,1539],{"class":215},":10.1f",[210,1541,358],{"class":299},[210,1543,1544],{"class":253}," ha  polygons ",[210,1546,349],{"class":299},[210,1548,1549],{"class":219},"poly ",[210,1551,329],{"class":215},[210,1553,1536],{"class":299},[210,1555,1539],{"class":215},[210,1557,358],{"class":299},[210,1559,1318],{"class":253},[210,1561,271],{"class":219},[14,1563,1564,1566,1567,1570],{},[468,1565,470],{}," ",[27,1568,1569],{},"native:rasterlayeruniquevaluesreport"," counts pixels per value; multiplying by the pixel area computed earlier converts counts to square metres. Before simplification, polygon areas must match exactly; after simplification they differ slightly, and the comparison shows by how much. A class missing from the polygons usually means it was deleted as NoData by mistake.",[174,1572,1574],{"id":1573},"qgis-version-compatibility","QGIS version compatibility",[14,1576,1577,320,1579,1581,1582,1585,1586,1589,1590,1592],{},[27,1578,120],{},[27,1580,29],{}," and the native vector algorithms work on QGIS 3.34 LTR, 3.40 LTR and QGIS 4. ",[27,1583,1584],{},"SEPARATE_DISJOINT"," on ",[27,1587,1588],{},"native:dissolve"," was added in 3.32; omit it on older releases. ",[27,1591,1569],{}," has existed since 3.4.",[174,1594,1596],{"id":1595},"troubleshooting","Troubleshooting",[179,1598,1599,1605,1611,1617],{},[182,1600,1601,1604],{},[468,1602,1603],{},"Millions of polygons."," Sieve first, with a threshold tied to a minimum mapping area.",[182,1606,1607,1610],{},[468,1608,1609],{},"A huge polygon covers the whole extent."," NoData was not declared; delete the NoData-class polygon or set NoData on the raster.",[182,1612,1613,1616],{},[468,1614,1615],{},"Invalid geometries after polygonizing."," 8-connectedness created self-touching rings; use 4-connectedness or fix geometries.",[182,1618,1619,1622],{},[468,1620,1621],{},"Gaps between polygons after simplifying."," Polygons were simplified independently; use a smaller tolerance.",[174,1624,1626],{"id":1625},"conclusion","Conclusion",[14,1628,1629],{},"Sieve speckle away in the raster with a threshold from a minimum area, polygonize with 4-connectedness into GeoPackage, drop NoData and unwanted classes, dissolve for per-class statistics, simplify by about half a pixel for clean edges, and check areas against pixel counts.",[174,1631,1633],{"id":1632},"frequently-asked-questions","Frequently Asked Questions",[14,1635,1636,1639],{},[468,1637,1638],{},"Can I polygonize a continuous raster?","\nNot usefully — every distinct value becomes a polygon. Reclassify into bands first.",[14,1641,1642,1645],{},[468,1643,1644],{},"How do I polygonize only one class?","\nReclassify everything else to NoData, then polygonize; or polygonize all and filter.",[14,1647,1648,1651,1652,1655],{},[468,1649,1650],{},"Is there a faster way for huge rasters?","\nProcess in tiles with a small overlap and merge results, or use ",[27,1653,1654],{},"gdal_polygonize.py"," directly with a large cache.",[14,1657,1658,1661],{},[468,1659,1660],{},"Should I keep the raster after polygonizing?","\nYes. The raster is the source of truth for the classification; polygons are a derived, simplified view. Keep both, and record the sieve threshold and simplification tolerance with the polygons so the derivation can be repeated.",[14,1663,1664,1667,1668,1671],{},[468,1665,1666],{},"Can I attach the class names to the polygons?","\nJoin a lookup table of class codes and names on the ",[27,1669,1670],{},"class"," field, so the layer is readable without the classification's documentation.",[14,1673,1674,1677],{},[468,1675,1676],{},"Why do polygons look blocky at high zoom?","\nThey follow pixel edges. Simplify or smooth for display; keep the originals for analysis.",[174,1679,1681],{"id":1680},"related","Related",[179,1683,1684,1689,1695,1700,1706],{},[182,1685,1686,1688],{},[21,1687,24],{"href":23}," — the guide this recipe belongs to",[182,1690,1691],{},[21,1692,1694],{"href":1693},"\u002Fspatial-data-processing-automation\u002Fraster-analysis-workflows\u002Frasterize-vector-layer-pyqgis\u002F","Rasterize a Vector Layer in PyQGIS",[182,1696,1697],{},[21,1698,1699],{"href":190},"Reclassify Raster Values in PyQGIS",[182,1701,1702],{},[21,1703,1705],{"href":1704},"\u002Fspatial-data-processing-automation\u002Fvector-data-manipulation\u002Fdissolve-features-by-attribute-pyqgis\u002F","Dissolve Features by Attribute in PyQGIS",[182,1707,1708],{},[21,1709,1710],{"href":1087},"Simplify Geometry in PyQGIS",[1712,1713,1714],"style",{},"html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":206,"searchDepth":223,"depth":223,"links":1716},[1717,1718,1719,1720,1721,1722,1723,1724,1725,1726,1727,1728,1729],{"id":176,"depth":223,"text":177},{"id":195,"depth":223,"text":196},{"id":474,"depth":223,"text":475},{"id":621,"depth":223,"text":622},{"id":699,"depth":223,"text":700},{"id":808,"depth":223,"text":809},{"id":1092,"depth":223,"text":1093},{"id":1337,"depth":223,"text":1338},{"id":1573,"depth":223,"text":1574},{"id":1595,"depth":223,"text":1596},{"id":1625,"depth":223,"text":1626},{"id":1632,"depth":223,"text":1633},{"id":1680,"depth":223,"text":1681},"Convert classified rasters into polygons with gdal:polygonize — preparing the raster so the output is usable, choosing 4- or 8-connectedness, removing NoData and tiny speckle polygons, dissolving by class, simplifying staircase edges and computing areas.","md",{"slug":1733,"type":1734,"breadcrumb":1735,"datePublished":1736,"dateModified":1736},"polygonize-raster-to-vector-pyqgis","article","Polygonize a Raster to Vector","2026-10-02","\u002Fspatial-data-processing-automation\u002Fraster-analysis-workflows\u002Fpolygonize-raster-to-vector-pyqgis",{"title":5,"description":1730},"spatial-data-processing-automation\u002Fraster-analysis-workflows\u002Fpolygonize-raster-to-vector-pyqgis\u002Findex","RmkoHlsIjJLocFvFKZUTOgr8u8yx0Mg06pBxkc1MZ_o",1790966264629]