Source code for caer.io.io
# _____ ______ _____
# / ____/ /\ | ____ | __ \
# | | / \ | |__ | |__) | Caer - Modern Computer Vision
# | | / /\ \ | __| | _ / Languages: Python, C, C++, Cuda
# | |___ / ____ \ | |____ | | \ \ http://github.com/jasmcaus/caer
# \_____\/_/ \_ \______ |_| \_\
# Licensed under the MIT License <http://opensource.org/licenses/MIT>
# SPDX-License-Identifier: MIT
# Copyright (c) 2020-2021 The Caer Authors <http://github.com/jasmcaus>
import cv2 as cv
import numpy as np
from urllib.request import urlopen
# from urllib.error import URLError
from .resize import resize
from ..coreten import to_tensor, Tensor
from ..color import rgb2bgr, to_bgr
from ..path import exists
from .._internal import _check_target_size
from typing import Tuple, Optional, Union
__all__ = [
"imread",
"imsave"
]
IMREAD_COLOR = 1
[docs]def imread(
image_path: str,
rgb: bool = True,
target_size: Optional[Tuple[int, int]] = None,
resize_factor: Optional[Union[float, Tuple]] = None,
preserve_aspect_ratio: bool = False,
interpolation: str = "bilinear",
) -> Tensor:
r"""
Loads in an image from `image_path` (can be either a system filepath or a URL)
Args:
image_path (str): Filepath/URL to read the image from.
rgb (bool): Boolean to keep RGB ordering. Default: True
target_size (tuple): Size of the target image
resize_factor (float, tuple): Resizing Factor to employ.
Shrinks the image if ``resize_factor < 1``
Enlarges the image if ``resize_factor > 1``
preserve_aspect_ration (bool): Prevent aspect ratio distortion (employs center crop). Default:False
Returns:
Tensor with shape ``(height, width, channels)``.
Examples::
>> tens = caer.imread(tens_path) # From FilePath
>> tens.shape
(427, 640, 3)
>> tens = caer.imread('https://raw.githubusercontent.com/jasmcaus/caer/master/caer/data/beverages.jpg') # From URL
>> tens.shape
(427, 640, 3)
"""
return _imread(image_path,rgb=rgb,target_size=target_size,resize_factor=resize_factor,preserve_aspect_ratio=preserve_aspect_ratio,interpolation=interpolation,)
def _imread(
image_path,
rgb: bool = True,
target_size=None,
resize_factor=None,
preserve_aspect_ratio=False,
interpolation: str = "bilinear"
) -> Tensor:
if target_size is not None:
_check_target_size(target_size)
# if not isinstance(channels, int) or channels not in [1, 3]:
# raise ValueError("channels must be an integer - 1 (Grayscale) or 3 (RGB)")
interpolation_methods = {
'nearest': 0, '0': 0, 0: 0, # 0
'bilinear': 1, '1': 1, 1: 1, # 1
'bicubic': 2, '2': 2, 2: 2, # 2
'area': 3, '3': 3, 3: 3, # 3
}
if interpolation not in interpolation_methods:
raise ValueError("Specify a valid interpolation type - area/nearest/bicubic/bilinear")
if exists(image_path):
tens = _read_image(image_path) # returns RGB
# TODO: Create URL validator
elif image_path.startswith(('http://", "https://')):
# Returns RGB image
tens = _url_to_image(image_path)
# If the URL is valid, but no image at that URL, NoneType is returned
if tens is None:
raise ValueError("The URL specified does not point to an image")
else:
raise ValueError("Specify either a valid URL or filepath")
# try:
# # Returns RGB image
# tens = _url_to_image(image_path)
# # If the URL is valid, but no image at that URL, NoneType is returned
# if tens is None:
# raise ValueError("The URL specified does not point to an image")
# # return tens
# # If the URL is invalid
# except (Exception, URLError):
# if exists(image_path):
# tens = _read_image(image_path) # returns RGB
# else:
# raise ValueError("Specify either a valid URL or filepath")
if target_size is not None or resize_factor is not None:
# Enforce a Tensor is passed to resize()
to_tensor(tens, cspace="rgb")
tens = resize(tens,target_size,resize_factor=resize_factor,preserve_aspect_ratio=preserve_aspect_ratio,interpolation=interpolation,)
# If `rgb=False`, then we assume that BGR is expected
if not rgb:
tens = rgb2bgr(tens)
# We need to convert back to tensor
return to_tensor(tens, cspace="bgr")
return to_tensor(tens, cspace="rgb")
def _read_image(image_path: str) -> np.ndarray:
r"""
Returns an RGB ndarray
Args:
image_path (str): Filepath/URL to read the image from.
"""
if not exists(image_path):
raise FileNotFoundError("The image file was not found")
# BGR image
tens = cv.imread(image_path)
# Convert to RGB
# WARNING: DO NOT USE to_rgb() as it creates a brand new Tensor (which defaults to RGB)
# This issue will, hopefully, be fixed in a future update.
# tens = to_rgb(tens)
return cv.cvtColor(tens, cv.COLOR_BGR2RGB)
def _url_to_image(url: str) -> np.ndarray:
r"""
Returns an RGB ndarray.
"""
response = urlopen(url)
tens = np.asarray(bytearray(response.read()), dtype="uint8")
# BGR image
tens = cv.imdecode(tens, IMREAD_COLOR)
if tens is not None:
return cv.cvtColor(tens, cv.COLOR_BGR2RGB)
else:
raise ValueError(f"No image found at '{url}'")
[docs]def imsave(path: str, tens: Tensor) -> bool:
r"""
Saves a Tensor to `path`
Args:
path (str): Filepath to save the image to
Returns
``True``; if `tens` was written to `path`
``False``; otherwise
Examples::
>> tens = caer.data.audio_mixer()
>> caer.imsave("audio_mixer.png", tens)
True
"""
if not isinstance(tens, Tensor):
raise TypeError("`tens` must be a caer.Tensor")
# Convert to tensor
tens._nullprt() # raises a ValueError if we're dealing with a Foreign Tensor with illegal `.cspace` value
try:
# OpenCV uses BGR Tensors and saves them as RGB images
if tens.cspace != "bgr":
tens = to_bgr(tens) # type: ignore
return cv.imwrite(path, tens)
except:
raise ValueError(
"`tens` needs to be a caer Tensor. Try reading the image using `caer.imread()`."
"More support for additional platforms will follow. Check the Changelog for further details."
)