Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch default resize backend #715

Merged
merged 2 commits into from
Aug 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions eolearn/features/feature_manipulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ def __init__(
width_param: float,
features: FeaturesSpecification = ...,
resize_method: ResizeMethod = ResizeMethod.LINEAR,
resize_library: ResizeLib = ResizeLib.PIL,
resize_library: ResizeLib = ResizeLib.CV2,
):
"""
:param features: Which features to resize. Supports new names for features.
Expand All @@ -271,8 +271,8 @@ def __init__(
:param height_param: Parameter to be applied to the height in combination with the resize_type
:param width_param: Parameter to be applied to the width in combination with the resize_type
:param resize_method: Interpolation method used for resizing.
:param resize_library: Which Python library to use for resizing. Default is PIL, as it supports all dtypes and
features anti-aliasing. For cases where execution speed is crucial one can use CV2.
:param resize_library: Which Python library to use for resizing. Default is CV2 because it is faster, but one
can use PIL, which features anti-aliasing.
"""
self.features = features
self.resize_type = ResizeParam(resize_type)
Expand Down
31 changes: 18 additions & 13 deletions eolearn/features/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,18 @@
import warnings
from enum import Enum
from functools import partial
from typing import TYPE_CHECKING

import cv2
import numpy as np
from PIL import Image

from eolearn.core.exceptions import EORuntimeWarning
from eolearn.core.utils.common import _apply_to_spatial_axes

_CV2_IMPORT_MESSAGE = "The CV2 backend is not installed by default. We suggest you install the `opencv-python` package."
_PIL_IMPORT_MESSAGE = "The PIL backend is not installed by default. Please install the `pillow` package."

if TYPE_CHECKING:
from PIL import Image


class ResizeParam(Enum):
Expand All @@ -38,10 +42,7 @@ class ResizeMethod(Enum):

def get_cv2_method(self, dtype: np.dtype | type) -> int:
"""Obtain the constant specifying the interpolation method for the CV2 library."""
try:
import cv2 # pylint: disable=import-outside-toplevel
except ImportError as exception:
raise ImportError(_CV2_IMPORT_MESSAGE) from exception

number_dtype = np.dtype(dtype)
if np.issubdtype(number_dtype, np.floating):
choices = {
Expand All @@ -64,6 +65,10 @@ def get_cv2_method(self, dtype: np.dtype | type) -> int:

def get_pil_method(self) -> Image.Resampling:
"""Obtain the constant specifying the interpolation method for the PIL library."""
try:
from PIL import Image # pylint: disable=import-outside-toplevel
except ImportError as exception:
raise ImportError(_PIL_IMPORT_MESSAGE) from exception
choices = {
ResizeMethod.NEAREST: Image.Resampling.NEAREST,
ResizeMethod.LINEAR: Image.Resampling.BILINEAR,
Expand Down Expand Up @@ -113,7 +118,7 @@ def spatially_resize_image(
scale_factors: tuple[float, float] | None = None,
spatial_axes: tuple[int, int] | None = None,
resize_method: ResizeMethod = ResizeMethod.LINEAR,
resize_library: ResizeLib = ResizeLib.PIL,
resize_library: ResizeLib = ResizeLib.CV2,
) -> np.ndarray:
"""Resizes the image(s) according to given size or scale factors.

Expand All @@ -125,8 +130,8 @@ def spatially_resize_image(
:param spatial_axes: Which two axes of input data represent height and width. If left as `None` they are selected
according to standards of eo-learn features.
:param resize_method: Interpolation method used for resizing.
:param resize_library: Which Python library to use for resizing. Default is PIL, as it supports all dtypes and
features anti-aliasing. For cases where execution speed is crucial one can use CV2.
:param resize_library: Which Python library to use for resizing. Default is CV2 because it is faster, but one can
use PIL, which features anti-aliasing.
"""

resize_method = ResizeMethod(resize_method)
Expand Down Expand Up @@ -154,10 +159,6 @@ def spatially_resize_image(
data = data.astype(new_dtype)

if resize_library is ResizeLib.CV2:
try:
import cv2 # pylint: disable=import-outside-toplevel
except ImportError as exception:
raise ImportError(_CV2_IMPORT_MESSAGE) from exception
resize_function = partial(cv2.resize, dsize=size, interpolation=resize_method.get_cv2_method(data.dtype))
else:
resize_function = partial(_pil_resize_ndarray, size=size, method=resize_method.get_pil_method())
Expand All @@ -171,4 +172,8 @@ def spatially_resize_image(


def _pil_resize_ndarray(image: np.ndarray, size: tuple[int, int], method: Image.Resampling) -> np.ndarray:
try:
from PIL import Image # pylint: disable=import-outside-toplevel
except ImportError as exception:
raise ImportError(_PIL_IMPORT_MESSAGE) from exception
return np.array(Image.fromarray(image).resize(size, method))
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ coregistration = [
] # using headless version of opencv, otherwise gitlab runners fail
features = [
"numba>=0.53.0",
"pillow>=9.1.0",
"opencv-python-headless",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice

"scikit-image>=0.19.0",
"scikit-learn",
"scipy",
Expand Down