Module facetorch.analyzer.detector.pre

Classes

class BaseDetPreProcessor (transform: torchvision.transforms.transforms.Compose,
device: torch.device,
optimize_transform: bool)
Expand source code
class BaseDetPreProcessor(BaseProcessor):
    # Custom preprocessors are assumed capable of mutating ``data.tensor`` and
    # therefore retain the detector's defensive raw-image copy by default.
    preserves_input_tensor = False

    @Timer(
        "BaseDetPreProcessor.__init__",
        "{name}: {milliseconds:.2f} ms",
        logger=logger.debug,
    )
    def __init__(
        self,
        transform: transforms.Compose,
        device: torch.device,
        optimize_transform: bool,
    ):
        """Base class for detector pre processors.

        All detector pre processors should subclass it.
        All subclass should overwrite:

        - Methods:``run``, used for running the processing

        Args:
            device (torch.device): Torch device cpu or cuda.
            transform (transforms.Compose): Transform compose object to be applied to the image.
            optimize_transform (bool): Whether to optimize the transform.

        """
        super().__init__(transform, device, optimize_transform)

    @abstractmethod
    def run(self, data: ImageData) -> ImageData:
        """Abstract method that runs the detector pre processing functionality.
        Returns a batch of preprocessed face tensors.

        Args:
            data (ImageData): ImageData object containing the image tensor.

        Returns:
            ImageData: ImageData object containing the image tensor preprocessed for the detector.

        """

Base class for detector pre processors.

All detector pre processors should subclass it. All subclass should overwrite:

  • Methods:run, used for running the processing
Args
-----=
device : torch.device
Torch device cpu or cuda.
transform : transforms.Compose
Transform compose object to be applied to the image.
optimize_transform : bool
Whether to optimize the transform.

Ancestors

Subclasses

Class variables

var preserves_input_tensor

Methods

def run(self,
data: ImageData) ‑> ImageData
Expand source code
@abstractmethod
def run(self, data: ImageData) -> ImageData:
    """Abstract method that runs the detector pre processing functionality.
    Returns a batch of preprocessed face tensors.

    Args:
        data (ImageData): ImageData object containing the image tensor.

    Returns:
        ImageData: ImageData object containing the image tensor preprocessed for the detector.

    """

Abstract method that runs the detector pre processing functionality. Returns a batch of preprocessed face tensors.

Args
-----=
data : ImageData
ImageData object containing the image tensor.
Returns
-----=
ImageData
ImageData object containing the image tensor preprocessed for the detector.

Inherited members

class DetectorPreProcessor (transform: torchvision.transforms.transforms.Compose,
device: torch.device,
optimize_transform: bool,
reverse_colors: bool)
Expand source code
class DetectorPreProcessor(BaseDetPreProcessor):
    # This implementation isolates configurable transforms from the caller's
    # tensor. Custom preprocessors remain defensive by default through the
    # base-class flag.
    preserves_input_tensor = True
    model_min_size = 64
    model_max_size = 2048
    model_size_multiple = 32

    @Timer(
        "DetectorPreProcessor.__init__",
        "{name}: {milliseconds:.2f} ms",
        logger=logger.debug,
    )
    def __init__(
        self,
        transform: transforms.Compose,
        device: torch.device,
        optimize_transform: bool,
        reverse_colors: bool,
    ):
        """Initialize the detector preprocessor.

        Args:
            transform (Compose): Composed Torch transform object.
            device (torch.device): Torch device cpu or cuda.
            optimize_transform (bool): Whether to optimize the transform.
            reverse_colors (bool): Whether to reverse the colors of the image tensor from RGB to BGR or vice versa. If False, the colors remain unchanged.

        """
        super().__init__(transform, device, optimize_transform)
        self.reverse_colors = reverse_colors

    @Timer(
        "DetectorPreProcessor.run", "{name}: {milliseconds:.2f} ms", logger=logger.debug
    )
    def run(self, data: ImageData) -> ImageData:
        """Run the detector preprocessor on the image tensor in BGR format and return the transformed image tensor.

        Args:
            data (ImageData): ImageData object containing the image tensor.

        Returns:
            ImageData: ImageData object containing the preprocessed image tensor.
        """
        source_h, source_w = data.tensor.shape[-2:]
        # A configured transform may mutate its argument (for example,
        # ``Normalize(inplace=True)``). Always give it independent storage so
        # FaceDetector can safely restore the canonical source tensor.
        data.tensor = data.tensor.to(device=self.device, copy=True)
        data.tensor = self.transform(data.tensor)

        if self.reverse_colors:
            data.tensor = rgb2bgr(data.tensor)

        _, _, h, w = data.tensor.shape
        resize_scale = min(
            1.0,
            self.model_max_size / h,
            self.model_max_size / w,
        )
        target_h = max(1, min(self.model_max_size, round(h * resize_scale)))
        target_w = max(1, min(self.model_max_size, round(w * resize_scale)))
        if (target_h, target_w) != (h, w):
            data.tensor = F.interpolate(
                data.tensor,
                size=(target_h, target_w),
                mode="bilinear",
                align_corners=False,
                antialias=True,
            )

        # FaceDetector consumes this private handoff before returning ImageData.
        # Padding does not change pixel coordinates, so the scale uses the
        # unpadded detector image dimensions.
        data._facetorch_detector_coordinate_scale = (
            source_w / target_w,
            source_h / target_h,
        )

        padded_h = max(
            self.model_min_size,
            ((target_h + self.model_size_multiple - 1) // self.model_size_multiple)
            * self.model_size_multiple,
        )
        padded_w = max(
            self.model_min_size,
            ((target_w + self.model_size_multiple - 1) // self.model_size_multiple)
            * self.model_size_multiple,
        )
        pad_h = padded_h - target_h
        pad_w = padded_w - target_w
        if pad_h > 0 or pad_w > 0:
            data.tensor = F.pad(data.tensor, (0, pad_w, 0, pad_h), value=0)
        data.set_dims()

        return data

Initialize the detector preprocessor.

Args
-----=
transform : Compose
Composed Torch transform object.
device : torch.device
Torch device cpu or cuda.
optimize_transform : bool
Whether to optimize the transform.
reverse_colors : bool
Whether to reverse the colors of the image tensor from RGB to BGR or vice versa. If False, the colors remain unchanged.

Ancestors

Class variables

var preserves_input_tensor
var model_min_size
var model_max_size
var model_size_multiple

Methods

def run(self,
data: ImageData) ‑> ImageData
Expand source code
@Timer(
    "DetectorPreProcessor.run", "{name}: {milliseconds:.2f} ms", logger=logger.debug
)
def run(self, data: ImageData) -> ImageData:
    """Run the detector preprocessor on the image tensor in BGR format and return the transformed image tensor.

    Args:
        data (ImageData): ImageData object containing the image tensor.

    Returns:
        ImageData: ImageData object containing the preprocessed image tensor.
    """
    source_h, source_w = data.tensor.shape[-2:]
    # A configured transform may mutate its argument (for example,
    # ``Normalize(inplace=True)``). Always give it independent storage so
    # FaceDetector can safely restore the canonical source tensor.
    data.tensor = data.tensor.to(device=self.device, copy=True)
    data.tensor = self.transform(data.tensor)

    if self.reverse_colors:
        data.tensor = rgb2bgr(data.tensor)

    _, _, h, w = data.tensor.shape
    resize_scale = min(
        1.0,
        self.model_max_size / h,
        self.model_max_size / w,
    )
    target_h = max(1, min(self.model_max_size, round(h * resize_scale)))
    target_w = max(1, min(self.model_max_size, round(w * resize_scale)))
    if (target_h, target_w) != (h, w):
        data.tensor = F.interpolate(
            data.tensor,
            size=(target_h, target_w),
            mode="bilinear",
            align_corners=False,
            antialias=True,
        )

    # FaceDetector consumes this private handoff before returning ImageData.
    # Padding does not change pixel coordinates, so the scale uses the
    # unpadded detector image dimensions.
    data._facetorch_detector_coordinate_scale = (
        source_w / target_w,
        source_h / target_h,
    )

    padded_h = max(
        self.model_min_size,
        ((target_h + self.model_size_multiple - 1) // self.model_size_multiple)
        * self.model_size_multiple,
    )
    padded_w = max(
        self.model_min_size,
        ((target_w + self.model_size_multiple - 1) // self.model_size_multiple)
        * self.model_size_multiple,
    )
    pad_h = padded_h - target_h
    pad_w = padded_w - target_w
    if pad_h > 0 or pad_w > 0:
        data.tensor = F.pad(data.tensor, (0, pad_w, 0, pad_h), value=0)
    data.set_dims()

    return data

Run the detector preprocessor on the image tensor in BGR format and return the transformed image tensor.

Args
-----=
data : ImageData
ImageData object containing the image tensor.
Returns
-----=
ImageData
ImageData object containing the preprocessed image tensor.

Inherited members