[{"data":1,"prerenderedAt":1688},["ShallowReactive",2],{"doc:\u002Fspatial-data-processing-automation\u002Fcoordinate-reference-systems\u002Fbatch-reprojecting-raster-datasets":3},{"id":4,"title":5,"body":6,"description":1676,"extension":1677,"meta":1678,"navigation":308,"path":1684,"seo":1685,"stem":1686,"__hash__":1687},"docs\u002Fspatial-data-processing-automation\u002Fcoordinate-reference-systems\u002Fbatch-reprojecting-raster-datasets\u002Findex.md","Batch Reprojecting Raster Datasets in PyQGIS",{"type":7,"value":8,"toc":1663},"minimark",[9,13,32,35,222,227,251,259,263,266,715,747,750,932,936,939,970,973,977,985,1097,1115,1118,1207,1211,1218,1238,1261,1265,1272,1329,1339,1343,1418,1422,1433,1436,1522,1525,1529,1547,1551,1566,1583,1592,1607,1628,1632,1659],[10,11,5],"h1",{"id":12},"batch-reprojecting-raster-datasets-in-pyqgis",[14,15,16,17,22,23,27,28,31],"p",{},"Reprojecting one raster in the QGIS GUI is trivial; doing it to a hundred DEM tiles, satellite scenes, or land-cover grids by hand is not. When a whole collection has to land in the same target projection — so it aligns with your basemap, your vector data, and every other layer in the project — you want a script that scans a folder, applies one ",[18,19,21],"a",{"href":20},"\u002Fspatial-data-processing-automation\u002Fcoordinate-reference-systems\u002F","Coordinate Reference System"," to every file, and writes clean outputs without touching the interface. In PyQGIS the workhorse is ",[24,25,26],"code",{},"processing.run()"," driving the ",[24,29,30],{},"gdal:warpreproject"," algorithm inside a loop.",[14,33,34],{},"This page shows a correct batch reproject that auto-detects each source CRS, picks resampling that suits the data type, keeps memory and file sizes under control, and validates the results — plus a native GDAL fallback for when the QGIS bindings are unavailable.",[36,37,42,46,50,57,75,85,94,99,108,114,122,126,131,135,140,146,150,155,160,164,169,173,177,181,185,189,193,199,202,205,209,212,218],"svg",{"viewBox":38,"role":39,"ariaLabel":40,"xmlns":41},"0 0 820 420","img","Batch raster reprojection pipeline in PyQGIS: a source folder is scanned with glob for .tif files, each raster is looped through gdal:warpreproject with source CRS auto-detected, a single target CRS and a chosen resampling method, and a try\u002Fexcept guard sends successes to an output folder and failures to an error log","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg",[43,44,45],"title",{},"PyQGIS batch reprojection data-flow",[47,48,49],"desc",{},"A source folder of GeoTIFFs is scanned by glob into a file list. Inside a per-file loop, the parameters SOURCE_CRS=None (auto-detect), a single TARGET_CRS, and a RESAMPLING kernel feed processing.run for gdal:warpreproject. A try\u002Fexcept guard wraps each call: successful warps are written as _reproj.tif files carrying the target CRS into an output folder, while failures are printed to an error log so one bad file cannot stop the run.",[51,52],"rect",{"x":53,"y":53,"width":54,"height":55,"fill":56},"0","820","420","#f6f3ea",[58,59,60],"defs",{},[61,62,70],"marker",{"id":63,"viewBox":64,"refX":65,"refY":66,"markerWidth":67,"markerHeight":67,"orient":68,"markerUnits":69},"br-arrow","0 0 10 10","9","5","7","auto","strokeWidth",[71,72],"path",{"d":73,"fill":74},"M0,0 L10,5 L0,10 z","#2f3b35",[51,76],{"x":77,"y":78,"width":79,"height":80,"rx":81,"fill":82,"stroke":83,"style":84},"28","170","162","84","8","#fffdf7","#2563eb","stroke-width:2.5",[86,87,93],"text",{"x":88,"y":89,"style":90,"fill":91,"textAnchor":92},"109","203","text-anchor:middle;font-size:14px;font-weight:bold;font-family:sans-serif","#17211d","middle","Source folder",[86,95,98],{"x":88,"y":96,"style":97,"fill":74,"textAnchor":92},"227","text-anchor:middle;font-size:12px;font-family:monospace","glob(“*.tif”)",[51,100],{"x":101,"y":102,"width":103,"height":104,"rx":105,"fill":82,"stroke":106,"style":107},"250","70","300","282","10","#b45309","stroke-width:2.5;stroke-dasharray:7 5",[86,109,113],{"x":110,"y":111,"style":112,"fill":106,"textAnchor":92},"400","96","text-anchor:middle;font-size:13px;font-weight:bold;font-family:sans-serif","for each raster (loop)",[51,115],{"x":116,"y":117,"width":118,"height":119,"rx":81,"fill":82,"stroke":120,"style":121},"276","112","248","74","#0f766e","stroke-width:2",[86,123,125],{"x":110,"y":124,"style":97,"fill":91,"textAnchor":92},"133","SOURCE_CRS = None",[86,127,130],{"x":110,"y":128,"style":129,"fill":74,"textAnchor":92},"150","text-anchor:middle;font-size:11px;font-family:sans-serif","(auto-detect per file)",[86,132,134],{"x":110,"y":133,"style":97,"fill":91,"textAnchor":92},"169","TARGET_CRS · RESAMPLING",[51,136],{"x":116,"y":137,"width":118,"height":138,"rx":81,"fill":139,"stroke":139,"style":121},"202","56","#26322d",[86,141,145],{"x":110,"y":142,"style":143,"fill":144,"textAnchor":92},"225","text-anchor:middle;font-size:12px;font-weight:bold;font-family:monospace","#d9f99d","processing.run(",[86,147,149],{"x":110,"y":148,"style":143,"fill":144,"textAnchor":92},"243","“gdal:warpreproject”, params)",[51,151],{"x":116,"y":152,"width":118,"height":153,"rx":81,"fill":82,"stroke":154,"style":121},"278","48","#15803d",[86,156,159],{"x":110,"y":157,"style":158,"fill":91,"textAnchor":92},"299","text-anchor:middle;font-size:12px;font-weight:bold;font-family:sans-serif","try \u002F except",[86,161,163],{"x":110,"y":162,"style":129,"fill":74,"textAnchor":92},"316","one bad file never stops the run",[51,165],{"x":166,"y":167,"width":168,"height":80,"rx":81,"fill":82,"stroke":154,"style":84},"600","120","192",[86,170,172],{"x":171,"y":128,"style":90,"fill":91,"textAnchor":92},"696","Output folder",[86,174,176],{"x":171,"y":175,"style":97,"fill":74,"textAnchor":92},"172","*_reproj.tif",[86,178,180],{"x":171,"y":179,"style":129,"fill":74,"textAnchor":92},"191","carries target CRS",[51,182],{"x":166,"y":183,"width":168,"height":184,"rx":81,"fill":82,"stroke":106,"style":84},"262","80",[86,186,188],{"x":171,"y":187,"style":90,"fill":91,"textAnchor":92},"292","Error log",[86,190,192],{"x":171,"y":191,"style":97,"fill":74,"textAnchor":92},"314","print(failed path)",[194,195],"line",{"x1":196,"y1":197,"x2":101,"y2":197,"stroke":74,"style":198},"190","212","stroke-width:2.5;marker-end:url(#br-arrow)",[194,200],{"x1":110,"y1":201,"x2":110,"y2":137,"stroke":74,"style":198},"186",[194,203],{"x1":110,"y1":204,"x2":110,"y2":152,"stroke":74,"style":198},"258",[194,206],{"x1":207,"y1":187,"x2":166,"y2":208,"stroke":154,"style":198},"524","168",[194,210],{"x1":207,"y1":211,"x2":166,"y2":103,"stroke":106,"style":198},"308",[86,213,217],{"x":214,"y":215,"style":216,"fill":154,"textAnchor":92},"566","214","text-anchor:middle;font-size:11px;font-weight:bold;font-family:sans-serif","success",[86,219,221],{"x":214,"y":220,"style":216,"fill":106,"textAnchor":92},"332","on error",[223,224,226],"h2",{"id":225},"prerequisites","Prerequisites",[228,229,230,234,237,248],"ul",{},[231,232,233],"li",{},"QGIS 3.34 LTR (bundled Python 3.12) with the Processing framework available.",[231,235,236],{},"A folder of rasters to reproject (single- or multi-band GeoTIFFs work out of the box).",[231,238,239,240,243,244,247],{},"The QGIS Python Console (",[24,241,242],{},"Plugins > Python Console",", or ",[24,245,246],{},"Ctrl+Alt+P",").",[231,249,250],{},"GDAL ≥ 3.4 and PROJ ≥ 8.2 with the PROJ data grids installed, so datum shifts transform accurately rather than falling back silently.",[14,252,253,254,258],{},"Ideally every source file already declares its own projection. Files with missing or broken metadata need extra handling — see ",[18,255,257],{"href":256},"\u002Fspatial-data-processing-automation\u002Fcoordinate-reference-systems\u002Fhandling-missing-crs-in-pyqgis\u002F","Handling Missing CRS in PyQGIS"," — and the recipe below flags those cases explicitly instead of guessing.",[223,260,262],{"id":261},"run-a-batch-reproject","Run a Batch Reproject",[14,264,265],{},"Point the script at a source directory and a target EPSG code. It scans for GeoTIFFs, reprojects each one, and logs successes and failures so a single bad file cannot stop the run.",[267,268,273],"pre",{"className":269,"code":270,"language":271,"meta":272,"style":272},"language-python shiki shiki-themes github-dark","import os\nimport glob\nimport processing\n\n# Configuration\nINPUT_DIR = \"\u002Fdata\u002Fsource\u002Frasters\"\nOUTPUT_DIR = \"\u002Fdata\u002Freprojected\u002Frasters\"\nTARGET_CRS = \"EPSG:3857\"   # your target projection\nRESAMPLING = 1             # 0=Nearest, 1=Bilinear, 2=Cubic, 3=CubicSpline\n\nos.makedirs(OUTPUT_DIR, exist_ok=True)\nraster_files = glob.glob(os.path.join(INPUT_DIR, \"*.tif\"))\n\nfor raster_path in raster_files:\n    out_name = os.path.basename(raster_path).replace(\".tif\", \"_reproj.tif\")\n    out_path = os.path.join(OUTPUT_DIR, out_name)\n\n    params = {\n        \"INPUT\": raster_path,\n        \"SOURCE_CRS\": None,          # auto-detect from file metadata\n        \"TARGET_CRS\": TARGET_CRS,\n        \"RESAMPLING\": RESAMPLING,\n        \"NODATA\": None,\n        \"TARGET_RESOLUTION\": None,\n        \"OPTIONS\": \"\",\n        \"DATA_TYPE\": 0,              # 0=Auto (keep source data type)\n        \"OUTPUT\": out_path,\n    }\n\n    try:\n        processing.run(\"gdal:warpreproject\", params)\n        print(f\"Success: {out_name}\")\n    except Exception as exc:\n        print(f\"Failed {raster_path}: {exc}\")\n","python","",[24,274,275,287,295,303,310,317,331,342,356,370,375,399,420,425,440,461,477,482,493,502,520,533,545,557,569,582,598,607,613,618,627,639,668,683],{"__ignoreMap":272},[276,277,279,283],"span",{"class":194,"line":278},1,[276,280,282],{"class":281},"snl16","import",[276,284,286],{"class":285},"s95oV"," os\n",[276,288,290,292],{"class":194,"line":289},2,[276,291,282],{"class":281},[276,293,294],{"class":285}," glob\n",[276,296,298,300],{"class":194,"line":297},3,[276,299,282],{"class":281},[276,301,302],{"class":285}," processing\n",[276,304,306],{"class":194,"line":305},4,[276,307,309],{"emptyLinePlaceholder":308},true,"\n",[276,311,313],{"class":194,"line":312},5,[276,314,316],{"class":315},"sjoCn","# Configuration\n",[276,318,320,324,327],{"class":194,"line":319},6,[276,321,323],{"class":322},"sDLfK","INPUT_DIR",[276,325,326],{"class":281}," =",[276,328,330],{"class":329},"sU2Wk"," \"\u002Fdata\u002Fsource\u002Frasters\"\n",[276,332,334,337,339],{"class":194,"line":333},7,[276,335,336],{"class":322},"OUTPUT_DIR",[276,338,326],{"class":281},[276,340,341],{"class":329}," \"\u002Fdata\u002Freprojected\u002Frasters\"\n",[276,343,345,348,350,353],{"class":194,"line":344},8,[276,346,347],{"class":322},"TARGET_CRS",[276,349,326],{"class":281},[276,351,352],{"class":329}," \"EPSG:3857\"",[276,354,355],{"class":315},"   # your target projection\n",[276,357,359,362,364,367],{"class":194,"line":358},9,[276,360,361],{"class":322},"RESAMPLING",[276,363,326],{"class":281},[276,365,366],{"class":322}," 1",[276,368,369],{"class":315},"             # 0=Nearest, 1=Bilinear, 2=Cubic, 3=CubicSpline\n",[276,371,373],{"class":194,"line":372},10,[276,374,309],{"emptyLinePlaceholder":308},[276,376,378,381,383,386,390,393,396],{"class":194,"line":377},11,[276,379,380],{"class":285},"os.makedirs(",[276,382,336],{"class":322},[276,384,385],{"class":285},", ",[276,387,389],{"class":388},"s9osk","exist_ok",[276,391,392],{"class":281},"=",[276,394,395],{"class":322},"True",[276,397,398],{"class":285},")\n",[276,400,402,405,407,410,412,414,417],{"class":194,"line":401},12,[276,403,404],{"class":285},"raster_files ",[276,406,392],{"class":281},[276,408,409],{"class":285}," glob.glob(os.path.join(",[276,411,323],{"class":322},[276,413,385],{"class":285},[276,415,416],{"class":329},"\"*.tif\"",[276,418,419],{"class":285},"))\n",[276,421,423],{"class":194,"line":422},13,[276,424,309],{"emptyLinePlaceholder":308},[276,426,428,431,434,437],{"class":194,"line":427},14,[276,429,430],{"class":281},"for",[276,432,433],{"class":285}," raster_path ",[276,435,436],{"class":281},"in",[276,438,439],{"class":285}," raster_files:\n",[276,441,443,446,448,451,454,456,459],{"class":194,"line":442},15,[276,444,445],{"class":285},"    out_name ",[276,447,392],{"class":281},[276,449,450],{"class":285}," os.path.basename(raster_path).replace(",[276,452,453],{"class":329},"\".tif\"",[276,455,385],{"class":285},[276,457,458],{"class":329},"\"_reproj.tif\"",[276,460,398],{"class":285},[276,462,464,467,469,472,474],{"class":194,"line":463},16,[276,465,466],{"class":285},"    out_path ",[276,468,392],{"class":281},[276,470,471],{"class":285}," os.path.join(",[276,473,336],{"class":322},[276,475,476],{"class":285},", out_name)\n",[276,478,480],{"class":194,"line":479},17,[276,481,309],{"emptyLinePlaceholder":308},[276,483,485,488,490],{"class":194,"line":484},18,[276,486,487],{"class":285},"    params ",[276,489,392],{"class":281},[276,491,492],{"class":285}," {\n",[276,494,496,499],{"class":194,"line":495},19,[276,497,498],{"class":329},"        \"INPUT\"",[276,500,501],{"class":285},": raster_path,\n",[276,503,505,508,511,514,517],{"class":194,"line":504},20,[276,506,507],{"class":329},"        \"SOURCE_CRS\"",[276,509,510],{"class":285},": ",[276,512,513],{"class":322},"None",[276,515,516],{"class":285},",          ",[276,518,519],{"class":315},"# auto-detect from file metadata\n",[276,521,523,526,528,530],{"class":194,"line":522},21,[276,524,525],{"class":329},"        \"TARGET_CRS\"",[276,527,510],{"class":285},[276,529,347],{"class":322},[276,531,532],{"class":285},",\n",[276,534,536,539,541,543],{"class":194,"line":535},22,[276,537,538],{"class":329},"        \"RESAMPLING\"",[276,540,510],{"class":285},[276,542,361],{"class":322},[276,544,532],{"class":285},[276,546,548,551,553,555],{"class":194,"line":547},23,[276,549,550],{"class":329},"        \"NODATA\"",[276,552,510],{"class":285},[276,554,513],{"class":322},[276,556,532],{"class":285},[276,558,560,563,565,567],{"class":194,"line":559},24,[276,561,562],{"class":329},"        \"TARGET_RESOLUTION\"",[276,564,510],{"class":285},[276,566,513],{"class":322},[276,568,532],{"class":285},[276,570,572,575,577,580],{"class":194,"line":571},25,[276,573,574],{"class":329},"        \"OPTIONS\"",[276,576,510],{"class":285},[276,578,579],{"class":329},"\"\"",[276,581,532],{"class":285},[276,583,585,588,590,592,595],{"class":194,"line":584},26,[276,586,587],{"class":329},"        \"DATA_TYPE\"",[276,589,510],{"class":285},[276,591,53],{"class":322},[276,593,594],{"class":285},",              ",[276,596,597],{"class":315},"# 0=Auto (keep source data type)\n",[276,599,601,604],{"class":194,"line":600},27,[276,602,603],{"class":329},"        \"OUTPUT\"",[276,605,606],{"class":285},": out_path,\n",[276,608,610],{"class":194,"line":609},28,[276,611,612],{"class":285},"    }\n",[276,614,616],{"class":194,"line":615},29,[276,617,309],{"emptyLinePlaceholder":308},[276,619,621,624],{"class":194,"line":620},30,[276,622,623],{"class":281},"    try",[276,625,626],{"class":285},":\n",[276,628,630,633,636],{"class":194,"line":629},31,[276,631,632],{"class":285},"        processing.run(",[276,634,635],{"class":329},"\"gdal:warpreproject\"",[276,637,638],{"class":285},", params)\n",[276,640,642,645,648,651,654,657,660,663,666],{"class":194,"line":641},32,[276,643,644],{"class":322},"        print",[276,646,647],{"class":285},"(",[276,649,650],{"class":281},"f",[276,652,653],{"class":329},"\"Success: ",[276,655,656],{"class":322},"{",[276,658,659],{"class":285},"out_name",[276,661,662],{"class":322},"}",[276,664,665],{"class":329},"\"",[276,667,398],{"class":285},[276,669,671,674,677,680],{"class":194,"line":670},33,[276,672,673],{"class":281},"    except",[276,675,676],{"class":322}," Exception",[276,678,679],{"class":281}," as",[276,681,682],{"class":285}," exc:\n",[276,684,686,688,690,692,695,697,700,702,704,706,709,711,713],{"class":194,"line":685},34,[276,687,644],{"class":322},[276,689,647],{"class":285},[276,691,650],{"class":281},[276,693,694],{"class":329},"\"Failed ",[276,696,656],{"class":322},[276,698,699],{"class":285},"raster_path",[276,701,662],{"class":322},[276,703,510],{"class":329},[276,705,656],{"class":322},[276,707,708],{"class":285},"exc",[276,710,662],{"class":322},[276,712,665],{"class":329},[276,714,398],{"class":285},[14,716,717,721,722,725,726,729,730,733,734,736,737,739,740,743,744,746],{},[718,719,720],"strong",{},"Breakdown:"," ",[24,723,724],{},"glob.glob"," collects every ",[24,727,728],{},".tif"," in the source folder, and each iteration builds an output name so results never overwrite the originals. ",[24,731,732],{},"SOURCE_CRS=None"," tells GDAL to read the projection from each file's own metadata, while ",[24,735,347],{}," is the single destination every file is warped into. ",[24,738,361],{}," chooses the interpolation kernel, ",[24,741,742],{},"DATA_TYPE=0"," preserves the source pixel type, and wrapping ",[24,745,26],{}," in try\u002Fexcept keeps the loop alive when one file has a problem.",[14,748,749],{},"Resampling is the decision that separates a correct batch from a plausible one, because the wrong method does not fail — it produces values that never existed in the source.",[14,751,752],{},[36,753,756,759,762,765,770,828,878],{"viewBox":754,"role":39,"ariaLabel":755,"xmlns":41},"0 0 760 250","Three resampling methods applied to a categorical land-cover raster and a continuous elevation raster, showing that averaging invents categories that do not exist",[43,757,758],{},"Why categorical rasters must use nearest neighbour",[47,760,761],{},"A land-cover raster with classes one, two and five is resampled. Nearest neighbour keeps only existing class values. Bilinear averaging produces intermediate values such as three point five, which correspond to no class at all. On a continuous elevation raster the same averaging is correct and produces a smoother surface.",[51,763],{"x":53,"y":53,"width":764,"height":101,"fill":56},"760",[86,766,769],{"x":767,"y":768,"style":90,"fill":91,"textAnchor":92},"380","26","Averaging class codes invents classes that do not exist",[771,772,773,779,784,825],"g",{},[51,774],{"x":775,"y":776,"width":777,"height":778,"rx":105,"fill":82,"stroke":154,"style":84},"12","46","236","188",[86,780,783],{"x":781,"y":102,"style":782,"fill":154,"textAnchor":92},"130","text-anchor:middle;font-size:11.5px;font-weight:bold;font-family:sans-serif","land cover · nearest",[771,785,787,794,798,801,805,808,811,814,817,819,821,823],{"style":786},"font-size:12px;font-family:monospace;text-anchor:middle",[51,788],{"x":153,"y":789,"width":790,"height":791,"fill":154,"fillOpacity":792,"stroke":154,"style":793},"88","52","40",0.25,"stroke-width:1.5",[86,795,797],{"x":119,"y":796,"fill":74},"113","1",[51,799],{"x":800,"y":789,"width":790,"height":791,"fill":83,"fillOpacity":792,"stroke":83,"style":793},"100",[86,802,804],{"x":803,"y":796,"fill":74},"126","2",[51,806],{"x":807,"y":789,"width":790,"height":791,"fill":106,"fillOpacity":792,"stroke":106,"style":793},"152",[86,809,66],{"x":810,"y":796,"fill":74},"178",[51,812],{"x":153,"y":813,"width":790,"height":791,"fill":154,"fillOpacity":792,"stroke":154,"style":793},"140",[86,815,797],{"x":119,"y":816,"fill":74},"165",[51,818],{"x":800,"y":813,"width":790,"height":791,"fill":106,"fillOpacity":792,"stroke":106,"style":793},[86,820,66],{"x":803,"y":816,"fill":74},[51,822],{"x":807,"y":813,"width":790,"height":791,"fill":83,"fillOpacity":792,"stroke":83,"style":793},[86,824,804],{"x":810,"y":816,"fill":74},[86,826,827],{"x":781,"y":197,"style":129,"fill":154,"textAnchor":92},"every value is a real class",[771,829,830,833,836,875],{},[51,831],{"x":183,"y":776,"width":777,"height":778,"rx":105,"fill":82,"stroke":832,"style":84},"#b91c1c",[86,834,835],{"x":767,"y":102,"style":782,"fill":832,"textAnchor":92},"land cover · bilinear",[771,837,838,842,846,849,853,856,860,862,865,867,870,872],{"style":786},[51,839],{"x":840,"y":789,"width":790,"height":791,"fill":832,"fillOpacity":841,"stroke":832,"style":793},"298",0.2,[86,843,845],{"x":844,"y":796,"fill":74},"324","1.4",[51,847],{"x":848,"y":789,"width":790,"height":791,"fill":832,"fillOpacity":841,"stroke":832,"style":793},"350",[86,850,852],{"x":851,"y":796,"fill":74},"376","3.1",[51,854],{"x":855,"y":789,"width":790,"height":791,"fill":832,"fillOpacity":841,"stroke":832,"style":793},"402",[86,857,859],{"x":858,"y":796,"fill":74},"428","3.8",[51,861],{"x":840,"y":813,"width":790,"height":791,"fill":832,"fillOpacity":841,"stroke":832,"style":793},[86,863,864],{"x":844,"y":816,"fill":74},"2.2",[51,866],{"x":848,"y":813,"width":790,"height":791,"fill":832,"fillOpacity":841,"stroke":832,"style":793},[86,868,869],{"x":851,"y":816,"fill":74},"3.5",[51,871],{"x":855,"y":813,"width":790,"height":791,"fill":832,"fillOpacity":841,"stroke":832,"style":793},[86,873,874],{"x":858,"y":816,"fill":74},"2.9",[86,876,877],{"x":767,"y":197,"style":129,"fill":832,"textAnchor":92},"class 3.5 does not exist",[771,879,880,883,887,929],{},[51,881],{"x":882,"y":776,"width":777,"height":778,"rx":105,"fill":82,"stroke":154,"style":84},"512",[86,884,886],{"x":885,"y":102,"style":782,"fill":154,"textAnchor":92},"630","elevation · bilinear",[771,888,890,894,898,900,904,908,912,914,917,920,923,926],{"style":889},"font-size:11px;font-family:monospace;text-anchor:middle",[51,891],{"x":892,"y":789,"width":790,"height":791,"fill":120,"fillOpacity":893,"stroke":120,"style":793},"548",0.15,[86,895,897],{"x":896,"y":796,"fill":74},"574","312.4",[51,899],{"x":166,"y":789,"width":790,"height":791,"fill":120,"fillOpacity":792,"stroke":120,"style":793},[86,901,903],{"x":902,"y":796,"fill":74},"626","318.9",[51,905],{"x":906,"y":789,"width":790,"height":791,"fill":120,"fillOpacity":907,"stroke":120,"style":793},"652",0.35,[86,909,911],{"x":910,"y":796,"fill":74},"678","325.1",[51,913],{"x":892,"y":813,"width":790,"height":791,"fill":120,"fillOpacity":841,"stroke":120,"style":793},[86,915,916],{"x":896,"y":816,"fill":74},"315.8",[51,918],{"x":166,"y":813,"width":790,"height":791,"fill":120,"fillOpacity":919,"stroke":120,"style":793},0.3,[86,921,922],{"x":902,"y":816,"fill":74},"321.6",[51,924],{"x":906,"y":813,"width":790,"height":791,"fill":120,"fillOpacity":925,"stroke":120,"style":793},0.4,[86,927,928],{"x":910,"y":816,"fill":74},"328.3",[86,930,931],{"x":885,"y":197,"style":129,"fill":154,"textAnchor":92},"intermediate values are valid",[223,933,935],{"id":934},"choose-the-right-resampling","Choose the Right Resampling",[14,937,938],{},"The resampling method is the one setting that silently corrupts data if you get it wrong, so match it to what the raster represents:",[228,940,941,950,958],{},[231,942,943,949],{},[718,944,945,946,948],{},"Nearest Neighbor (",[24,947,53],{},")"," — for categorical rasters such as land cover, soil class, or any classified map. It copies existing pixel values and never invents an intermediate class, so class codes stay valid.",[231,951,952,957],{},[718,953,954,955,948],{},"Bilinear (",[24,956,797],{}," — a good default for continuous data such as elevation, slope, or temperature, giving smooth results at modest cost.",[231,959,960,969],{},[718,961,962,963,965,966,948],{},"Cubic (",[24,964,804],{},") \u002F Cubic Spline (",[24,967,968],{},"3"," — smoother still for continuous surfaces where interpolation quality matters more than speed.",[14,971,972],{},"Applying Bilinear or Cubic to a categorical raster averages neighbouring class codes into meaningless in-between values, so always drop to Nearest Neighbor for classified data.",[223,974,976],{"id":975},"handle-missing-source-crs","Handle Missing Source CRS",[14,978,979,981,982,984],{},[24,980,732],{}," works only when the file actually carries projection metadata. If a file has none, ",[24,983,30],{}," raises a \"CRS not defined\" error. Rather than assume a default, read the CRS first and pass it explicitly for that file:",[267,986,988],{"className":269,"code":987,"language":271,"meta":272,"style":272},"from qgis.core import QgsRasterLayer\n\nlayer = QgsRasterLayer(raster_path, \"probe\")\nsource_crs = layer.crs().authid()   # e.g. \"EPSG:32633\"\n\nif source_crs:\n    params[\"SOURCE_CRS\"] = source_crs\nelse:\n    print(f\"Skipping (no CRS): {raster_path}\")\n    continue\n",[24,989,990,1003,1007,1022,1035,1039,1047,1063,1070,1092],{"__ignoreMap":272},[276,991,992,995,998,1000],{"class":194,"line":278},[276,993,994],{"class":281},"from",[276,996,997],{"class":285}," qgis.core ",[276,999,282],{"class":281},[276,1001,1002],{"class":285}," QgsRasterLayer\n",[276,1004,1005],{"class":194,"line":289},[276,1006,309],{"emptyLinePlaceholder":308},[276,1008,1009,1012,1014,1017,1020],{"class":194,"line":297},[276,1010,1011],{"class":285},"layer ",[276,1013,392],{"class":281},[276,1015,1016],{"class":285}," QgsRasterLayer(raster_path, ",[276,1018,1019],{"class":329},"\"probe\"",[276,1021,398],{"class":285},[276,1023,1024,1027,1029,1032],{"class":194,"line":305},[276,1025,1026],{"class":285},"source_crs ",[276,1028,392],{"class":281},[276,1030,1031],{"class":285}," layer.crs().authid()   ",[276,1033,1034],{"class":315},"# e.g. \"EPSG:32633\"\n",[276,1036,1037],{"class":194,"line":312},[276,1038,309],{"emptyLinePlaceholder":308},[276,1040,1041,1044],{"class":194,"line":319},[276,1042,1043],{"class":281},"if",[276,1045,1046],{"class":285}," source_crs:\n",[276,1048,1049,1052,1055,1058,1060],{"class":194,"line":333},[276,1050,1051],{"class":285},"    params[",[276,1053,1054],{"class":329},"\"SOURCE_CRS\"",[276,1056,1057],{"class":285},"] ",[276,1059,392],{"class":281},[276,1061,1062],{"class":285}," source_crs\n",[276,1064,1065,1068],{"class":194,"line":344},[276,1066,1067],{"class":281},"else",[276,1069,626],{"class":285},[276,1071,1072,1075,1077,1079,1082,1084,1086,1088,1090],{"class":194,"line":358},[276,1073,1074],{"class":322},"    print",[276,1076,647],{"class":285},[276,1078,650],{"class":281},[276,1080,1081],{"class":329},"\"Skipping (no CRS): ",[276,1083,656],{"class":322},[276,1085,699],{"class":285},[276,1087,662],{"class":322},[276,1089,665],{"class":329},[276,1091,398],{"class":285},[276,1093,1094],{"class":194,"line":372},[276,1095,1096],{"class":281},"    continue\n",[14,1098,1099,1101,1102,1105,1106,1109,1110,1114],{},[718,1100,720],{}," Loading the raster as a ",[24,1103,1104],{},"QgsRasterLayer"," lets you query ",[24,1107,1108],{},"crs().authid()"," for an authority string. When it comes back empty the file's projection is genuinely unknown, and skipping-and-logging is safer than injecting a guess that would misplace every pixel. This mirrors the detection pattern used across ",[18,1111,1113],{"href":1112},"\u002Fspatial-data-processing-automation\u002F","Spatial Data Processing & Automation"," pipelines.",[14,1116,1117],{},"A batch that stops on its first bad file wastes the run. Recording each outcome and continuing turns a failed batch into a report you can act on.",[14,1119,1120],{},[36,1121,1124,1127,1130,1133,1136,1141,1173,1177,1181,1200,1203],{"viewBox":1122,"role":39,"ariaLabel":1123,"xmlns":41},"0 0 760 232","A batch of eight rasters where one fails, contrasting an abort-on-error run that stops at file three with a collect-errors run that processes all eight and reports one failure",[43,1125,1126],{},"Abort on error versus collect and continue",[47,1128,1129],{},"Eight input rasters are processed. In the abort-on-error run, file three fails and the remaining five are never attempted, so the run produces two outputs and no information about the rest. In the collect-and-continue run, file three is recorded as failed and the other seven are processed, producing seven outputs and a named failure to investigate.",[51,1131],{"x":53,"y":53,"width":764,"height":1132,"fill":56},"232",[86,1134,1135],{"x":767,"y":768,"style":90,"fill":91,"textAnchor":92},"One corrupt file should not cost you the whole run",[86,1137,1140],{"x":201,"y":184,"style":1138,"fill":832,"textAnchor":1139},"text-anchor:end;font-size:11.5px;font-weight:bold;font-family:sans-serif","end","abort on error",[771,1142,1143,1151,1154,1156,1161,1164,1167,1170],{},[51,1144],{"x":1145,"y":1146,"width":1147,"height":1148,"rx":1149,"fill":154,"fillOpacity":907,"stroke":154,"style":1150},"200","62","58","30","4","stroke-width:1.6",[51,1152],{"x":1153,"y":1146,"width":1147,"height":1148,"rx":1149,"fill":154,"fillOpacity":907,"stroke":154,"style":1150},"266",[51,1155],{"x":220,"y":1146,"width":1147,"height":1148,"rx":1149,"fill":832,"fillOpacity":925,"stroke":832,"style":121},[51,1157],{"x":1158,"y":1146,"width":1147,"height":1148,"rx":1149,"fill":82,"stroke":1159,"style":1160},"398","#59645f","stroke-width:1.3;stroke-dasharray:4 3",[51,1162],{"x":1163,"y":1146,"width":1147,"height":1148,"rx":1149,"fill":82,"stroke":1159,"style":1160},"464",[51,1165],{"x":1166,"y":1146,"width":1147,"height":1148,"rx":1149,"fill":82,"stroke":1159,"style":1160},"530",[51,1168],{"x":1169,"y":1146,"width":1147,"height":1148,"rx":1149,"fill":82,"stroke":1159,"style":1160},"596",[51,1171],{"x":1172,"y":1146,"width":1147,"height":1148,"rx":1149,"fill":82,"stroke":1159,"style":1160},"662",[86,1174,1176],{"x":1145,"y":117,"style":1175,"fill":832},"font-size:11px;font-family:sans-serif","2 written, 5 never attempted",[86,1178,1180],{"x":201,"y":1179,"style":1138,"fill":154,"textAnchor":1139},"160","collect and continue",[771,1182,1183,1186,1188,1190,1192,1194,1196,1198],{},[51,1184],{"x":1145,"y":1185,"width":1147,"height":1148,"rx":1149,"fill":154,"fillOpacity":907,"stroke":154,"style":1150},"142",[51,1187],{"x":1153,"y":1185,"width":1147,"height":1148,"rx":1149,"fill":154,"fillOpacity":907,"stroke":154,"style":1150},[51,1189],{"x":220,"y":1185,"width":1147,"height":1148,"rx":1149,"fill":106,"fillOpacity":925,"stroke":106,"style":121},[51,1191],{"x":1158,"y":1185,"width":1147,"height":1148,"rx":1149,"fill":154,"fillOpacity":907,"stroke":154,"style":1150},[51,1193],{"x":1163,"y":1185,"width":1147,"height":1148,"rx":1149,"fill":154,"fillOpacity":907,"stroke":154,"style":1150},[51,1195],{"x":1166,"y":1185,"width":1147,"height":1148,"rx":1149,"fill":154,"fillOpacity":907,"stroke":154,"style":1150},[51,1197],{"x":1169,"y":1185,"width":1147,"height":1148,"rx":1149,"fill":154,"fillOpacity":907,"stroke":154,"style":1150},[51,1199],{"x":1172,"y":1185,"width":1147,"height":1148,"rx":1149,"fill":154,"fillOpacity":907,"stroke":154,"style":1150},[86,1201,1202],{"x":1145,"y":168,"style":1175,"fill":154},"7 written, 1 named failure to investigate",[86,1204,1206],{"x":1205,"y":197,"style":129,"fill":106,"textAnchor":92},"361","↑ the bad file",[223,1208,1210],{"id":1209},"tame-large-datasets","Tame Large Datasets",[14,1212,1213,1214,1217],{},"Big collections stress memory and hit file-format limits. GDAL tiles rasters into RAM as it warps, so keep roughly twice the size of the largest input free. Pass creation options through the ",[24,1215,1216],{},"OPTIONS"," parameter to compress, tile, and lift the classic 4 GB TIFF ceiling:",[267,1219,1221],{"className":269,"code":1220,"language":271,"meta":272,"style":272},"params[\"OPTIONS\"] = \"-co TILED=YES -co COMPRESS=LZW -co BIGTIFF=YES\"\n",[24,1222,1223],{"__ignoreMap":272},[276,1224,1225,1228,1231,1233,1235],{"class":194,"line":278},[276,1226,1227],{"class":285},"params[",[276,1229,1230],{"class":329},"\"OPTIONS\"",[276,1232,1057],{"class":285},[276,1234,392],{"class":281},[276,1236,1237],{"class":329}," \"-co TILED=YES -co COMPRESS=LZW -co BIGTIFF=YES\"\n",[14,1239,1240,1243,1244,1247,1248,1251,1252,1255,1256,1260],{},[24,1241,1242],{},"TILED=YES"," stores the output in internal tiles for faster windowed reads, ",[24,1245,1246],{},"COMPRESS=LZW"," shrinks it losslessly, and ",[24,1249,1250],{},"BIGTIFF=YES"," allows outputs beyond 4 GB. For collections over roughly 50 GB, process in chunks or build a Virtual Raster with ",[24,1253,1254],{},"gdal:buildvirtualraster"," first, then warp the VRT so GDAL streams from many files as if they were one. Reprojected tiles then feed cleanly into downstream steps such as ",[18,1257,1259],{"href":1258},"\u002Fspatial-data-processing-automation\u002Fraster-analysis-workflows\u002Fclip-raster-by-mask-layer-pyqgis\u002F","Clip a Raster by a Mask Layer in PyQGIS",".",[223,1262,1264],{"id":1263},"qgis-version-compatibility","QGIS Version Compatibility",[14,1266,1267,1268,1271],{},"The code targets ",[718,1269,1270],{},"QGIS 3.34 LTR"," (Python 3.12).",[1273,1274,1275,1291],"table",{},[1276,1277,1278],"thead",{},[1279,1280,1281,1285,1288],"tr",{},[1282,1283,1284],"th",{},"QGIS version",[1282,1286,1287],{},"Python",[1282,1289,1290],{},"Notes",[1292,1293,1294,1308,1319],"tbody",{},[1279,1295,1296,1300,1303],{},[1297,1298,1299],"td",{},"3.28 LTR",[1297,1301,1302],{},"3.9",[1297,1304,1305,1307],{},[24,1306,30],{}," parameters identical; requires GDAL ≥ 3.4 for reliable datum shifts.",[1279,1309,1310,1313,1316],{},[1297,1311,1312],{},"3.34 LTR",[1297,1314,1315],{},"3.12",[1297,1317,1318],{},"Baseline for this page.",[1279,1320,1321,1324,1326],{},[1297,1322,1323],{},"3.40 \u002F 3.44",[1297,1325,1315],{},[1297,1327,1328],{},"Same algorithm ID and parameters; newer bundled GDAL improves nodata and edge handling.",[14,1330,1331,1332,1334,1335,1338],{},"On very old builds (pre-3.24) ",[24,1333,347],{}," sometimes had to be a ",[24,1336,1337],{},"QgsCoordinateReferenceSystem"," object rather than an authority string; on the current LTR line the string form shown here is stable. The exact GDAL version bundled differs per release, which can affect edge-pixel handling on huge rasters, but the PyQGIS interface is unchanged.",[223,1340,1342],{"id":1341},"troubleshooting","Troubleshooting",[228,1344,1345,1362,1371,1381,1394,1408],{},[231,1346,1347,1353,1354,1357,1358,1361],{},[718,1348,1349,1352],{},[24,1350,1351],{},"CRS not defined"," on some files."," Those inputs carry no projection metadata. Read the CRS with ",[24,1355,1356],{},"QgsRasterLayer(path, \"probe\").crs().authid()"," and pass it as ",[24,1359,1360],{},"SOURCE_CRS",", or skip and log the file — never assume a default.",[231,1363,1364,1367,1368,1260],{},[718,1365,1366],{},"Outputs drift or misalign across the batch."," PROJ datum-shift grids are missing, so GDAL falls back to a coarser transform. Confirm GDAL ≥ 3.4 and PROJ ≥ 8.2 with the proj-data package installed, and verify each output with ",[24,1369,1370],{},"gdalinfo",[231,1372,1373,1376,1377,1380],{},[718,1374,1375],{},"Categorical rasters come out with garbage values."," A continuous kernel was used on classified data. Set ",[24,1378,1379],{},"RESAMPLING = 0"," (Nearest Neighbor).",[231,1382,1383,1386,1387,1390,1391,1393],{},[718,1384,1385],{},"Out-of-memory or very slow runs."," Add ",[24,1388,1389],{},"-co TILED=YES -co COMPRESS=LZW"," to ",[24,1392,1216],{},", keep ~2× the largest file free in RAM, and split extremely large collections into chunks or a Virtual Raster.",[231,1395,1396,1386,1402,1390,1405,1407],{},[718,1397,1398,1401],{},[24,1399,1400],{},"BIGTIFF"," errors on files over 4 GB.",[24,1403,1404],{},"-co BIGTIFF=YES",[24,1406,1216],{}," to switch off the classic-TIFF size limit.",[231,1409,1410,1413,1414,1417],{},[718,1411,1412],{},"Windows path issues."," Use raw strings (",[24,1415,1416],{},"r\"C:\\data\"",") or forward slashes, avoid spaces where possible, and expect network drives to time out on large batches.",[223,1419,1421],{"id":1420},"the-gui-and-cli-fallbacks","The GUI and CLI Fallbacks",[14,1423,1424,1425,1428,1429,1432],{},"If you would rather not script it, the same algorithm runs as a batch job in the interface: ",[24,1426,1427],{},"Processing Toolbox > GDAL > Warp (Reproject)",", then right-click the tool and choose ",[718,1430,1431],{},"Execute as Batch Process",". Drag the files in, set the target CRS column, and run. It bypasses Python but offers no programmatic error recovery.",[14,1434,1435],{},"When the QGIS bindings are unavailable entirely, a plain shell loop over native GDAL is a dependable fallback:",[267,1437,1441],{"className":1438,"code":1439,"language":1440,"meta":272,"style":272},"language-bash shiki shiki-themes github-dark","mkdir -p reproj_output\nfor f in source\u002F*.tif; do\n    gdalwarp -t_srs EPSG:3857 -r bilinear \\\n        \"$f\" \"reproj_output\u002F$(basename \"$f\" .tif)_reproj.tif\"\ndone\n","bash",[24,1442,1443,1455,1473,1493,1517],{"__ignoreMap":272},[276,1444,1445,1449,1452],{"class":194,"line":278},[276,1446,1448],{"class":1447},"svObZ","mkdir",[276,1450,1451],{"class":322}," -p",[276,1453,1454],{"class":329}," reproj_output\n",[276,1456,1457,1459,1462,1464,1467,1470],{"class":194,"line":289},[276,1458,430],{"class":281},[276,1460,1461],{"class":285}," f ",[276,1463,436],{"class":281},[276,1465,1466],{"class":329}," source\u002F*.tif",[276,1468,1469],{"class":285},"; ",[276,1471,1472],{"class":281},"do\n",[276,1474,1475,1478,1481,1484,1487,1490],{"class":194,"line":297},[276,1476,1477],{"class":1447},"    gdalwarp",[276,1479,1480],{"class":322}," -t_srs",[276,1482,1483],{"class":329}," EPSG:3857",[276,1485,1486],{"class":322}," -r",[276,1488,1489],{"class":329}," bilinear",[276,1491,1492],{"class":322}," \\\n",[276,1494,1495,1498,1501,1503,1506,1509,1512,1514],{"class":194,"line":305},[276,1496,1497],{"class":329},"        \"",[276,1499,1500],{"class":285},"$f",[276,1502,665],{"class":329},[276,1504,1505],{"class":329}," \"reproj_output\u002F$(",[276,1507,1508],{"class":1447},"basename",[276,1510,1511],{"class":329}," \"",[276,1513,1500],{"class":285},[276,1515,1516],{"class":329},"\" .tif)_reproj.tif\"\n",[276,1518,1519],{"class":194,"line":312},[276,1520,1521],{"class":281},"done\n",[14,1523,1524],{},"This is the CLI equivalent of the recipe above and useful in headless environments or CI where a full QGIS install is not present.",[223,1526,1528],{"id":1527},"conclusion","Conclusion",[14,1530,1531,1532,1534,1535,1537,1538,1540,1541,1543,1544,1546],{},"Batch reprojecting rasters in PyQGIS comes down to a few deliberate choices: let ",[24,1533,732],{}," auto-detect where metadata exists and read it explicitly where it does not, match ",[24,1536,361],{}," to whether the data is categorical or continuous, and reach for ",[24,1539,1216],{}," tiling, compression, and BigTIFF once files get large. Wrapping each ",[24,1542,30],{}," call in try\u002Fexcept keeps a big run resilient, and a final ",[24,1545,1370],{}," check confirms every output carries the target CRS exactly. With that in place, an entire folder of mismatched rasters becomes an aligned, analysis-ready collection in one pass.",[223,1548,1550],{"id":1549},"frequently-asked-questions","Frequently Asked Questions",[14,1552,1553,1556,1557,1559,1560,1562,1563,1565],{},[718,1554,1555],{},"Which resampling method should I choose when batch reprojecting?","\nUse Nearest Neighbor (",[24,1558,1379],{},") for categorical rasters such as land cover or classified maps, because it never invents intermediate class values. Use Bilinear (",[24,1561,797],{},") or Cubic (",[24,1564,804],{},") for continuous data such as elevation or temperature, where smooth interpolation is appropriate. Applying a continuous method to categorical data introduces false pixel values that corrupt later analysis.",[14,1567,1568,1577,1579,1580,1582],{},[718,1569,1570,1571,1573,1574,1576],{},"What happens if ",[24,1572,1360],{}," is set to ",[24,1575,513],{},"?",[24,1578,30],{}," tries to auto-detect the source projection from each file's embedded metadata, which works for well-formed GeoTIFFs. If a file lacks projection metadata it raises a \"CRS not defined\" error; in that case extract the CRS first with ",[24,1581,1356],{}," and pass it explicitly. Never assume a default source projection for files of unknown origin.",[14,1584,1585,1588,1589,1591],{},[718,1586,1587],{},"Why are my outputs drifting or misaligned after reprojection?","\nCoordinate drift across a batch usually means PROJ datum-shift grids are missing, so GDAL falls back to a less accurate transformation. Confirm GDAL is at least 3.4 and PROJ at least 8.2 with the proj-data package installed. Verify each output with ",[24,1590,1370],{}," to ensure the embedded CRS matches your target exactly.",[14,1593,1594,1597,1598,1390,1601,1603,1604,1606],{},[718,1595,1596],{},"How do I reproject very large rasters without exhausting memory?","\nKeep roughly twice the size of the largest raster free in RAM, and add ",[24,1599,1600],{},"\"-co TILED=YES -co COMPRESS=LZW\"",[24,1602,1216],{}," to reduce I\u002FO pressure. For files over 4 GB also add ",[24,1605,1404],{}," to bypass the classic TIFF size limit. For collections over 50 GB, process in chunks or build a Virtual Raster first.",[14,1608,1609,1612,1613,1616,1617,1620,1621,1623,1624,1627],{},[718,1610,1611],{},"Can I run this batch script outside the QGIS Python Console?","\nYes, but a standalone script must initialize the application context with ",[24,1614,1615],{},"QgsApplication([], False)"," and ",[24,1618,1619],{},"initQgis()"," before calling ",[24,1622,26],{},". Inside the console this setup is already done. If QGIS bindings are unavailable entirely, the native ",[24,1625,1626],{},"gdalwarp"," CLI loop shown above is a dependable fallback.",[223,1629,1631],{"id":1630},"related","Related",[228,1633,1634,1639,1643,1647,1653],{},[231,1635,1636],{},[18,1637,1638],{"href":20},"Coordinate Reference Systems in PyQGIS",[231,1640,1641],{},[18,1642,257],{"href":256},[231,1644,1645],{},[18,1646,1259],{"href":1258},[231,1648,1649],{},[18,1650,1652],{"href":1651},"\u002Fspatial-data-processing-automation\u002Fbatch-processing-with-pyqgis\u002F","Batch Processing with PyQGIS",[231,1654,1655],{},[18,1656,1658],{"href":1657},"\u002Fspatial-data-processing-automation\u002Fraster-analysis-workflows\u002F","Raster Analysis Workflows in PyQGIS",[1660,1661,1662],"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 .sjoCn, html code.shiki .sjoCn{--shiki-default:#9AA79F}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}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);}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}",{"title":272,"searchDepth":289,"depth":289,"links":1664},[1665,1666,1667,1668,1669,1670,1671,1672,1673,1674,1675],{"id":225,"depth":289,"text":226},{"id":261,"depth":289,"text":262},{"id":934,"depth":289,"text":935},{"id":975,"depth":289,"text":976},{"id":1209,"depth":289,"text":1210},{"id":1263,"depth":289,"text":1264},{"id":1341,"depth":289,"text":1342},{"id":1420,"depth":289,"text":1421},{"id":1527,"depth":289,"text":1528},{"id":1549,"depth":289,"text":1550},{"id":1630,"depth":289,"text":1631},"Batch reproject a folder of rasters in PyQGIS with gdal:warpreproject. Set the target CRS, pick the right resampling, and keep alignment across large collections.","md",{"slug":1679,"type":1680,"breadcrumb":1681,"datePublished":1682,"dateModified":1683},"batch-reprojecting-raster-datasets","article","Batch Reprojecting Raster Datasets","2026-06-20","2026-07-18","\u002Fspatial-data-processing-automation\u002Fcoordinate-reference-systems\u002Fbatch-reprojecting-raster-datasets",{"title":5,"description":1676},"spatial-data-processing-automation\u002Fcoordinate-reference-systems\u002Fbatch-reprojecting-raster-datasets\u002Findex","EDSL7Ux4BwwK4vQfj5n3EWQVr_9nNTMNdCl0j_L9vmk",1787823363582]