def test_isinstance_validator():
    """ Test the isinstance_validator """
    validator = isinstance_validator(str)
    assert str(validator) == "Value must be of type str"
    assert validator("foo")
    assert not validator([])
    assert not validator({})
    assert not validator(1)
    assert not validator(2.0)

    validator = isinstance_validator(int)
    assert str(validator) == "Value must be of type int"
    assert validator(1)
    assert not validator("foo")
    assert not validator(1.0)
    assert not validator([])
    assert not validator({})

    validator = isinstance_validator(BaseImageContainer)
    assert str(validator) == "Value must be of type BaseImageContainer"
    image_container = NumpyImageContainer(
        image=np.array([[-0.5, 0.2], [0.1, -0.9]]))
    assert validator(image_container)
    assert not validator("foo")
    assert not validator(1)
    assert not validator([])

    validator = isinstance_validator((float, int))
    assert str(validator) == "Value must be of type float or int"
    assert validator(1.0)
    assert validator(2)
    assert not validator([1])
    assert not validator([1, 2])
    assert not validator("foo")
    assert not validator(["foo", "bar"])
    def _validate_inputs(self):
        """Checks that the inputs meet their validation criteria

        `'image'` must be derived from a BaseImageContainer
        `'affine'` must be a numpy.ndarray of shape (4,4)
        `'shape'` must be a Tuple of integers of length 3

        """
        input_validator = ParameterValidator(
            parameters={
                self.KEY_IMAGE:
                Parameter(
                    validators=[isinstance_validator(BaseImageContainer)]),
                self.KEY_AFFINE:
                Parameter(validators=[isinstance_validator(np.ndarray)]),
                self.KEY_SHAPE:
                Parameter(validators=[
                    isinstance_validator(tuple),
                    for_each_validator(isinstance_validator(int)),
                ]),
            })
        input_validator.validate(self.inputs,
                                 error_type=FilterInputValidationError)

        # Further validation that can't be handled bby the parameter validator
        # check that ResampleFilter.KEY_AFFINE is of size 4x4
        if self.inputs[self.KEY_AFFINE].shape != (4, 4):
            raise FilterInputValidationError

        # Check that the tuple ResampleFilter.KEY_SHAPE has length 3
        if len(self.inputs[self.KEY_SHAPE]) != 3:
            raise FilterInputValidationError
    def _validate_inputs(self):
        """Checks that the inputs meet their validation criteria
        'image' must be derived from BaseImageContainer
        'metadata' must be a dict
        """

        input_validator = ParameterValidator(
            parameters={
                self.KEY_IMAGE:
                Parameter(validators=isinstance_validator(BaseImageContainer)),
                self.KEY_METADATA:
                Parameter(validators=isinstance_validator(dict)),
            })

        input_validator.validate(self.inputs,
                                 error_type=FilterInputValidationError)
 def _validate_inputs(self):
     """Validate the inputs.
     'image' must be derived from BaseImageContainer
     'scale' (optional) must be a float or integer
     'offset' (optional) must be a float or integer
     """
     input_validator = ParameterValidator(
         parameters={
             self.KEY_IMAGE:
             Parameter(validators=[
                 isinstance_validator(BaseImageContainer),
             ]),
             self.KEY_SCALE:
             Parameter(validators=[isinstance_validator((int, float))],
                       optional=True),
             self.KEY_OFFSET:
             Parameter(validators=[isinstance_validator((int, float))],
                       optional=True),
         })
     input_validator.validate(self.inputs,
                              error_type=FilterInputValidationError)
    def _validate_inputs(self):
        """
        'image' must be derived from BaseImageContainer
        'snr' must be a positive float
        'reference_image' if present must be derived from BaseImageContainer.
        image.shape and reference_image.shape must be equal
        """
        input_validator = ParameterValidator(
            parameters={
                self.KEY_IMAGE:
                Parameter(validators=isinstance_validator(BaseImageContainer)),
                self.KEY_SNR:
                Parameter(validators=[
                    isinstance_validator(float),
                    greater_than_equal_to_validator(0),
                ]),
                self.KEY_REF_IMAGE:
                Parameter(validators=isinstance_validator(BaseImageContainer),
                          optional=True),
            })

        input_validator.validate(self.inputs,
                                 error_type=FilterInputValidationError)

        # If 'reference_image' is supplied, check that its dimensions match 'image'
        if self.KEY_REF_IMAGE in self.inputs:
            input_reference_image = self.inputs[self.KEY_REF_IMAGE]
            input_image = self.inputs[self.KEY_IMAGE]
            if not isinstance(input_reference_image, BaseImageContainer):
                raise FilterInputValidationError(
                    f"Input 'reference_image' is not a BaseImageContainer"
                    f"(is {type(input_reference_image)})")
            if not input_image.shape == input_reference_image.shape:
                raise FilterInputValidationError(
                    f"Shape of inputs 'image' and 'reference_image' are not equal"
                    f"Shape of 'image' is {input_image.shape}"
                    f"Shape of 'reference_image' is {input_reference_image.shape}"
                )
 def _validate_inputs(self):
     """
     'image' must be derived from BaseImageContainer.
     'snr' must be a float and >= 0
     'reference_image' if present must be derived from BaseImageContainer
     """
     input_validator = ParameterValidator(
         parameters={
             self.KEY_IMAGE: Parameter(
                 validators=isinstance_validator(BaseImageContainer)
             ),
             self.KEY_SNR: Parameter(
                 validators=[
                     isinstance_validator(float),
                     greater_than_equal_to_validator(0),
                 ]
             ),
             self.KEY_REF_IMAGE: Parameter(
                 validators=isinstance_validator(BaseImageContainer), optional=True
             ),
         }
     )
     input_validator.validate(self.inputs, error_type=FilterInputValidationError)
    def _validate_inputs(self):
        """Validate the inputs.
        'image' must be derived from BaseImageContainer and have
        an  ``image_type`` attribute that is not equal to 'PHASE_IMAGE_TYPE'.
        """
        input_validator = ParameterValidator(
            parameters={
                self.KEY_IMAGE: Parameter(
                    validators=[isinstance_validator(BaseImageContainer),]
                )
            }
        )
        input_validator.validate(self.inputs, error_type=FilterInputValidationError)

        # raise an error if the input image is a phase image.
        if self.inputs[self.KEY_IMAGE].image_type == PHASE_IMAGE_TYPE:
            raise FilterInputValidationError(
                "input 'image' has attribute 'image_type' with value 'PHASE_IMAGE_TYPE', this is"
                "not supported"
            )
Beispiel #8
0
 def _validate_inputs(self):
     """
     Checks that the inputs meet their validation criteria
     Note that values are only checked if they are present and the correct
     type, as more rigorous checking is performed in each corresponding filter.
     't1': BaseImageContainer
     't2': BaseImageContainer
     't2_star': BaseImageContainer
     'm0': BaseImageContainer
     'mag_enc': BaseImageContainer, optional
     'acq_contrast': str
     'echo_time': float
     'repetition_time': float
     'excitation_flip_angle': float, optional
     'inversion_flip_angle': float, optional
     'inversion_time': float, optional
     'image_flavour': str, optional
     'target_shape': Tuple[int, int, int], optional
     'rotation': Tuple[float, float, float], optional
     'rotation_origin': Tuple[float, float, float], optional
     'translation': Tuple[float, float, float], optional
     'reference_image': BaseImageContainer, optional
     'snr': float
     """
     input_validator = ParameterValidator(
         parameters={
             self.KEY_M0: Parameter(
                 validators=[
                     isinstance_validator(BaseImageContainer),
                 ]
             ),
             self.KEY_T1: Parameter(
                 validators=[
                     isinstance_validator(BaseImageContainer),
                 ]
             ),
             self.KEY_T2: Parameter(
                 validators=[
                     isinstance_validator(BaseImageContainer),
                 ]
             ),
             self.KEY_T2_STAR: Parameter(
                 validators=[
                     isinstance_validator(BaseImageContainer),
                 ],
             ),
             self.KEY_MAG_ENC: Parameter(
                 validators=[isinstance_validator(BaseImageContainer)], optional=True
             ),
             self.KEY_ACQ_CONTRAST: Parameter(
                 validators=[
                     isinstance_validator(str),
                 ]
             ),
             self.KEY_ECHO_TIME: Parameter(
                 validators=[
                     isinstance_validator(float),
                 ]
             ),
             self.KEY_REPETITION_TIME: Parameter(
                 validators=[
                     isinstance_validator(float),
                 ]
             ),
             self.KEY_EXCITATION_FLIP_ANGLE: Parameter(
                 validators=[
                     isinstance_validator(float),
                 ],
             ),
             self.KEY_INVERSION_FLIP_ANGLE: Parameter(
                 validators=[
                     isinstance_validator(float),
                 ],
                 optional=True,
             ),
             self.KEY_INVERSION_TIME: Parameter(
                 validators=[
                     isinstance_validator(float),
                 ],
                 optional=True,
             ),
             self.KEY_IMAGE_FLAVOUR: Parameter(
                 validators=[
                     isinstance_validator(str),
                 ],
                 optional=True,
             ),
             self.KEY_TARGET_SHAPE: Parameter(
                 validators=[
                     isinstance_validator(tuple),
                 ],
                 optional=True,
             ),
             self.KEY_ROTATION: Parameter(
                 validators=[
                     isinstance_validator(tuple),
                 ],
                 optional=True,
             ),
             self.KEY_ROTATION_ORIGIN: Parameter(
                 validators=[
                     isinstance_validator(tuple),
                 ],
                 optional=True,
             ),
             self.KEY_TRANSLATION: Parameter(
                 validators=[
                     isinstance_validator(tuple),
                 ],
                 optional=True,
             ),
             self.KEY_REF_IMAGE: Parameter(
                 validators=[isinstance_validator(BaseImageContainer)], optional=True
             ),
             self.KEY_SNR: Parameter(
                 validators=[
                     isinstance_validator(float),
                 ]
             ),
         }
     )
     input_validator.validate(self.inputs, error_type=FilterInputValidationError)
def test_isinstance_validator_creator():
    """ The the isinstance validator creation """
    isinstance_validator(int)  # ok
    isinstance_validator((int, float, str))  # ok
    with pytest.raises(TypeError):
        isinstance_validator(1)
    with pytest.raises(TypeError):
        isinstance_validator("foo")
    with pytest.raises(TypeError):
        isinstance_validator([])
    with pytest.raises(TypeError):
        isinstance_validator({})
    def _validate_inputs(self):
        """ Checks that the inputs meet their validation critera
        't1' must be derived from BaseImageContainer, >=0, and non-complex
        't2' must be derived from BaseImageContainer, >=0, and non-complex
        't2_star' must be derived from BaseImageContainer, >=0, and non-complex
            Only required if 'acq_contrast' == 'ge'
        'm0' must be derived from BaseImageContainer, >=0, and non-complex
        'mag_enc' (optional) must be derived from BaseImageContainer and non-complex
        'acq_contrast' must be a string and equal to "ge" or "se" (case insensitive)
        'echo_time' must be a float and >= 0
        'repetition_time' must be a float and >= 0
        'excitation_flip_angle' must be a float and >=0
        'inversion_flip_angle' must be a float and >=0
        'inversion_time' must be a float and >=0

        All images must have the same dimensions

        """
        input_validator = ParameterValidator(
            parameters={
                self.KEY_M0:
                Parameter(validators=[
                    isinstance_validator(BaseImageContainer),
                    greater_than_equal_to_validator(0),
                ]),
                self.KEY_T1:
                Parameter(validators=[
                    isinstance_validator(BaseImageContainer),
                    greater_than_equal_to_validator(0),
                ]),
                self.KEY_T2:
                Parameter(validators=[
                    isinstance_validator(BaseImageContainer),
                    greater_than_equal_to_validator(0),
                ]),
                self.KEY_T2_STAR:
                Parameter(
                    validators=[
                        isinstance_validator(BaseImageContainer),
                        greater_than_equal_to_validator(0),
                    ],
                    optional=True,
                ),
                self.KEY_MAG_ENC:
                Parameter(
                    validators=[isinstance_validator(BaseImageContainer)],
                    optional=True),
                self.KEY_ACQ_CONTRAST:
                Parameter(validators=[
                    isinstance_validator(str),
                    from_list_validator(
                        [self.CONTRAST_GE, self.CONTRAST_SE, self.CONTRAST_IR],
                        case_insensitive=True,
                    ),
                ]),
                self.KEY_ECHO_TIME:
                Parameter(validators=[
                    isinstance_validator(float),
                    greater_than_equal_to_validator(0),
                ]),
                self.KEY_REPETITION_TIME:
                Parameter(validators=[
                    isinstance_validator(float),
                    greater_than_equal_to_validator(0),
                ]),
                self.KEY_EXCITATION_FLIP_ANGLE:
                Parameter(
                    validators=[
                        isinstance_validator(float),
                    ],
                    optional=True,
                ),
                self.KEY_INVERSION_FLIP_ANGLE:
                Parameter(
                    validators=[
                        isinstance_validator(float),
                    ],
                    optional=True,
                ),
                self.KEY_INVERSION_TIME:
                Parameter(
                    validators=[
                        isinstance_validator(float),
                        greater_than_equal_to_validator(0),
                    ],
                    optional=True,
                ),
                self.KEY_IMAGE_FLAVOUR:
                Parameter(validators=[
                    isinstance_validator(str),
                ],
                          optional=True),
            })
        input_validator.validate(self.inputs,
                                 error_type=FilterInputValidationError)

        # Parameters that are conditionally required based on the value of "acq_contrast"
        # if the acquisition contrast is gradient echo ("ge")
        if self.inputs[self.KEY_ACQ_CONTRAST].lower() == self.CONTRAST_GE:
            # 't2_star' must be present in inputs
            if self.inputs.get(self.KEY_T2_STAR) is None:
                raise FilterInputValidationError(
                    "Acquisition contrast is ge, 't2_star' image required")
        # if the acquisition contrast is gradient echo ("ge") or inversion recovery ("ir")
        if self.inputs[self.KEY_ACQ_CONTRAST].lower() in (
                self.CONTRAST_GE,
                self.CONTRAST_IR,
        ):
            # 'excitation_flip_angle' must be present in inputs
            if self.inputs.get(self.KEY_EXCITATION_FLIP_ANGLE) is None:
                raise FilterInputValidationError(
                    f"Acquisition contrast is {self.inputs[self.KEY_ACQ_CONTRAST]},"
                    " 'excitation_flip_angle' required")

        # if the acquisition contrast is inversion recovery ("ir")
        if self.inputs[self.KEY_ACQ_CONTRAST].lower() == self.CONTRAST_IR:
            if self.inputs.get(self.KEY_INVERSION_FLIP_ANGLE) is None:
                raise FilterInputValidationError(
                    f"Acquisition contrast is {self.inputs[self.KEY_ACQ_CONTRAST]},"
                    " 'inversion_flip_angle' required")
            if self.inputs.get(self.KEY_INVERSION_TIME) is None:
                raise FilterInputValidationError(
                    f"Acquisition contrast is {self.inputs[self.KEY_ACQ_CONTRAST]},"
                    " 'inversion_time' required")
            if self.inputs.get(self.KEY_REPETITION_TIME) < (
                    self.inputs.get(self.KEY_ECHO_TIME) +
                    self.inputs.get(self.KEY_INVERSION_TIME)):
                raise FilterInputValidationError(
                    "repetition_time must be greater than echo_time + inversion_time"
                )

        # Check repetition_time is not < echo_time for ge and se
        if self.inputs.get(self.KEY_REPETITION_TIME) < self.inputs.get(
                self.KEY_ECHO_TIME):
            raise FilterInputValidationError(
                "repetition_time must be greater than echo_time")

        # Check that all the input images are all the same dimensions
        input_keys = self.inputs.keys()
        keys_of_images = [
            key for key in input_keys
            if isinstance(self.inputs[key], BaseImageContainer)
        ]

        list_of_image_shapes = [
            self.inputs[key].shape for key in keys_of_images
        ]
        if list_of_image_shapes.count(
                list_of_image_shapes[0]) != len(list_of_image_shapes):
            raise FilterInputValidationError([
                "Input image shapes do not match.",
                [
                    f"{keys_of_images[i]}: {list_of_image_shapes[i]}, "
                    for i in range(len(list_of_image_shapes))
                ],
            ])

        # Check that all the input images are not of image_type == "COMPLEX_IMAGE_TYPE"
        for key in keys_of_images:
            if self.inputs[key].image_type == COMPLEX_IMAGE_TYPE:
                raise FilterInputValidationError(
                    f"{key} has image type {COMPLEX_IMAGE_TYPE}, this is not supported"
                )
Beispiel #11
0
    def _validate_inputs(self):
        """ Checks that the inputs meet their validation critera
        'image' must be a derived from BaseImageContainer
        'output_directory' must be a string and a path
        'filename_prefix' must be a string and is optional

        Also checks the input image's metadata
        """

        input_validator = ParameterValidator(
            parameters={
                self.KEY_IMAGE:
                Parameter(validators=isinstance_validator(BaseImageContainer)),
                self.KEY_OUTPUT_DIRECTORY:
                Parameter(validators=isinstance_validator(str)),
                self.KEY_FILENAME_PREFIX:
                Parameter(
                    validators=isinstance_validator(str),
                    optional=True,
                    default_value="",
                ),
            })
        # validate the inputs
        new_params = input_validator.validate(
            self.inputs, error_type=FilterInputValidationError)

        metdata_validator = ParameterValidator(
            parameters={
                self.SERIES_TYPE:
                Parameter(
                    validators=from_list_validator(SUPPORTED_IMAGE_TYPES)),
                MODALITY:
                Parameter(validators=isinstance_validator(str), optional=True),
                self.SERIES_NUMBER:
                Parameter(validators=[
                    isinstance_validator(int),
                    greater_than_equal_to_validator(0),
                ]),
                ASL_CONTEXT:
                Parameter(
                    validators=isinstance_validator((str, list)),
                    optional=True,
                ),
                GkmFilter.KEY_LABEL_TYPE:
                Parameter(
                    validators=isinstance_validator(str),
                    optional=True,
                ),
                GkmFilter.KEY_LABEL_DURATION:
                Parameter(validators=isinstance_validator(float),
                          optional=True),
                GkmFilter.KEY_POST_LABEL_DELAY:
                Parameter(validators=isinstance_validator(float),
                          optional=True),
                GkmFilter.KEY_LABEL_EFFICIENCY:
                Parameter(validators=isinstance_validator(float),
                          optional=True),
                GroundTruthLoaderFilter.KEY_QUANTITY:
                Parameter(
                    validators=isinstance_validator(str),
                    optional=True,
                ),
                GroundTruthLoaderFilter.KEY_UNITS:
                Parameter(
                    validators=isinstance_validator(str),
                    optional=True,
                ),
                "image_flavour":
                Parameter(
                    validators=isinstance_validator(str),
                    optional=True,
                ),
            })
        # validate the metadata
        metadata = self.inputs[self.KEY_IMAGE].metadata
        metdata_validator.validate(metadata,
                                   error_type=FilterInputValidationError)

        # Specific validation for series_type == "structural"
        if metadata[self.SERIES_TYPE] == STRUCTURAL:
            if metadata.get(MODALITY) is None:
                raise FilterInputValidationError(
                    "metadata field 'modality' is required when `series_type` is 'structural'"
                )

        # specific validation when series_type is "ground_truth"
        if metadata[self.SERIES_TYPE] == GROUND_TRUTH:
            if metadata.get(GroundTruthLoaderFilter.KEY_QUANTITY) is None:
                raise FilterInputValidationError(
                    "metadata field 'quantity' is required when `series_type` is 'ground_truth'"
                )
        if metadata[self.SERIES_TYPE] == GROUND_TRUTH:
            if metadata.get(GroundTruthLoaderFilter.KEY_UNITS) is None:
                raise FilterInputValidationError(
                    "metadata field 'units' is required when `series_type` is 'ground_truth'"
                )

        # Specific validation for series_type == "asl"
        if metadata[self.SERIES_TYPE] == ASL:
            # asl_context needs some further validating
            asl_context = metadata.get(ASL_CONTEXT)
            if asl_context is None:
                raise FilterInputValidationError(
                    "metadata field 'asl_context' is required when `series_type` is 'asl'"
                )
            if isinstance(asl_context, str):
                asl_context_validator = ParameterValidator(
                    parameters={
                        ASL_CONTEXT:
                        Parameter(validators=from_list_validator(
                            SUPPORTED_ASL_CONTEXTS), ),
                    })

            elif isinstance(asl_context, list):
                asl_context_validator = ParameterValidator(
                    parameters={
                        ASL_CONTEXT:
                        Parameter(validators=for_each_validator(
                            from_list_validator(SUPPORTED_ASL_CONTEXTS)), ),
                    })
            asl_context_validator.validate(
                {"asl_context": asl_context},
                error_type=FilterInputValidationError)

            # determine the modality_label based on asl_context
            modality_label = self.determine_asl_modality_label(asl_context)

            if modality_label == ASL:
                # do some checking for when the `modality` is 'asl'
                if metadata.get(GkmFilter.KEY_LABEL_TYPE) is None:
                    raise FilterInputValidationError(
                        "metadata field 'label_type' is required for 'series_type'"
                        + " and 'modality' is 'asl'")
                if metadata.get(GkmFilter.KEY_LABEL_DURATION) is None:
                    raise FilterInputValidationError(
                        "metadata field 'label_duration' is required for 'series_type'"
                        + " and 'modality' is 'asl'")
                if metadata.get(GkmFilter.KEY_POST_LABEL_DELAY) is None:
                    raise FilterInputValidationError(
                        "metadata field 'post_label_delay' is required for 'series_type'"
                        + " and 'modality' is 'asl'")
                if metadata.get("image_flavour") is None:
                    raise FilterInputValidationError(
                        "metadata field 'image_flavour' is required for 'series_type'"
                        + " and 'modality' is 'asl'")

        # Check that self.inputs[self.KEY_OUTPUT_DIRECTORY] is a valid path.
        if not os.path.exists(self.inputs[self.KEY_OUTPUT_DIRECTORY]):
            raise FilterInputValidationError(
                f"'output_directory' {self.inputs[self.KEY_OUTPUT_DIRECTORY]} does not exist"
            )

        # merge the updated parameters from the output with the input parameters
        self.inputs = {**self._i, **new_params}
Beispiel #12
0
    def _validate_inputs(self):
        """ Checks that the inputs meet their validation criteria

        `'rotation'` (optional) must be a Tuple of floats of length 3, each value -180 to 180
        inclusive,default (optional) = (0.0, 0.0, 0.0)
        `'rotation_origin'` (optional) must be a Tuple of floats of length 3,
        default = (0.0, 0.0, 0.0)
        `'translation'` (optional) must be a Tuple of floats of length 3, default = (0.0, 0.0, 0.0)
        `'scale'` (optional) must be a Tuple of floats of length 3, default = (1.0, 1.0, 1.0)
        `'affine'` (optional) must be a numpy.ndarray of shape (4,4), default = numpy.eye(4)
        """

        input_validator = ParameterValidator(
            parameters={
                self.KEY_ROTATION:
                Parameter(
                    validators=[
                        isinstance_validator(tuple),
                        for_each_validator(isinstance_validator(float)),
                        for_each_validator(range_inclusive_validator(
                            -180, 180)),
                    ],
                    optional=True,
                    default_value=(0.0, 0.0, 0.0),
                ),
                self.KEY_ROTATION_ORIGIN:
                Parameter(
                    validators=[
                        isinstance_validator(tuple),
                        for_each_validator(isinstance_validator(float)),
                    ],
                    optional=True,
                    default_value=(0.0, 0.0, 0.0),
                ),
                self.KEY_TRANSLATION:
                Parameter(
                    validators=[
                        isinstance_validator(tuple),
                        for_each_validator(isinstance_validator(float)),
                    ],
                    optional=True,
                    default_value=(0.0, 0.0, 0.0),
                ),
                self.KEY_SCALE:
                Parameter(
                    validators=[
                        isinstance_validator(tuple),
                        for_each_validator(isinstance_validator(float)),
                    ],
                    optional=True,
                    default_value=(1.0, 1.0, 1.0),
                ),
                self.KEY_AFFINE:
                Parameter(
                    validators=[isinstance_validator(np.ndarray)],
                    optional=True,
                    default_value=np.eye(4),
                ),
                self.KEY_AFFINE_LAST:
                Parameter(
                    validators=[isinstance_validator(np.ndarray)],
                    optional=True,
                    default_value=np.eye(4),
                ),
            })

        # validate, returning a dictionary which also includes default parameters
        new_params = input_validator.validate(
            self.inputs, error_type=FilterInputValidationError)

        # Further validation that can't be handled by the parameter validator
        # Check that AffineMatrixFilter.KEY_AFFINE is of size 4x4
        if new_params[self.KEY_AFFINE].shape != (4, 4):
            raise FilterInputValidationError
        # Check that AffineMatrixFilter.KEY_AFFINE_LAST is of size 4x4
        if new_params[self.KEY_AFFINE_LAST].shape != (4, 4):
            raise FilterInputValidationError

        # Check that the tuple AffineMatrixFilter.KEY_ROTATION's length is 3
        if len(new_params[self.KEY_ROTATION]) != 3:
            raise FilterInputValidationError

        # Check that the tuple AffineMatrixFilter.KEY_ROTATION_ORIGIN's length is 3
        if len(new_params[self.KEY_ROTATION_ORIGIN]) != 3:
            raise FilterInputValidationError

        # Check that the tuple AffineMatrixFilter.KEY_TRANSLATION's length is 3
        if len(new_params[self.KEY_TRANSLATION]) != 3:
            raise FilterInputValidationError

        # Check that the tuple AffineMatrixFilter.KEY_SCALE's length is 3
        if len(new_params[self.KEY_SCALE]) != 3:
            raise FilterInputValidationError

        # merge the updated parameters from the output with the input parameters
        self.inputs = {**self._i, **new_params}
    def _validate_inputs(self):
        """Checks that the inputs meet their validation criteria
        'perfusion_rate' must be derived from BaseImageContainer and be >= 0
        'transit_time' must be derived from BaseImageContainer and be >= 0
        'm0' must be either a float or derived from BaseImageContainer and be >= 0
        'label_type' must be a string and equal to "CASL" OR "pCASL" OR "PASL"
        'label_duration" must be a float between 0 and 100
        'signal_time' must be a float between 0 and 100
        'label_efficiency' must be a float between 0 and 1
        'lambda_blood_brain' must be a float between 0 and 1
        't1_arterial_blood' must be a float between 0 and 100

        all BaseImageContainers supplied should be the same dimensions
        """
        input_validator = ParameterValidator(
            parameters={
                self.KEY_PERFUSION_RATE:
                Parameter(validators=[
                    greater_than_equal_to_validator(0),
                    isinstance_validator(BaseImageContainer),
                ]),
                self.KEY_TRANSIT_TIME:
                Parameter(validators=[
                    greater_than_equal_to_validator(0),
                    isinstance_validator(BaseImageContainer),
                ]),
                self.KEY_M0:
                Parameter(validators=[
                    greater_than_equal_to_validator(0),
                    isinstance_validator((BaseImageContainer, float)),
                ]),
                self.KEY_T1_TISSUE:
                Parameter(validators=[
                    range_inclusive_validator(0, 100),
                    isinstance_validator(BaseImageContainer),
                ]),
                self.KEY_LABEL_TYPE:
                Parameter(validators=from_list_validator(
                    [self.CASL, self.PCASL, self.PASL],
                    case_insensitive=True)),
                self.KEY_LABEL_DURATION:
                Parameter(validators=[
                    range_inclusive_validator(0, 100),
                    isinstance_validator(float),
                ]),
                self.KEY_SIGNAL_TIME:
                Parameter(validators=[
                    range_inclusive_validator(0, 100),
                    isinstance_validator(float),
                ]),
                self.KEY_LABEL_EFFICIENCY:
                Parameter(validators=[
                    range_inclusive_validator(0, 1),
                    isinstance_validator(float),
                ]),
                self.KEY_LAMBDA_BLOOD_BRAIN:
                Parameter(validators=[
                    range_inclusive_validator(0, 1),
                    isinstance_validator(float),
                ]),
                self.KEY_T1_ARTERIAL_BLOOD:
                Parameter(validators=[
                    range_inclusive_validator(0, 100),
                    isinstance_validator(float),
                ]),
            })

        input_validator.validate(self.inputs,
                                 error_type=FilterInputValidationError)

        # Check that all the input images are all the same dimensions
        input_keys = self.inputs.keys()
        keys_of_images = [
            key for key in input_keys
            if isinstance(self.inputs[key], BaseImageContainer)
        ]

        list_of_image_shapes = [
            self.inputs[key].shape for key in keys_of_images
        ]
        if list_of_image_shapes.count(
                list_of_image_shapes[0]) != len(list_of_image_shapes):
            raise FilterInputValidationError([
                "Input image shapes do not match.",
                [
                    f"{keys_of_images[i]}: {list_of_image_shapes[i]}, "
                    for i in range(len(list_of_image_shapes))
                ],
            ])
Beispiel #14
0
    def _validate_inputs(self):
        """Checks that the inputs meet their validation criteria.
        'image': NiftiImageContainer, must be 5D, 5th dimension same length as 'quantities'
        'quantities': list[str]
        'units': list[str]
        'segmentation': dict
        'parameters': dict
        'image_override': dict (optional)
        'parameter_override': dict (optional)
        The number of 'units' and 'quantities' should be equal.
        The size of the 5th dimension of the image must equal the number of 'quantities'.
        If 'image_override' is present, must be a dict, each of the keys must be a string
        and the values a float or int type. The key must match an entry in 'quantities'.
        If 'parameter_override' is present, must be a dict, each of the keys must be a
        string and the values a float or int type.
        """
        input_validator = ParameterValidator(
            parameters={
                self.KEY_IMAGE: Parameter(
                    validators=isinstance_validator(NiftiImageContainer)
                ),
                self.KEY_QUANTITIES: Parameter(
                    validators=for_each_validator(isinstance_validator(str))
                ),
                self.KEY_UNITS: Parameter(
                    validators=for_each_validator(isinstance_validator(str))
                ),
                self.KEY_SEGMENTATION: Parameter(validators=isinstance_validator(dict)),
                self.KEY_PARAMETERS: Parameter(validators=isinstance_validator(dict)),
                self.KEY_GROUND_TRUTH_MODULATE: Parameter(
                    validators=isinstance_validator(dict), optional=True
                ),
            }
        )
        input_validator.validate(self.inputs, error_type=FilterInputValidationError)

        image_container: NiftiImageContainer = self.inputs["image"]
        if len(image_container.shape) != 5:
            raise FilterInputValidationError(
                f"{self} filter requires an input nifti which is 5D"
            )

        if image_container.shape[4] != len(self.inputs["quantities"]):
            raise FilterInputValidationError(
                f"{self} filter requires an input nifti which has the "
                "same number of images (across the 5th dimension) as the JSON filter "
                "supplies in 'quantities'"
            )

        if len(self.inputs["units"]) != len(self.inputs["quantities"]):
            raise FilterInputValidationError(
                f"{self} filter requires an input 'units' which is the same length as the input "
                "'quantities'"
            )

        for input_key in [self.KEY_IMAGE_OVERRIDE, self.KEY_PARAMETER_OVERRIDE]:
            if input_key in self.inputs:
                # Check the value is a dictionary
                if not isinstance(self.inputs[input_key], dict):
                    raise FilterInputValidationError(
                        f"{input_key} must be a dictionary, is {self.inputs[input_key]}"
                    )
                # Check all of the keys are strings and the values are int or float
                for key, value in self.inputs[input_key].items():
                    if not isinstance(key, str):
                        raise FilterInputValidationError(
                            f"All keys in the {input_key} dictionary must be strings. "
                            f"{key} is not."
                        )
                    if not isinstance(value, (int, float)):
                        raise FilterInputValidationError(
                            f"Values in the {input_key} dictionary must be int or float. "
                            f"The value for {key} ({value}) is not."
                        )

        if self.KEY_IMAGE_OVERRIDE in self.inputs:
            # Check all of the keys are present in self.inputs['quantities']
            for key, value in self.inputs[self.KEY_IMAGE_OVERRIDE].items():
                if key not in self.inputs[self.KEY_QUANTITIES]:
                    raise FilterInputValidationError(
                        f"{key} is not in the input 'quantities' list"
                    )
        if self.KEY_GROUND_TRUTH_MODULATE in self.inputs:
            try:
                jsonschema.validate(
                    self.inputs[self.KEY_GROUND_TRUTH_MODULATE],
                    SCHEMAS["input_params"]["properties"]["global_configuration"][
                        "properties"
                    ]["ground_truth_modulate"],
                )
            except jsonschema.ValidationError as exception:
                raise FilterInputValidationError from exception
    def _validate_inputs(self):
        """Checks that the inputs meet their validation criteria
        `'object'` must be derived from BaseImageContainer
        `'target_shape'` (optional)must be a Tuple of ints of length 3, values > 0
        `'rotation'` (optional) must be a Tuple of floats of length 3, each value -180 to 180
        inclusive, default (optional) = (0.0, 0.0, 0.0)
        `'rotation_origin'` (optional) must be a Tuple of floats of length 3,
        default = (0.0, 0.0, 0.0)
        `'translation'` (optional) must be a Tuple of floats of length 3, default = (0.0, 0.0, 0.0)
        """

        input_validator = ParameterValidator(
            parameters={
                self.KEY_IMAGE:
                Parameter(validators=isinstance_validator(BaseImageContainer)),
                self.KEY_ROTATION:
                Parameter(
                    validators=[
                        isinstance_validator(tuple),
                        for_each_validator(isinstance_validator(float)),
                        for_each_validator(range_inclusive_validator(
                            -180, 180)),
                    ],
                    optional=True,
                    default_value=(0.0, 0.0, 0.0),
                ),
                self.KEY_ROTATION_ORIGIN:
                Parameter(
                    validators=[
                        isinstance_validator(tuple),
                        for_each_validator(isinstance_validator(float)),
                    ],
                    optional=True,
                    default_value=(0.0, 0.0, 0.0),
                ),
                self.KEY_TRANSLATION:
                Parameter(
                    validators=[
                        isinstance_validator(tuple),
                        for_each_validator(isinstance_validator(float)),
                    ],
                    optional=True,
                    default_value=(0.0, 0.0, 0.0),
                ),
                self.KEY_TARGET_SHAPE:
                Parameter(
                    validators=[
                        isinstance_validator(tuple),
                        for_each_validator(isinstance_validator(int)),
                        for_each_validator(greater_than_validator(0)),
                    ],
                    optional=True,
                    default_value=(9999, 9999, 9999),
                ),
            })

        # validate, returning a dictionary which also includes default parameters
        new_params = input_validator.validate(
            self.inputs, error_type=FilterInputValidationError)

        # Further validation that can't be handled by the parameter validator

        if new_params[self.KEY_TARGET_SHAPE] == (9999, 9999, 9999):
            new_params[self.KEY_TARGET_SHAPE] = self.inputs[
                self.KEY_IMAGE].shape

        # Check that the tuple self.KEY_ROTATION's length is 3
        if len(new_params[self.KEY_ROTATION]) != 3:
            raise FilterInputValidationError

        # Check that the tuple self.KEY_ROTATION_ORIGIN's length is 3
        if len(new_params[self.KEY_ROTATION_ORIGIN]) != 3:
            raise FilterInputValidationError

        # Check that the tuple self.KEY_TRANSLATION's length is 3
        if len(new_params[self.KEY_TRANSLATION]) != 3:
            raise FilterInputValidationError

        # Check that the tuple self.KEY_SCALE's length is 3
        if len(new_params[self.KEY_TARGET_SHAPE]) != 3:
            raise FilterInputValidationError

        # merge the updated parameters from the output with the input parameters
        self.inputs = {**self._i, **new_params}