Source code for iota2.configuration_files.sections.classif_section

# !/usr/bin/env python3

# =========================================================================
#   Program:   iota2
#
#   Copyright (c) CESBIO. All rights reserved.
#
#   See LICENSE for details.
#
#   This software is distributed WITHOUT ANY WARRANTY; without even
#   the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
#   PURPOSE.  See the above copyright notices for more information.
#
# =========================================================================
"""
Definitions of the parameters corresponding to the classification section of the configuration file
"""
from typing import ClassVar, Literal

from pydantic import Field, root_validator

from iota2.configuration_files.sections.cfg_utils import ConfigError, Iota2ParamSection


[docs]class ClassifSection(Iota2ParamSection): """Definition of the parameters that belong to the 'arg_classification' section.""" section_name: ClassVar[str] = "arg_classification" merge_final_classifications: bool = Field( False, doc_type="bool", short_desc=( "Enable the fusion of " "classifications mode, merging all " "run in a unique result." ), available_on_builders=["I2Classification"], ) merge_final_classifications_method: Literal[ "majorityvoting", "dempstershafer" ] = Field( "majorityvoting", doc_type="str", short_desc=( "Indicate the fusion of classification method:" " 'majorityvoting' or 'dempstershafer.'" ), available_on_builders=["I2Classification"], ) merge_final_classifications_indecidedlabel: int = Field( 255, doc_type="int", short_desc="Indicate the label for indecision case during fusion.", available_on_builders=["I2Classification"], ) fusionofclassification_all_samples_validation: bool = Field( False, doc_type="bool", short_desc=( "Enable the use of all reference data " "to validate the classification merge." ), long_desc=( """ If the fusion mode is enabled, enable the use of all reference data samples for validation. """ ), available_on_builders=["I2Classification"], ) dempstershafer_mob: Literal["precision", "recall", "accuracy", "kappa"] = Field( "precision", doc_type="str", short_desc="Choose the dempster shafer mass of belief estimation method.", long_desc=( """Two kind of indexes can be used:\n * Global: `accuracy` or `kappa`.\n * Per class: `precision` or `recall`.\n """ ), available_on_builders=["I2Classification"], ) merge_final_classifications_ratio: float = Field( 0.1, doc_type="float", short_desc=( "Percentage of samples to use in order to evaluate the fusion raster." ), available_on_builders=["I2Classification"], ) keep_runs_results: bool = Field( True, doc_type="bool", short_desc=( "If in fusion mode, two final reports can be provided. " "One for each seed, and one for the classification fusion." ), long_desc=( """ If in fusion mode, two final reports can be provided. One for each seed, and one for the classification fusion. """ ), available_on_builders=["I2Classification"], ) no_label_management: str = Field( "maxConfidence", doc_type="str", short_desc="Method for choosing a label in case of fusion.", available_on_builders=["I2Classification"], ) enable_probability_map: bool = Field( False, doc_type="bool", short_desc="Produce the probability map.", long_desc=( """ A probability map is a image with N bands , where N is the number of classes in the nomenclature file. The bands are sorted in ascending order, more information :doc:`here <probability_maps>`. """ ), available_on_builders=["I2Classification"], ) fusion_options: str = Field( " -nodatalabel 0 -method majorityvoting", doc_type="str", short_desc=( "OTB FusionOfClassification options for voting method involved if classif_mode " "is set to 'fusion'." ), available_on_builders=["I2Classification"], ) classif_mode: str = Field( "separate", doc_type="str", short_desc="'separate' or 'fusion'", long_desc=( """ If 'fusion' : too huge models will be divided into smaller ones and will classify the same pixels. The threshold between small/big models is defined by the parameter 'mode_outside_regionsplit'. """ ), available_on_builders=["I2Classification"], ) enable_boundary_fusion: bool = Field( False, doc_type="bool", short_desc="Enable the boundary fusion.", long_desc="If enabled probabilities are used to fuse maps between regions.", available_on_builders=["I2Classification"], ) boundary_exterior_buffer_size: int = Field( 0, doc_type="int", short_desc="Buffer size outside the region.", long_desc=( """ This value can be different from the interior buffer. The unit is in meters. The value is divided by the resolution to estimate the distance in pixels. """ ), available_on_builders=["I2Classification"], ) boundary_interior_buffer_size: int = Field( 0, doc_type="int", short_desc="Buffer size inside the region", long_desc=( """ This value can be different from the exterior buffer. The unit is in meters. The value is divided by the resolution to estimate the distance in pixels. """ ), available_on_builders=["I2Classification"], ) boundary_fusion_epsilon: float = Field( 0.0, doc_type="float", short_desc="Threshold to avoid weights equals to zero", long_desc=( """ If the region shape contains the buffer, operations are not bijective. In this condition, several weights can be set to 0. This lead to 0 area in the final map (holes). The weights maps are stored as uint16. The threshold should be higher enough to be different to zero, once multiplied by 1000. """ ), available_on_builders=["I2Classification"], ) boundary_comparison_mode: bool = Field( False, doc_type="bool", short_desc="Enable classification comparison", long_desc=( """ If enabled, it will produce two maps. The boundary regions will be analysed to measure the method improvements. """ ), available_on_builders=["I2Classification"], ) generate_final_probability_map: bool = Field( False, doc_type="bool", short_desc="Enable the mosaicing of probabilities maps.", long_desc=( """ This operation can produce heavy maps. If you don't need it over the whole area in one image, disable this option. """ ), available_on_builders=["I2Classification"], ) @root_validator(skip_on_failure=True) @classmethod def ensure_proba_comp(cls, values: dict) -> dict: """Check if all parameters is enabled for boundary fusion.""" enable_proba = values["enable_probability_map"] enable_boundary_fusion = values["enable_boundary_fusion"] enable_comp = values["boundary_comparison_mode"] params = [enable_proba, enable_boundary_fusion, enable_comp] if enable_comp: if not all(params): raise ConfigError( "The comparison mode is enabled. " "The following parameters must be all True. " "But the following was detected: " f'"enable_probability_map" : {enable_proba}, ' f'"enable_boundary_fusion":{enable_boundary_fusion}' ) if enable_boundary_fusion: if not enable_proba: raise ConfigError( "The boundary fusion mode is enabled. " "Probability maps are required but " f"'enable_probability_map' is {enable_proba}." ) if enable_boundary_fusion: int_buff = values["boundary_interior_buffer_size"] if int_buff < 0: raise ConfigError( "boundary_interior_buffer_size must" f" be higher than 0 < {int_buff}" ) ext_buff = values["boundary_exterior_buffer_size"] if ext_buff < 0: raise ConfigError( "boundary_exterior_buffer_size must" f" be higher than 0 < {ext_buff}." ) eps = values["boundary_fusion_epsilon"] if eps < 0.001 or eps > 0.999: raise ConfigError( f"boundary_fusion_epsilon must be between 0.001 < {eps} < 0.999." ) return values