geowatch.tasks.fusion.datamodules.qa_bands module

Describe how to interpret QA bands.

References

https://smart-research.slack.com/?redir=%2Ffiles%2FU028UQGN1N0%2FF04B998ANRL%2Faccenture_ta1_productdoc_phaseii_20211117.pptx%3Forigin_team%3DTN3QR7WAH%26origin_channel%3DC03QTAXU7GF

class geowatch.tasks.fusion.datamodules.qa_bands.QA_SpecMixin[source]

Bases: object

draw_labels(quality_im, legend='separate', legend_dpi=96, verbose=0)[source]

The doctest can be used to debug cloudmasks for the datasets

class geowatch.tasks.fusion.datamodules.qa_bands.QA_BitSpecTable(spec)[source]

Bases: QA_SpecMixin

Bit tables are more efficient because we can reduce over the query input

Example

>>> from geowatch.tasks.fusion.datamodules import qa_bands
>>> import kwimage
>>> # Lookup a table for this spec
>>> self = qa_bands.QA_SPECS.find_table('ACC-1', 'S2')
>>> assert isinstance(self, qa_bands.QA_BitSpecTable)
>>> # Make a quality image with every value
>>> pure_patches = [np.zeros((32, 32), dtype=np.int16) + val for val in self.name_to_value.values()]
>>> # Also add in a few mixed patches
>>> mixed_patches = [
>>>     pure_patches[0] | pure_patches[1],
>>>     pure_patches[4] | pure_patches[1],
>>>     pure_patches[3] | pure_patches[5],
>>>     pure_patches[0] | pure_patches[4],
>>>     pure_patches[3] | pure_patches[4],
>>> ]
>>> patches = pure_patches + mixed_patches
>>> quality_im = kwimage.stack_images_grid(patches)
>>> # The mask_any method makes a mask where any of the semantically given labels will be masked
>>> query_names = ['cloud']
>>> is_iffy = self.mask_any(quality_im, ['cloud', 'cirrus'])
>>> drawings = self.draw_labels(quality_im)  # visualize
>>> # xdoctest: +REQUIRES(--show)
>>> import kwplot
>>> plt = kwplot.autoplt()
>>> qa_canvas = drawings['qa_canvas']
>>> legend = drawings['legend']
>>> kwplot.imshow(is_iffy, pnum=(1, 3, 1), title=f'mask matching {query_names}')
>>> kwplot.imshow(qa_canvas, pnum=(1, 3, 2), title='qa bits')
>>> kwplot.imshow(legend, pnum=(1, 3, 3), title='qa bit legend')
>>> kwplot.set_figtitle(f"QA Spec: name={self.spec['qa_spec_name']} sensor={self.spec['sensor']}")

Example

>>> from geowatch.tasks.fusion.datamodules import qa_bands
>>> import kwimage
>>> # Lookup a table for this spec
>>> self = qa_bands.QA_SPECS.find_table('qa_pixel', 'L8')
>>> assert isinstance(self, qa_bands.QA_BitSpecTable)
>>> # Make a quality image with every value
>>> pure_patches = [np.zeros((32, 32), dtype=np.int16) + val for val in self.name_to_value.values()]
>>> # Also add in a few mixed patches
>>> mixed_patches = [
>>>     pure_patches[0] | pure_patches[1],
>>>     pure_patches[2] | pure_patches[1],
>>> ]
>>> patches = pure_patches + mixed_patches
>>> quality_im = kwimage.stack_images_grid(patches)
>>> # The mask_any method makes a mask where any of the semantically given labels will be masked
>>> query_names = ['cloud']
>>> is_iffy = self.mask_any(quality_im, ['cloud'])
>>> drawings = self.draw_labels(quality_im)  # visualize
>>> # xdoctest: +REQUIRES(--show)
>>> import kwplot
>>> plt = kwplot.autoplt()
>>> qa_canvas = drawings['qa_canvas']
>>> legend = drawings['legend']
>>> kwplot.imshow(is_iffy, pnum=(1, 3, 1), title=f'mask matching {query_names}')
>>> kwplot.imshow(qa_canvas, pnum=(1, 3, 2), title='qa bits')
>>> kwplot.imshow(legend, pnum=(1, 3, 3), title='qa bit legend')
>>> kwplot.set_figtitle(f"QA Spec: name={self.spec['qa_spec_name']} sensor={self.spec['sensor']}")
mask_any(quality_im, qa_names)[source]
describe_values(unique_qavals)[source]

Get a human readable description of each value for a legend

geowatch.tasks.fusion.datamodules.qa_bands.unpack_bit_positions(val, itemsize=None)[source]

Given an integer value, return the positions of the on bits.

Parameters:
  • val (int) – a signed or unsigned integer

  • itemsize (int | None) – Number of bytes used to represent the integer. E.g. 1 for a uint8 4 for an int32. If unspecified infer the smallest number of bytes needed, but warning this may produce ambiguous results for negative numbers.

Returns:

the indexes of the 1 bits.

Return type:

List[int]

Note

This turns out to be faster than a numpy or lookuptable strategy I tried. See github.com:Erotemic/misc/learn/bit_conversion.py

Example

>>> unpack_bit_positions(0)
[]
>>> unpack_bit_positions(1)
[0]
>>> unpack_bit_positions(-1)
[0, 1, 2, 3, 4, 5, 6, 7]
>>> unpack_bit_positions(-1, itemsize=2)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
>>> unpack_bit_positions(9)
[0, 3]
>>> unpack_bit_positions(2132)
[2, 4, 6, 11]
>>> unpack_bit_positions(-9999)
[0, 4, 5, 6, 7, 11, 12, 14, 15]
>>> unpack_bit_positions(np.int16(-9999))
[0, 4, 5, 6, 7, 11, 12, 14, 15]
>>> unpack_bit_positions(np.int16(-1))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
class geowatch.tasks.fusion.datamodules.qa_bands.QA_ValueSpecTable(spec)[source]

Bases: QA_SpecMixin

Value tables are less efficient

mask_any(quality_im, qa_names)[source]
describe_values(unique_qavals)[source]

Get a human readable description of each value for a legend

class geowatch.tasks.fusion.datamodules.qa_bands.QA_SpecRegistry(iterable=(), /)[source]

Bases: list

query_table(spec_name='*', sensor='*')[source]
find_table(spec_name='*', sensor='*')[source]
geowatch.tasks.fusion.datamodules.qa_bands.demo()[source]

Small script to viz qa bands.