Module facetorch.analyzer.reader.core

Expand source code
import io
import requests
from PIL import Image
import numpy as np
import torch
import torchvision
from codetiming import Timer
from typing import Union
from facetorch.base import BaseReader
from facetorch.datastruct import ImageData
from facetorch.logger import LoggerJsonFile

logger = LoggerJsonFile().logger


class UniversalReader(BaseReader):
    def __init__(
        self,
        transform: torchvision.transforms.Compose,
        device: torch.device,
        optimize_transform: bool,
    ):
        """UniversalReader can read images from a path, URL, tensor, numpy array, bytes or PIL Image and return an ImageData object containing the image tensor.

        Args:
            transform (torchvision.transforms.Compose): Transform compose object to be applied to the image, if fix_image_size is True.
            device (torch.device): Torch device cpu or cuda object.
            optimize_transform (bool): Whether to optimize the transforms that are: resizing the image to a fixed size.

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

    @Timer("UniversalReader.run", "{name}: {milliseconds:.2f} ms", logger=logger.debug)
    def run(
        self,
        image_source: Union[str, torch.Tensor, np.ndarray, bytes, Image.Image],
        fix_img_size: bool = False,
    ) -> ImageData:
        """Reads an image from a path, URL, tensor, numpy array, bytes or PIL Image and returns a tensor of the image with values between 0-255 and shape (batch, channels, height, width). The order of color channels is RGB. PyTorch and Torchvision are used to read the image.

        Args:
            image_source (Union[str, torch.Tensor, np.ndarray, bytes, Image.Image]): Image source to be read.
            fix_img_size (bool): Whether to resize the image to a fixed size. If False, the size_portrait and size_landscape are ignored. Default is False.

        Returns:
            ImageData: ImageData object with image tensor and pil Image.
        """
        if isinstance(image_source, str):
            if image_source.startswith("http"):
                return self.read_image_from_url(image_source, fix_img_size)
            else:
                return self.read_image_from_path(image_source, fix_img_size)
        elif isinstance(image_source, torch.Tensor):
            return self.read_tensor(image_source, fix_img_size)
        elif isinstance(image_source, np.ndarray):
            return self.read_numpy_array(image_source, fix_img_size)
        elif isinstance(image_source, bytes):
            return self.read_image_from_bytes(image_source, fix_img_size)
        elif isinstance(image_source, Image.Image):
            return self.read_pil_image(image_source, fix_img_size)
        else:
            raise ValueError("Unsupported data type")

    def read_tensor(self, tensor: torch.Tensor, fix_img_size: bool) -> ImageData:
        return self.process_tensor(tensor, fix_img_size)

    def read_pil_image(self, pil_image: Image.Image, fix_img_size: bool) -> ImageData:
        tensor = torchvision.transforms.functional.to_tensor(pil_image)
        return self.process_tensor(tensor, fix_img_size)

    def read_numpy_array(self, array: np.ndarray, fix_img_size: bool) -> ImageData:
        pil_image = Image.fromarray(array, mode="RGB")
        return self.read_pil_image(pil_image, fix_img_size)

    def read_image_from_bytes(
        self, image_bytes: bytes, fix_img_size: bool
    ) -> ImageData:
        pil_image = Image.open(io.BytesIO(image_bytes))
        return self.read_pil_image(pil_image, fix_img_size)

    def read_image_from_path(self, path_image: str, fix_img_size: bool) -> ImageData:
        try:
            image_tensor = torchvision.io.read_image(path_image)
        except Exception as e:
            logger.error(f"Failed to read image from path {path_image}: {e}")
            raise ValueError(f"Could not read image from path {path_image}: {e}") from e

        return self.process_tensor(image_tensor, fix_img_size)

    def read_image_from_url(self, url: str, fix_img_size: bool) -> ImageData:
        try:
            response = requests.get(url, timeout=10)
            response.raise_for_status()
        except requests.RequestException as e:
            logger.error(f"Failed to fetch image from URL {url}: {e}")
            raise ValueError(f"Could not fetch image from URL {url}: {e}") from e

        image_bytes = response.content
        return self.read_image_from_bytes(image_bytes, fix_img_size)


class ImageReader(BaseReader):
    def __init__(
        self,
        transform: torchvision.transforms.Compose,
        device: torch.device,
        optimize_transform: bool,
    ):
        """ImageReader is a wrapper around a functionality for reading images by Torchvision.

        Args:
            transform (torchvision.transforms.Compose): Transform compose object to be applied to the image, if fix_image_size is True.
            device (torch.device): Torch device cpu or cuda object.
            optimize_transform (bool): Whether to optimize the transforms that are: resizing the image to a fixed size.

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

    @Timer("ImageReader.run", "{name}: {milliseconds:.2f} ms", logger=logger.debug)
    def run(self, path_image: str, fix_img_size: bool = False) -> ImageData:
        """Reads an image from a path and returns a tensor of the image with values between 0-255 and shape (batch, channels, height, width). The order of color channels is RGB. PyTorch and Torchvision are used to read the image.

        Args:
            path_image (str): Path to the image.
            fix_img_size (bool): Whether to resize the image to a fixed size. If False, the size_portrait and size_landscape are ignored. Default is False.

        Returns:
            ImageData: ImageData object with image tensor and pil Image.
        """
        data = ImageData(path_input=path_image)
        data.img = torchvision.io.read_image(
            data.path_input, mode=torchvision.io.ImageReadMode.RGB
        )
        data.img = data.img.unsqueeze(0)
        data.img = data.img.to(self.device)

        if fix_img_size:
            data.img = self.transform(data.img)

        data.tensor = data.img.type(torch.float32)
        data.img = data.img.squeeze(0).cpu()
        data.set_dims()

        return data


class TensorReader(BaseReader):
    def __init__(
        self,
        transform: torchvision.transforms.Compose,
        device: torch.device,
        optimize_transform: bool,
    ):
        """TensorReader is a wrapper around a functionality for reading tensors by Torchvision.

        Args:
            transform (torchvision.transforms.Compose): Transform compose object to be applied to the image, if fix_image_size is True.
            device (torch.device): Torch device cpu or cuda object.
            optimize_transform (bool): Whether to optimize the transforms that are: resizing the image to a fixed size.

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

    @Timer("TensorReader.run", "{name}: {milliseconds:.2f} ms", logger=logger.debug)
    def run(self, tensor: torch.Tensor, fix_img_size: bool = False) -> ImageData:
        """Reads a tensor and returns a tensor of the image with values between 0-255 and shape (batch, channels, height, width). The order of color channels is RGB. PyTorch and Torchvision are used to read the image.

        Args:
            tensor (torch.Tensor): Tensor of a single image with RGB values between 0-255 and shape (channels, height, width).
            fix_img_size (bool): Whether to resize the image to a fixed size. If False, the size_portrait and size_landscape are ignored. Default is False.

        Returns:
            ImageData: ImageData object with image tensor and pil Image.
        """
        return self.process_tensor(tensor, fix_img_size)

Classes

class UniversalReader (transform: torchvision.transforms.transforms.Compose, device: torch.device, optimize_transform: bool)

UniversalReader can read images from a path, URL, tensor, numpy array, bytes or PIL Image and return an ImageData object containing the image tensor.

Args

transform : torchvision.transforms.Compose
Transform compose object to be applied to the image, if fix_image_size is True.
device : torch.device
Torch device cpu or cuda object.
optimize_transform : bool
Whether to optimize the transforms that are: resizing the image to a fixed size.
Expand source code
class UniversalReader(BaseReader):
    def __init__(
        self,
        transform: torchvision.transforms.Compose,
        device: torch.device,
        optimize_transform: bool,
    ):
        """UniversalReader can read images from a path, URL, tensor, numpy array, bytes or PIL Image and return an ImageData object containing the image tensor.

        Args:
            transform (torchvision.transforms.Compose): Transform compose object to be applied to the image, if fix_image_size is True.
            device (torch.device): Torch device cpu or cuda object.
            optimize_transform (bool): Whether to optimize the transforms that are: resizing the image to a fixed size.

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

    @Timer("UniversalReader.run", "{name}: {milliseconds:.2f} ms", logger=logger.debug)
    def run(
        self,
        image_source: Union[str, torch.Tensor, np.ndarray, bytes, Image.Image],
        fix_img_size: bool = False,
    ) -> ImageData:
        """Reads an image from a path, URL, tensor, numpy array, bytes or PIL Image and returns a tensor of the image with values between 0-255 and shape (batch, channels, height, width). The order of color channels is RGB. PyTorch and Torchvision are used to read the image.

        Args:
            image_source (Union[str, torch.Tensor, np.ndarray, bytes, Image.Image]): Image source to be read.
            fix_img_size (bool): Whether to resize the image to a fixed size. If False, the size_portrait and size_landscape are ignored. Default is False.

        Returns:
            ImageData: ImageData object with image tensor and pil Image.
        """
        if isinstance(image_source, str):
            if image_source.startswith("http"):
                return self.read_image_from_url(image_source, fix_img_size)
            else:
                return self.read_image_from_path(image_source, fix_img_size)
        elif isinstance(image_source, torch.Tensor):
            return self.read_tensor(image_source, fix_img_size)
        elif isinstance(image_source, np.ndarray):
            return self.read_numpy_array(image_source, fix_img_size)
        elif isinstance(image_source, bytes):
            return self.read_image_from_bytes(image_source, fix_img_size)
        elif isinstance(image_source, Image.Image):
            return self.read_pil_image(image_source, fix_img_size)
        else:
            raise ValueError("Unsupported data type")

    def read_tensor(self, tensor: torch.Tensor, fix_img_size: bool) -> ImageData:
        return self.process_tensor(tensor, fix_img_size)

    def read_pil_image(self, pil_image: Image.Image, fix_img_size: bool) -> ImageData:
        tensor = torchvision.transforms.functional.to_tensor(pil_image)
        return self.process_tensor(tensor, fix_img_size)

    def read_numpy_array(self, array: np.ndarray, fix_img_size: bool) -> ImageData:
        pil_image = Image.fromarray(array, mode="RGB")
        return self.read_pil_image(pil_image, fix_img_size)

    def read_image_from_bytes(
        self, image_bytes: bytes, fix_img_size: bool
    ) -> ImageData:
        pil_image = Image.open(io.BytesIO(image_bytes))
        return self.read_pil_image(pil_image, fix_img_size)

    def read_image_from_path(self, path_image: str, fix_img_size: bool) -> ImageData:
        try:
            image_tensor = torchvision.io.read_image(path_image)
        except Exception as e:
            logger.error(f"Failed to read image from path {path_image}: {e}")
            raise ValueError(f"Could not read image from path {path_image}: {e}") from e

        return self.process_tensor(image_tensor, fix_img_size)

    def read_image_from_url(self, url: str, fix_img_size: bool) -> ImageData:
        try:
            response = requests.get(url, timeout=10)
            response.raise_for_status()
        except requests.RequestException as e:
            logger.error(f"Failed to fetch image from URL {url}: {e}")
            raise ValueError(f"Could not fetch image from URL {url}: {e}") from e

        image_bytes = response.content
        return self.read_image_from_bytes(image_bytes, fix_img_size)

Ancestors

Methods

def run(self, image_source: Union[str, torch.Tensor, numpy.ndarray, bytes, PIL.Image.Image], fix_img_size: bool = False) ‑> ImageData

Reads an image from a path, URL, tensor, numpy array, bytes or PIL Image and returns a tensor of the image with values between 0-255 and shape (batch, channels, height, width). The order of color channels is RGB. PyTorch and Torchvision are used to read the image.

Args

image_source : Union[str, torch.Tensor, np.ndarray, bytes, Image.Image]
Image source to be read.
fix_img_size : bool
Whether to resize the image to a fixed size. If False, the size_portrait and size_landscape are ignored. Default is False.

Returns

ImageData
ImageData object with image tensor and pil Image.
Expand source code
@Timer("UniversalReader.run", "{name}: {milliseconds:.2f} ms", logger=logger.debug)
def run(
    self,
    image_source: Union[str, torch.Tensor, np.ndarray, bytes, Image.Image],
    fix_img_size: bool = False,
) -> ImageData:
    """Reads an image from a path, URL, tensor, numpy array, bytes or PIL Image and returns a tensor of the image with values between 0-255 and shape (batch, channels, height, width). The order of color channels is RGB. PyTorch and Torchvision are used to read the image.

    Args:
        image_source (Union[str, torch.Tensor, np.ndarray, bytes, Image.Image]): Image source to be read.
        fix_img_size (bool): Whether to resize the image to a fixed size. If False, the size_portrait and size_landscape are ignored. Default is False.

    Returns:
        ImageData: ImageData object with image tensor and pil Image.
    """
    if isinstance(image_source, str):
        if image_source.startswith("http"):
            return self.read_image_from_url(image_source, fix_img_size)
        else:
            return self.read_image_from_path(image_source, fix_img_size)
    elif isinstance(image_source, torch.Tensor):
        return self.read_tensor(image_source, fix_img_size)
    elif isinstance(image_source, np.ndarray):
        return self.read_numpy_array(image_source, fix_img_size)
    elif isinstance(image_source, bytes):
        return self.read_image_from_bytes(image_source, fix_img_size)
    elif isinstance(image_source, Image.Image):
        return self.read_pil_image(image_source, fix_img_size)
    else:
        raise ValueError("Unsupported data type")
def read_tensor(self, tensor: torch.Tensor, fix_img_size: bool) ‑> ImageData
Expand source code
def read_tensor(self, tensor: torch.Tensor, fix_img_size: bool) -> ImageData:
    return self.process_tensor(tensor, fix_img_size)
def read_pil_image(self, pil_image: PIL.Image.Image, fix_img_size: bool) ‑> ImageData
Expand source code
def read_pil_image(self, pil_image: Image.Image, fix_img_size: bool) -> ImageData:
    tensor = torchvision.transforms.functional.to_tensor(pil_image)
    return self.process_tensor(tensor, fix_img_size)
def read_numpy_array(self, array: numpy.ndarray, fix_img_size: bool) ‑> ImageData
Expand source code
def read_numpy_array(self, array: np.ndarray, fix_img_size: bool) -> ImageData:
    pil_image = Image.fromarray(array, mode="RGB")
    return self.read_pil_image(pil_image, fix_img_size)
def read_image_from_bytes(self, image_bytes: bytes, fix_img_size: bool) ‑> ImageData
Expand source code
def read_image_from_bytes(
    self, image_bytes: bytes, fix_img_size: bool
) -> ImageData:
    pil_image = Image.open(io.BytesIO(image_bytes))
    return self.read_pil_image(pil_image, fix_img_size)
def read_image_from_path(self, path_image: str, fix_img_size: bool) ‑> ImageData
Expand source code
def read_image_from_path(self, path_image: str, fix_img_size: bool) -> ImageData:
    try:
        image_tensor = torchvision.io.read_image(path_image)
    except Exception as e:
        logger.error(f"Failed to read image from path {path_image}: {e}")
        raise ValueError(f"Could not read image from path {path_image}: {e}") from e

    return self.process_tensor(image_tensor, fix_img_size)
def read_image_from_url(self, url: str, fix_img_size: bool) ‑> ImageData
Expand source code
def read_image_from_url(self, url: str, fix_img_size: bool) -> ImageData:
    try:
        response = requests.get(url, timeout=10)
        response.raise_for_status()
    except requests.RequestException as e:
        logger.error(f"Failed to fetch image from URL {url}: {e}")
        raise ValueError(f"Could not fetch image from URL {url}: {e}") from e

    image_bytes = response.content
    return self.read_image_from_bytes(image_bytes, fix_img_size)

Inherited members

class ImageReader (transform: torchvision.transforms.transforms.Compose, device: torch.device, optimize_transform: bool)

ImageReader is a wrapper around a functionality for reading images by Torchvision.

Args

transform : torchvision.transforms.Compose
Transform compose object to be applied to the image, if fix_image_size is True.
device : torch.device
Torch device cpu or cuda object.
optimize_transform : bool
Whether to optimize the transforms that are: resizing the image to a fixed size.
Expand source code
class ImageReader(BaseReader):
    def __init__(
        self,
        transform: torchvision.transforms.Compose,
        device: torch.device,
        optimize_transform: bool,
    ):
        """ImageReader is a wrapper around a functionality for reading images by Torchvision.

        Args:
            transform (torchvision.transforms.Compose): Transform compose object to be applied to the image, if fix_image_size is True.
            device (torch.device): Torch device cpu or cuda object.
            optimize_transform (bool): Whether to optimize the transforms that are: resizing the image to a fixed size.

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

    @Timer("ImageReader.run", "{name}: {milliseconds:.2f} ms", logger=logger.debug)
    def run(self, path_image: str, fix_img_size: bool = False) -> ImageData:
        """Reads an image from a path and returns a tensor of the image with values between 0-255 and shape (batch, channels, height, width). The order of color channels is RGB. PyTorch and Torchvision are used to read the image.

        Args:
            path_image (str): Path to the image.
            fix_img_size (bool): Whether to resize the image to a fixed size. If False, the size_portrait and size_landscape are ignored. Default is False.

        Returns:
            ImageData: ImageData object with image tensor and pil Image.
        """
        data = ImageData(path_input=path_image)
        data.img = torchvision.io.read_image(
            data.path_input, mode=torchvision.io.ImageReadMode.RGB
        )
        data.img = data.img.unsqueeze(0)
        data.img = data.img.to(self.device)

        if fix_img_size:
            data.img = self.transform(data.img)

        data.tensor = data.img.type(torch.float32)
        data.img = data.img.squeeze(0).cpu()
        data.set_dims()

        return data

Ancestors

Methods

def run(self, path_image: str, fix_img_size: bool = False) ‑> ImageData

Reads an image from a path and returns a tensor of the image with values between 0-255 and shape (batch, channels, height, width). The order of color channels is RGB. PyTorch and Torchvision are used to read the image.

Args

path_image : str
Path to the image.
fix_img_size : bool
Whether to resize the image to a fixed size. If False, the size_portrait and size_landscape are ignored. Default is False.

Returns

ImageData
ImageData object with image tensor and pil Image.
Expand source code
@Timer("ImageReader.run", "{name}: {milliseconds:.2f} ms", logger=logger.debug)
def run(self, path_image: str, fix_img_size: bool = False) -> ImageData:
    """Reads an image from a path and returns a tensor of the image with values between 0-255 and shape (batch, channels, height, width). The order of color channels is RGB. PyTorch and Torchvision are used to read the image.

    Args:
        path_image (str): Path to the image.
        fix_img_size (bool): Whether to resize the image to a fixed size. If False, the size_portrait and size_landscape are ignored. Default is False.

    Returns:
        ImageData: ImageData object with image tensor and pil Image.
    """
    data = ImageData(path_input=path_image)
    data.img = torchvision.io.read_image(
        data.path_input, mode=torchvision.io.ImageReadMode.RGB
    )
    data.img = data.img.unsqueeze(0)
    data.img = data.img.to(self.device)

    if fix_img_size:
        data.img = self.transform(data.img)

    data.tensor = data.img.type(torch.float32)
    data.img = data.img.squeeze(0).cpu()
    data.set_dims()

    return data

Inherited members

class TensorReader (transform: torchvision.transforms.transforms.Compose, device: torch.device, optimize_transform: bool)

TensorReader is a wrapper around a functionality for reading tensors by Torchvision.

Args

transform : torchvision.transforms.Compose
Transform compose object to be applied to the image, if fix_image_size is True.
device : torch.device
Torch device cpu or cuda object.
optimize_transform : bool
Whether to optimize the transforms that are: resizing the image to a fixed size.
Expand source code
class TensorReader(BaseReader):
    def __init__(
        self,
        transform: torchvision.transforms.Compose,
        device: torch.device,
        optimize_transform: bool,
    ):
        """TensorReader is a wrapper around a functionality for reading tensors by Torchvision.

        Args:
            transform (torchvision.transforms.Compose): Transform compose object to be applied to the image, if fix_image_size is True.
            device (torch.device): Torch device cpu or cuda object.
            optimize_transform (bool): Whether to optimize the transforms that are: resizing the image to a fixed size.

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

    @Timer("TensorReader.run", "{name}: {milliseconds:.2f} ms", logger=logger.debug)
    def run(self, tensor: torch.Tensor, fix_img_size: bool = False) -> ImageData:
        """Reads a tensor and returns a tensor of the image with values between 0-255 and shape (batch, channels, height, width). The order of color channels is RGB. PyTorch and Torchvision are used to read the image.

        Args:
            tensor (torch.Tensor): Tensor of a single image with RGB values between 0-255 and shape (channels, height, width).
            fix_img_size (bool): Whether to resize the image to a fixed size. If False, the size_portrait and size_landscape are ignored. Default is False.

        Returns:
            ImageData: ImageData object with image tensor and pil Image.
        """
        return self.process_tensor(tensor, fix_img_size)

Ancestors

Methods

def run(self, tensor: torch.Tensor, fix_img_size: bool = False) ‑> ImageData

Reads a tensor and returns a tensor of the image with values between 0-255 and shape (batch, channels, height, width). The order of color channels is RGB. PyTorch and Torchvision are used to read the image.

Args

tensor : torch.Tensor
Tensor of a single image with RGB values between 0-255 and shape (channels, height, width).
fix_img_size : bool
Whether to resize the image to a fixed size. If False, the size_portrait and size_landscape are ignored. Default is False.

Returns

ImageData
ImageData object with image tensor and pil Image.
Expand source code
@Timer("TensorReader.run", "{name}: {milliseconds:.2f} ms", logger=logger.debug)
def run(self, tensor: torch.Tensor, fix_img_size: bool = False) -> ImageData:
    """Reads a tensor and returns a tensor of the image with values between 0-255 and shape (batch, channels, height, width). The order of color channels is RGB. PyTorch and Torchvision are used to read the image.

    Args:
        tensor (torch.Tensor): Tensor of a single image with RGB values between 0-255 and shape (channels, height, width).
        fix_img_size (bool): Whether to resize the image to a fixed size. If False, the size_portrait and size_landscape are ignored. Default is False.

    Returns:
        ImageData: ImageData object with image tensor and pil Image.
    """
    return self.process_tensor(tensor, fix_img_size)

Inherited members