cropping layer for 2d input e g picture it crops along spatial dimensions i e height and width examples inputshape 2 28 28 3 x np arangenp prodinputshape reshapeinputshape y keras layers cropping2dcropping2 2 4 4x y shape 2 24 20 3 args cropping int or tuple of 2 ints or tuple of 2 tuples of 2 ints if int the same symmetric cropping is applied to height and width if tuple of 2 ints interpreted as two different symmetric cropping values for height and width symmetricheightcrop symmetricwidthcrop if tuple of 2 tuples of 2 ints interpreted as topcrop bottomcrop leftcrop rightcrop dataformat a string one of channelslast default or channelsfirst the ordering of the dimensions in the inputs channelslast corresponds to inputs with shape batchsize height width channels while channelsfirst corresponds to inputs with shape batchsize channels height width when unspecified uses imagedataformat value found in your keras config file at keraskeras json if exists defaults to channelslast input shape 4d tensor with shape if dataformat is channelslast batchsize height width channels if dataformat is channelsfirst batchsize channels height width output shape 4d tensor with shape if dataformat is channelslast batchsize croppedheight croppedwidth channels if dataformat is channelsfirst batchsize channels croppedheight croppedwidth cropping layer for 2d input e g picture it crops along spatial dimensions i e height and width examples input_shape 2 28 28 3 x np arange np prod input_shape reshape input_shape y keras layers cropping2d cropping 2 2 4 4 x y shape 2 24 20 3 args cropping int or tuple of 2 ints or tuple of 2 tuples of 2 ints if int the same symmetric cropping is applied to height and width if tuple of 2 ints interpreted as two different symmetric cropping values for height and width symmetric_height_crop symmetric_width_crop if tuple of 2 tuples of 2 ints interpreted as top_crop bottom_crop left_crop right_crop data_format a string one of channels_last default or channels_first the ordering of the dimensions in the inputs channels_last corresponds to inputs with shape batch_size height width channels while channels_first corresponds to inputs with shape batch_size channels height width when unspecified uses image_data_format value found in your keras config file at keras keras json if exists defaults to channels_last input shape 4d tensor with shape if data_format is channels_last batch_size height width channels if data_format is channels_first batch_size channels height width output shape 4d tensor with shape if data_format is channels_last batch_size cropped_height cropped_width channels if data_format is channels_first batch_size channels cropped_height cropped_width
from keras import backend
from keras.api_export import keras_export
from keras.layers.input_spec import InputSpec
from keras.layers.layer import Layer
from keras.utils import argument_validation


@keras_export("keras.layers.Cropping2D")
class Cropping2D(Layer):
    

    def __init__(self, cropping=((0, 0), (0, 0)), data_format=None, **kwargs):
        super().__init__(**kwargs)
        self.data_format = backend.standardize_data_format(data_format)
        if isinstance(cropping, int):
            self.cropping = ((cropping, cropping), (cropping, cropping))
        elif hasattr(cropping, "__len__"):
            if len(cropping) != 2:
                raise ValueError(
                    "`cropping` should have two elements. "
                    f"Received: cropping={cropping}."
                )
            height_cropping = argument_validation.standardize_tuple(
                cropping[0], 2, "1st entry of cropping", allow_zero=True
            )
            width_cropping = argument_validation.standardize_tuple(
                cropping[1], 2, "2nd entry of cropping", allow_zero=True
            )
            self.cropping = (height_cropping, width_cropping)
        else:
            raise ValueError(
                "`cropping` should be either an int, a tuple of 2 ints "
                "(symmetric_height_crop, symmetric_width_crop), "
                "or a tuple of 2 tuples of 2 ints "
                "((top_crop, bottom_crop), (left_crop, right_crop)). "
                f"Received: cropping={cropping}."
            )
        self.input_spec = InputSpec(ndim=4)

    def compute_output_shape(self, input_shape):
        if self.data_format == "channels_first":
            if (
                input_shape[2] is not None
                and sum(self.cropping[0]) >= input_shape[2]
            ) or (
                input_shape[3] is not None
                and sum(self.cropping[1]) >= input_shape[3]
            ):
                raise ValueError(
                    "Values in `cropping` argument should be greater than the "
                    "corresponding spatial dimension of the input. Received: "
                    f"input_shape={input_shape}, cropping={self.cropping}"
                )
            return (
                input_shape[0],
                input_shape[1],
                input_shape[2] - self.cropping[0][0] - self.cropping[0][1]
                if input_shape[2] is not None
                else None,
                input_shape[3] - self.cropping[1][0] - self.cropping[1][1]
                if input_shape[3] is not None
                else None,
            )
        else:
            if (
                input_shape[1] is not None
                and sum(self.cropping[0]) >= input_shape[1]
            ) or (
                input_shape[2] is not None
                and sum(self.cropping[1]) >= input_shape[2]
            ):
                raise ValueError(
                    "Values in `cropping` argument should be greater than the "
                    "corresponding spatial dimension of the input. Received: "
                    f"input_shape={input_shape}, cropping={self.cropping}"
                )
            return (
                input_shape[0],
                input_shape[1] - self.cropping[0][0] - self.cropping[0][1]
                if input_shape[1] is not None
                else None,
                input_shape[2] - self.cropping[1][0] - self.cropping[1][1]
                if input_shape[2] is not None
                else None,
                input_shape[3],
            )

    def call(self, inputs):
        if self.data_format == "channels_first":
            if (
                inputs.shape[2] is not None
                and sum(self.cropping[0]) >= inputs.shape[2]
            ) or (
                inputs.shape[3] is not None
                and sum(self.cropping[1]) >= inputs.shape[3]
            ):
                raise ValueError(
                    "Values in `cropping` argument should be greater than the "
                    "corresponding spatial dimension of the input. Received: "
                    f"inputs.shape={inputs.shape}, cropping={self.cropping}"
                )
            if self.cropping[0][1] == self.cropping[1][1] == 0:
                return inputs[
                    :, :, self.cropping[0][0] :, self.cropping[1][0] :
                ]
            elif self.cropping[0][1] == 0:
                return inputs[
                    :,
                    :,
                    self.cropping[0][0] :,
                    self.cropping[1][0] : -self.cropping[1][1],
                ]
            elif self.cropping[1][1] == 0:
                return inputs[
                    :,
                    :,
                    self.cropping[0][0] : -self.cropping[0][1],
                    self.cropping[1][0] :,
                ]
            return inputs[
                :,
                :,
                self.cropping[0][0] : -self.cropping[0][1],
                self.cropping[1][0] : -self.cropping[1][1],
            ]
        else:
            if (
                inputs.shape[1] is not None
                and sum(self.cropping[0]) >= inputs.shape[1]
            ) or (
                inputs.shape[2] is not None
                and sum(self.cropping[1]) >= inputs.shape[2]
            ):
                raise ValueError(
                    "Values in `cropping` argument should be greater than the "
                    "corresponding spatial dimension of the input. Received: "
                    f"inputs.shape={inputs.shape}, cropping={self.cropping}"
                )
            if self.cropping[0][1] == self.cropping[1][1] == 0:
                return inputs[
                    :, self.cropping[0][0] :, self.cropping[1][0] :, :
                ]
            elif self.cropping[0][1] == 0:
                return inputs[
                    :,
                    self.cropping[0][0] :,
                    self.cropping[1][0] : -self.cropping[1][1],
                    :,
                ]
            elif self.cropping[1][1] == 0:
                return inputs[
                    :,
                    self.cropping[0][0] : -self.cropping[0][1],
                    self.cropping[1][0] :,
                    :,
                ]
            return inputs[
                :,
                self.cropping[0][0] : -self.cropping[0][1],
                self.cropping[1][0] : -self.cropping[1][1],
                :,
            ]

    def get_config(self):
        config = {"cropping": self.cropping, "data_format": self.data_format}
        base_config = super().get_config()
        return {**base_config, **config}