def extract_features(self, img: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]:
        """Extract features from input image using both CaiT models.

        The features are extracted at two scales:
        - Scale 1: Using CaiT-M48 up to block index 40 (448x448 input)
        - Scale 2: Using CaiT-S24 up to block index 20 (224x224 input)

        Args:
            img (torch.Tensor): Input image tensor of shape
                ``(batch_size, channels, height, width)``

        Returns:
            tuple[torch.Tensor, torch.Tensor]: Features from both extractors with shapes:
                ``[(B, 768, H/16, W/16), (B, 384, H/32, W/32)]``
        """
        self.extractor1.eval()
        self.extractor2.eval()

        # Scale 1 --> Extractor 1
        x1 = self.extractor1.patch_embed(img)
        x1 = x1 + self.extractor1.pos_embed
        x1 = self.extractor1.pos_drop(x1)
        for i in range(41):  # paper Table 6. Block Index = 40
            x1 = self.extractor1.blocks[i](x1)

        # Scale 2 --> Extractor 2
        img_sub = F.interpolate(torch.Tensor(img), size=(224, 224), mode="bicubic", align_corners=True)
        x2 = self.extractor2.patch_embed(img_sub)
        x2 = x2 + self.extractor2.pos_embed
        x2 = self.extractor2.pos_drop(x2)
        for i in range(21):
            x2 = self.extractor2.blocks[i](x2)

        return (x1, x2)
Extract features from input image using both CaiT models.

        The features are extracted at two scales:
        - Scale 1: Using CaiT-M48 up to block index 40 (448x448 input)
        - Scale 2: Using CaiT-S24 up to block index 20 (224x224 input)

        Args:
            img (torch.Tensor): Input image tensor of shape
                ``(batch_size, channels, height, width)``

        Returns:
            tuple[torch.Tensor, torch.Tensor]: Features from both extractors with shapes:
                ``[(B, 768, H/16, W/16), (B, 384, H/32, W/32)]``
        
src/anomalib/models/image/uflow/feature_extraction.py