Coverage for geoarray/masks.py: 96%
48 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-12-14 11:57 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-12-14 11:57 +0000
1# -*- coding: utf-8 -*-
3# geoarray, A fast Python interface for image geodata - either on disk or in memory.
4#
5# Copyright (C) 2017-2023
6# - Daniel Scheffler (GFZ Potsdam, daniel.scheffler@gfz-potsdam.de)
7# - Helmholtz Centre Potsdam - GFZ German Research Centre for Geosciences Potsdam,
8# Germany (https://www.gfz-potsdam.de/)
9#
10# This software was developed within the context of the GeoMultiSens project funded
11# by the German Federal Ministry of Education and Research
12# (project grant code: 01 IS 14 010 A-C).
13#
14# Licensed under the Apache License, Version 2.0 (the "License");
15# you may not use this file except in compliance with the License.
16# You may obtain a copy of the License at
17#
18# http://www.apache.org/licenses/LICENSE-2.0
19#
20# Unless required by applicable law or agreed to in writing, software
21# distributed under the License is distributed on an "AS IS" BASIS,
22# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23# See the License for the specific language governing permissions and
24# limitations under the License.
26from typing import Optional, Union
27import numpy as np
29# internal imports
30from .baseclasses import GeoArray
32__author__ = 'Daniel Scheffler'
35class _Mask(GeoArray):
36 _CLASSNAME = 'Mask baseclass'
38 def _validate_array_values(self, array: np.ndarray) -> None:
39 if not array.dtype == bool:
40 if np.issubdtype(array.dtype, np.integer):
41 if np.min(array) < 0 or np.max(array) > 1:
42 pixelvals = sorted(list(np.unique(array)))
43 assert len(pixelvals) <= 2, 'The %s must have only two pixel values (boolean) - 0 and 1 or ' \
44 'False and True! The given mask for %s contains the values %s.' \
45 % (self._CLASSNAME, self.basename, pixelvals)
46 assert pixelvals in [[0, 1], [0], [1], [False, True], [False], [True]], \
47 'Found unsupported pixel values in the given %s for %s: %s. ' \
48 'Only the values True, False, 0 and 1 are supported. ' \
49 % (self._CLASSNAME, self.basename, pixelvals)
50 else:
51 raise TypeError('Boolean or integer array expected.')
54class BadDataMask(_Mask):
55 _CLASSNAME = 'bad data mask'
57 def __init__(self,
58 path_or_array: Union[str, np.ndarray, GeoArray],
59 geotransform: tuple = None,
60 projection: str = None,
61 bandnames: list = None,
62 nodata: Union[float, int] = False,
63 progress: bool = True,
64 q: bool = False
65 ) -> None:
66 super(BadDataMask, self).__init__(path_or_array, geotransform=geotransform, projection=projection,
67 bandnames=bandnames, nodata=nodata, progress=progress, q=q)
69 if self.is_inmem:
70 # validate input data - before converting to bool
71 self._validate_array_values(self.arr)
72 self.arr = self.arr.astype(bool)
74 # del self._mask_baddata, self.mask_baddata # TODO delete property (requires deleter)
76 @property
77 def arr(self) -> Optional[np.ndarray]:
78 return self._arr
80 @arr.setter
81 def arr(self, ndarray: np.ndarray) -> None:
82 assert isinstance(ndarray, np.ndarray), "'arr' can only be set to a numpy array!"
83 self._validate_array_values(ndarray)
84 self._arr = ndarray.astype(bool)
87class NoDataMask(_Mask):
88 _CLASSNAME = 'no data mask'
90 def __init__(self,
91 path_or_array: Union[str, np.ndarray, GeoArray],
92 geotransform: tuple = None,
93 projection: str = None,
94 bandnames: list = None,
95 nodata: Union[float, int] = False,
96 progress: bool = True,
97 q: bool = False
98 ) -> None:
99 super(NoDataMask, self).__init__(path_or_array, geotransform=geotransform, projection=projection,
100 bandnames=bandnames, nodata=nodata, progress=progress, q=q)
102 if self.is_inmem:
103 # validate input data - before converting to bool
104 self._validate_array_values(self.arr)
105 self.arr = self.arr.astype(bool)
107 # del self._mask_nodata, self.mask_nodata # TODO delete property (requires deleter)
108 # TODO disk-mode: init must check the numbers of bands, and ideally also the pixel values in mask
110 @property
111 def arr(self) -> Optional[np.ndarray]:
112 return self._arr
114 @arr.setter
115 def arr(self, ndarray: np.ndarray) -> None:
116 assert isinstance(ndarray, np.ndarray), "'arr' can only be set to a numpy array!"
117 self._validate_array_values(ndarray)
118 self._arr = ndarray.astype(bool)
121class CloudMask(_Mask):
122 _CLASSNAME = 'cloud mask'
124 def __init__(self,
125 path_or_array: Union[str, np.ndarray, GeoArray],
126 geotransform: tuple = None,
127 projection: str = None,
128 bandnames: list = None,
129 nodata: Union[float, int] = False,
130 progress: bool = True,
131 q: bool = False
132 ) -> None:
133 # TODO implement class definitions and specific metadata
135 super(CloudMask, self).__init__(path_or_array, geotransform=geotransform, projection=projection,
136 bandnames=bandnames, nodata=nodata, progress=progress, q=q)
138 # del self._mask_nodata, self.mask_nodata # TODO delete property (requires deleter)
139 # TODO check that: "Automatically detected nodata value for CloudMask 'IN_MEM': 1.0"
141 def to_ENVI_classification(self) -> None: # pragma: no cover
142 raise NotImplementedError # TODO