Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

QGIS 3 #7

Draft
wants to merge 24 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
508cc7a
burn mask now works, but still yields an error on proj
NicolaiThomassen Apr 8, 2020
514af6c
fixup! Format Python code with psf/black push
Apr 14, 2020
7f2a317
Create .gitattributes
j08lue Jun 9, 2020
b9faf70
feedback update
NicolaiThomassen Jun 9, 2020
db6b501
fixup! Format Python code with psf/black push
Jun 9, 2020
3b18327
updated sentinel2makeanglesimage
NicolaiThomassen Jun 10, 2020
0ac84a4
fixup! Format Python code with psf/black push
Jun 10, 2020
1bfd767
Updated Fmask
NicolaiThomassen Jun 10, 2020
de967db
fixup! Format Python code with psf/black push
Jun 10, 2020
9078bf2
TOA to qgis scripts no bug
NicolaiThomassen Jun 11, 2020
835defe
fixup! Format Python code with psf/black push
Jun 15, 2020
83f86cb
Fix imports from within QGIS
radosuav Jun 2, 2021
2fc04e4
fixup! Format Python code with psf/black push
Jun 2, 2021
c695a41
Update script to QGIS 3
radosuav Jul 8, 2021
52aa0ac
Adjust to work with new Sentinel-2 file format
radosuav Feb 18, 2022
608a010
Remove unused files
radosuav Feb 18, 2022
8fcfa89
Fix burning of cloud mask
radosuav Feb 22, 2022
3429dfe
Properly set the cloud probability threshold
radosuav Feb 25, 2022
9178c2a
Add script to reclassify Landsat QA_PIXEL to Fmask classes
radosuav Feb 25, 2022
2193d77
fixup! Format Python code with psf/black push
Feb 25, 2022
b1b6257
Fix cloud masking of new S2 scenes
radosuav Mar 16, 2022
831f0c4
fixup! Format Python code with psf/black push
Mar 16, 2022
4244da7
Correct spelling
radosuav Apr 19, 2022
f2d875f
Fix handling of raster inputs
radosuav Apr 20, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.zip binary
178 changes: 126 additions & 52 deletions scripts/qgis_fmask_burnMask.py
Original file line number Diff line number Diff line change
@@ -1,56 +1,130 @@
# Definition of inputs and outputs
# ==================================
##Fmask=group
##Burn cloud mask=name
##ParameterRaster|dataFile|An image file to burn the cloud mask into|False
##ParameterRaster|maskFile|Could mask from FMask|False
##*ParameterBoolean|maskNull|Mask FMask null pixels|True
##*ParameterBoolean|maskCloud|Mask FMask cloud pixels|True
##*ParameterBoolean|maskShadow|Mask FMask shadow pixels|True
##*ParameterBoolean|maskSnow|Mask FMask snow pixels|True
##*ParameterBoolean|maskWater|Mask FMask water pixels|False
##*ParameterBoolean|maskLand|Mask FMask land pixels|False
##OutputRaster|outputFile|Maked output image
# TODO yields Error1: PROJ...
from qgis.processing import alg
from processing.core.ProcessingConfig import ProcessingConfig
from db_manager.db_plugins import data_model
from processing.tools import system
from qgis import processing

from processing.tools import dataobjects, system

# Run GDAL warp to make sure that the mask file exactly aligns with the image file
progress.setText("Aligning mask raster to image raster...")
dataRaster = dataobjects.getObject(dataFile)
proj = dataRaster.crs().authid()
resolution = dataRaster.rasterUnitsPerPixelX()
bandCount = dataRaster.bandCount()
extent = dataobjects.extent([dataRaster])
warpMask = system.getTempFilename("tif")
params = {
"INPUT": maskFile,
"DEST_SRS": proj,
"TR": resolution,
"USE_RASTER_EXTENT": True,
"RASTER_EXTENT": extent,
"EXTENT_CRS": proj,
"METHOD": 0,
"RTYPE": 0,
"OUTPUT": warpMask,
}
processing.runalg("gdalogr:warpreproject", params)
@alg(
name="burncloudmask",
label=alg.tr("Burn cloud mask"),
group="fmask",
group_label=alg.tr("FMask"),
)
@alg.input(
type=alg.RASTER_LAYER,
name="dataFile",
label="An image file to burn the cloud mask into",
optional=False,
)
@alg.input(
type=alg.RASTER_LAYER,
name="maskFile",
label="Could mask from FMask",
optional=False,
)
@alg.input(
type=bool,
name="maskNull",
label="Mask FMask null pixels",
default=True,
advanced=True,
)
@alg.input(
type=bool,
name="maskCloud",
label="Mask FMask cloud pixels",
default=True,
advanced=True,
)
@alg.input(
type=bool,
name="maskShadow",
label="Mask FMask shadow pixels",
default=True,
advanced=True,
)
@alg.input(
type=bool,
name="maskSnow",
label="Mask FMask snow pixels",
default=True,
advanced=True,
)
@alg.input(
type=bool,
name="maskWater",
label="Mask FMask water pixels",
default=False,
advanced=True,
)
@alg.input(
type=bool,
name="maskLand",
label="Mask FMask land pixels",
default=False,
advanced=True,
)
@alg.input(type=alg.FILE_DEST, name="outputFile", label="Maked output image")
def burncloudmask(instance, parameters, context, feedback, inputs):
""" burncloudmask """

progress.setText("Applying mask to image...")
# First reclassify fmask output into two classes
flags = [maskNull, maskLand, maskCloud, maskShadow, maskSnow, maskWater]
maskClass = [str(i) for i in range(len(flags)) if flags[i]]
leaveClass = [str(i) for i in range(len(flags)) if not flags[i]]
reclassString = " ".join(maskClass) + " = 0\n" + " ".join(leaveClass) + " = 1"
reclassMask = system.getTempFilename("tif")
params = {
"input": warpMask,
"txtrules": reclassString,
"output": reclassMask,
"GRASS_REGION_PARAMETER": extent,
"GRASS_REGION_CELLSIZE_PARAMETER": resolution,
}
processing.runalg("grass7:r.reclass", params)
dataRaster = instance.parameterAsRasterLayer(parameters, "dataFile", context)
# Run GDAL warp to make sure that the mask file exactly aligns with the image file

# Then use OTB band maths on all bands
params = {"-il": dataFile + ";" + reclassMask, "-exp": "im1*im2b1", "-out": outputFile}
processing.runalg("otb:bandmathx", params)
feedback.setProgressText("Aligning mask raster to image raster...")
# feedback.setProgressText(str(dir(dataRaster)))

feedback.setProgressText(str(dir(parameters["dataFile"])))
extent = dataRaster.extent().asWktPolygon()
proj = dataRaster.crs().toWkt()
resolution = dataRaster.rasterUnitsPerPixelX()
bandCount = dataRaster.bandCount()
warpMask = system.getTempFilename("tif")
params = {
"INPUT": parameters["maskFile"],
"DEST_SRS": proj,
"TR": resolution,
"USE_RASTER_EXTENT": True,
"RASTER_EXTENT": extent,
"EXTENT_CRS": proj,
"METHOD": 0,
"RTYPE": 0,
"OUTPUT": warpMask,
}
processing.run("gdal:warpreproject", params, feedback=feedback, context=context)

feedback.setProgressText("Applying mask to image...")
# First reclassify fmask output into two classes
flags = [
parameters["maskNull"],
parameters["maskLand"],
parameters["maskCloud"],
parameters["maskShadow"],
parameters["maskSnow"],
parameters["maskWater"],
]
maskClass = [str(i) for i in range(len(flags)) if flags[i]]
leaveClass = [str(i) for i in range(len(flags)) if not flags[i]]
reclassString = " ".join(maskClass) + " = 0\n" + " ".join(leaveClass) + " = 1"
reclassMask = system.getTempFilename("tif")
params = {
"input": warpMask,
"txtrules": reclassString,
"output": reclassMask,
"GRASS_REGION_PARAMETER": extent,
"GRASS_REGION_CELLSIZE_PARAMETER": resolution,
}
processing.run("grass7:r.reclass", params, feedback=feedback, context=context)

# Then use OTB band maths on all bands
params = {
"il": [
instance.parameterAsString(parameters, "dataFile", context),
reclassMask,
],
"exp": "im1*im2b1",
"out": instance.parameterAsString(parameters, "outputFile", context),
}
processing.run("otb:BandMathX", params, feedback=feedback, context=context)
61 changes: 31 additions & 30 deletions scripts/qgis_fmask_sentinel2Stacked.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Definition of inputs and outputs
# ==================================
#Definition of inputs and outputs
#==================================
##FMask=group
##FMask Sentinel 2=name
##ParameterFile|granuledir|Path to .SAFE or tile/granule directory|True|False
Expand All @@ -14,55 +14,56 @@
##*ParameterNumber|greensnowthreshold|Threshold for Green reflectance for snow detection (Eqn 20). Increase this to reduce snow commission errors|0|1|0.1

from argparse import Namespace
import sys
import os.path
import tempfile
import shutil
from processing.tools import dataobjects

# here = os.path.dirname(scriptDescriptionFile)
# if here not in sys.path:
# sys.path.append(here)

from qgis_fmask.stacks.sentinel_stack import create_sentinel_stack
from qgis_fmask.interfaces.fmask_sentinel2Stacked import mainRoutine
from qgis_fmask.interfaces.fmask_sentinel2makeAnglesImage import (
mainRoutine as mainRoutine_angles,
)
from qgis_fmask.interfaces.fmask_sentinel2makeAnglesImage import mainRoutine as mainRoutine_angles
from qgis_fmask.interfaces.redirect_print import redirect_print
from qgis_fmask.interfaces.s2meta import find_xml_in_granule_dir


tempdir = tempfile.mkdtemp()
try:
progress.setConsoleInfo("Creating Sentinel 2 band stack VRT file ...")
tempvrt = os.path.join(tempdir, "temp.vrt")
feedback.pushConsoleInfo('Creating Sentinel 2 band stack VRT file ...')
tempvrt = os.path.join(tempdir, 'temp.vrt')
create_sentinel_stack(granuledir, outfile=tempvrt)
progress.setConsoleInfo("Done.")
feedback.pushConsoleInfo('Done.')

if not anglesfile:
progress.setConsoleInfo("Creating angles file ...")
anglesfile = os.path.join(tempdir, "angles.img")
feedback.pushConsoleInfo('Creating angles file ...')
anglesfile = os.path.join(tempdir, 'angles.img')
cmdargs_angles = Namespace(
infile=find_xml_in_granule_dir(granuledir), outfile=anglesfile
)
infile=find_xml_in_granule_dir(granuledir),
outfile=anglesfile)
import numpy as np

with np.errstate(invalid="ignore"):
with np.errstate(invalid='ignore'):
mainRoutine_angles(cmdargs_angles)
progress.setConsoleInfo("Done.")
feedback.pushConsoleInfo('Done.')

cmdargs = Namespace(
toa=tempvrt,
anglesfile=anglesfile,
output=output,
verbose=verbose,
tempdir=tempdir,
keepintermediates=False,
mincloudsize=mincloudsize,
cloudbufferdistance=cloudbufferdistance,
shadowbufferdistance=shadowbufferdistance,
cloudprobthreshold=cloudprobthreshold,
nirsnowthreshold=nirsnowthreshold,
greensnowthreshold=greensnowthreshold,
)
toa=tempvrt,
anglesfile=anglesfile,
output=output,
verbose=verbose,
tempdir=tempdir,
keepintermediates=False,
mincloudsize=mincloudsize,
cloudbufferdistance=cloudbufferdistance,
shadowbufferdistance=shadowbufferdistance,
cloudprobthreshold=cloudprobthreshold,
nirsnowthreshold=nirsnowthreshold,
greensnowthreshold=greensnowthreshold)

progress.setConsoleInfo("Running FMask (this may take a while) ...")
feedback.pushConsoleInfo('Running FMask (this may take a while) ...')
with redirect_print(progress):
mainRoutine(cmdargs)
finally:
Expand All @@ -71,5 +72,5 @@
except OSError:
pass

progress.setConsoleInfo("Done.")
feedback.pushConsoleInfo('Done.')
dataobjects.load(output, os.path.basename(output))
16 changes: 12 additions & 4 deletions scripts/qgis_fmask_sentinel2makeAnglesImage.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
# Definition of inputs and outputs
# ==================================
#Definition of inputs and outputs
#==================================
##FMask=group
##Sentinel 2 Make Angles Image=name
##ParameterFile|infile|Input sentinel-2 tile metafile|False|False|xml
##OutputFile|outfile|Output angles image file|tif

from argparse import Namespace
import sys
import os.path
import numpy as np

# here = os.path.dirname(scriptDescriptionFile)
j08lue marked this conversation as resolved.
Show resolved Hide resolved
# if here not in sys.path:
# sys.path.append(here)

from qgis_fmask.interfaces.fmask_sentinel2makeAnglesImage import mainRoutine

cmdargs = Namespace(infile=infile, outfile=outfile)
cmdargs = Namespace(
infile=infile,
outfile=outfile)

with np.errstate(invalid="ignore"):
with np.errstate(invalid='ignore'):
mainRoutine(cmdargs)
17 changes: 13 additions & 4 deletions scripts/qgis_fmask_usgsLandsatMakeAnglesImage.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
# Definition of inputs and outputs
# ==================================
#Definition of inputs and outputs
#==================================
##FMask=group
##Landsat Make Angles Image=name
##ParameterFile|mtl|MTL file|False|False|txt
##ParameterFile|templateimg|Image file name to use as template for output angles image|False|False|TIF
##OutputFile|outfile|Output angles image file|tif

from argparse import Namespace
import sys
import os.path
import numpy as np

here = os.path.dirname(scriptDescriptionFile)
if here not in sys.path:
sys.path.append(here)

from qgis_fmask.interfaces.fmask_usgsLandsatMakeAnglesImage import mainRoutine

cmdargs = Namespace(mtl=mtl, templateimg=templateimg, outfile=outfile)
cmdargs = Namespace(
mtl=mtl,
templateimg=templateimg,
outfile=outfile)

with np.errstate(invalid="ignore"):
with np.errstate(invalid='ignore'):
mainRoutine(cmdargs)
17 changes: 13 additions & 4 deletions scripts/qgis_fmask_usgsLandsatSaturationMask.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Definition of inputs and outputs
# ==================================
#Definition of inputs and outputs
#==================================
##FMask=group
##Landsat Saturation Mask=name
##ParameterFile|infile|Input raw DN radiance image|False|False
Expand All @@ -8,11 +8,20 @@
##OutputFile|outfile|Output angles image file|tif

from argparse import Namespace
import sys
import os.path
import numpy as np

here = os.path.dirname(scriptDescriptionFile)
if here not in sys.path:
sys.path.append(here)

from qgis_fmask.interfaces.fmask_usgsLandsatSaturationMask import mainRoutine

cmdargs = Namespace(infile=infile, mtl=mtl, outfile=outfile)
cmdargs = Namespace(
infile=infile,
mtl=mtl,
outfile=outfile)

with np.errstate(invalid="ignore"):
with np.errstate(invalid='ignore'):
mainRoutine(cmdargs)
Loading