Skip to content

Commit

Permalink
Merge branch 'convex_hull_2d' of https://github.com/neuro-ml/imops in…
Browse files Browse the repository at this point in the history
…to convex_hull_2d
  • Loading branch information
AnihilatorGun committed Dec 2, 2024
2 parents 92e50e8 + 9eee515 commit 52dcb78
Show file tree
Hide file tree
Showing 20 changed files with 120 additions and 108 deletions.
27 changes: 27 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Lint

on: [ pull_request ]

env:
MODULE_NAME: imops

jobs:
lint:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Check python code style
run: |
pip install -r requirements-linters.txt
flake8 .
isort --check .
black --check .
- name: Check Cython code style
run: |
pip install cython-lint
cython-lint imops/src
17 changes: 5 additions & 12 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
needs: [ check_version ]
strategy:
matrix:
os: [ ubuntu-22.04, windows-2019, macOS-12 ]
os: [ ubuntu-22.04, windows-2019, macOS-13 ]

name: Build wheels on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
Expand All @@ -47,17 +47,10 @@ jobs:
python-version: '3.9'
- name: Install cibuildwheel
run: python -m pip install cibuildwheel==2.17.0
- name: Install gcc for mac
if: matrix.os == 'macOS-12'
- name: Install llvm for mac
if: matrix.os == 'macOS-13'
run: |
brew install llvm libomp
echo $PATH
ln -sf /usr/local/bin/gcc-11 /usr/local/bin/gcc
ln -sf /usr/local/bin/g++-11 /usr/local/bin/g++
ls /usr/local/bin/gcc*
ls /usr/local/bin/g++*
gcc --version
g++ --version
brew install llvm
- name: Install g++-11 for ubuntu
if: matrix.os == 'ubuntu-22.04'
id: install_cc
Expand All @@ -79,7 +72,7 @@ jobs:
python -m cibuildwheel --output-dir wheelhouse
env:
CIBW_ENVIRONMENT_MACOS: >
PATH="/usr/local/opt/llvm/bin:$PATH" LDFLAGS="-L/usr/local/opt/llvm/lib" CPPFLAGS="-I/usr/local/opt/llvm/include"
CC="$(brew --prefix llvm)/bin/clang" CXX="$(brew --prefix llvm)/bin/clang++"
CIBW_BUILD: cp37-* cp38-* cp39-* cp310-* cp311-* cp312-*
CIBW_BEFORE_BUILD_LINUX: 'if [ $(python -c "import sys; print(sys.version_info[1])") -ge 9 ]; then python -m pip install "numpy<3.0.0" --config-settings=setup-args="-Dallow-noblas=true"; fi'
- uses: actions/upload-artifact@v3
Expand Down
17 changes: 5 additions & 12 deletions .github/workflows/test_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
build_wheels:
strategy:
matrix:
os: [ubuntu-22.04, windows-2019, macOS-12 ]
os: [ubuntu-22.04, windows-2019, macOS-13 ]

name: Build wheels on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
Expand All @@ -21,17 +21,10 @@ jobs:
python-version: '3.9'
- name: Install cibuildwheel
run: python -m pip install cibuildwheel==2.17.0
- name: Install gcc for mac
if: matrix.os == 'macOS-12'
- name: Install llvm for mac
if: matrix.os == 'macOS-13'
run: |
brew install llvm libomp
echo $PATH
ln -sf /usr/local/bin/gcc-11 /usr/local/bin/gcc
ln -sf /usr/local/bin/g++-11 /usr/local/bin/g++
ls /usr/local/bin/gcc*
ls /usr/local/bin/g++*
gcc --version
g++ --version
brew install llvm
- name: Install g++-11 for ubuntu
if: matrix.os == 'ubuntu-22.04'
id: install_cc
Expand All @@ -53,7 +46,7 @@ jobs:
python -m cibuildwheel --output-dir wheelhouse
env:
CIBW_ENVIRONMENT_MACOS: >
PATH="/usr/local/opt/llvm/bin:$PATH" LDFLAGS="-L/usr/local/opt/llvm/lib" CPPFLAGS="-I/usr/local/opt/llvm/include"
CC="$(brew --prefix llvm)/bin/clang" CXX="$(brew --prefix llvm)/bin/clang++"
CIBW_BUILD: cp37-* cp39-* cp312-*
CIBW_SKIP: "*manylinux_x86_64"
CIBW_BEFORE_BUILD_LINUX: 'if [ $(python -c "import sys; print(sys.version_info[1])") -ge 9 ]; then python -m pip install "numpy<3.0.0" --config-settings=setup-args="-Dallow-noblas=true"; fi'
11 changes: 0 additions & 11 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,6 @@ jobs:
echo $MODULE_PARENT
echo "MODULE_PARENT=$(echo $MODULE_PARENT)" >> $GITHUB_ENV
- name: Check python code style
run: |
pip install -r requirements-linters.txt
flake8 .
isort --check .
black --check .
- name: Check Cython code style
run: |
pip install cython-lint
cython-lint imops/src
- name: Test with pytest
run: |
pytest tests -m "not nonumba" --junitxml=reports/junit-${{ matrix.python-version }}.xml --cov="$MODULE_PARENT/$MODULE_NAME" --cov-report=xml --cov-branch
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ imops/src/_fast*.pyx
dist/
*.so
.vscode/
.idea/
2 changes: 1 addition & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
include *.md
include requirements.txt
include pyproject.toml
include _build_utils.py
recursive-include imops *.py
recursive-include imops/cpp *.h *.hpp *.cpp
exclude tests/*
2 changes: 1 addition & 1 deletion _build_utils.py → imops/_build_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def get_ext_modules():
modules = ['backprojection', 'measure', 'morphology', 'numeric', 'radon', 'zoom', 'convex_hull']

Check warning on line 66 in imops/_build_utils.py

View check run for this annotation

Codecov / codecov/patch

imops/_build_utils.py#L66

Added line #L66 was not covered by tests
modules_to_link_against_numpy_core_math_lib = ['numeric']

src_dir = Path(__file__).parent / name / 'src'
src_dir = Path(__file__).parent / 'src'

Check warning on line 69 in imops/_build_utils.py

View check run for this annotation

Codecov / codecov/patch

imops/_build_utils.py#L69

Added line #L69 was not covered by tests
for module in modules:
# Cython extension and .pyx source file names must be the same to compile
# https://stackoverflow.com/questions/8024805/cython-compiled-c-extension-importerror-dynamic-module-does-not-define-init-fu
Expand Down
10 changes: 10 additions & 0 deletions imops/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,13 @@
from scipy.ndimage._morphology import _ni_support
except ImportError:
from scipy.ndimage.morphology import _ni_support

try:
from scipy.spatial import QhullError
except ImportError:
from scipy.spatial.qhull import QhullError

from scipy.ndimage._nd_image import euclidean_feature_transform # noqa


normalize_sequence = _ni_support._normalize_sequence # noqa
10 changes: 7 additions & 3 deletions imops/crop.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import Optional

import numpy as np

from .backend import BackendLike
Expand All @@ -6,7 +8,9 @@
from .utils import AxesLike, AxesParams, assert_subdtype, broadcast_axis, fill_by_indices


def crop_to_shape(x: np.ndarray, shape: AxesLike, axis: AxesLike = None, ratio: AxesParams = 0.5) -> np.ndarray:
def crop_to_shape(
x: np.ndarray, shape: AxesLike, axis: Optional[AxesLike] = None, ratio: AxesParams = 0.5
) -> np.ndarray:
"""
Crop `x` to match `shape` along `axis`.
Expand Down Expand Up @@ -57,8 +61,8 @@ def crop_to_shape(x: np.ndarray, shape: AxesLike, axis: AxesLike = None, ratio:
def crop_to_box(
x: np.ndarray,
box: np.ndarray,
axis: AxesLike = None,
padding_values: AxesParams = None,
axis: Optional[AxesLike] = None,
padding_values: Optional[AxesParams] = None,
num_threads: int = _NUMERIC_DEFAULT_NUM_THREADS,
backend: BackendLike = None,
) -> np.ndarray:
Expand Down
4 changes: 2 additions & 2 deletions imops/interp1d.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Union
from typing import Optional, Union
from warnings import warn

import numpy as np
Expand Down Expand Up @@ -71,7 +71,7 @@ def __init__(
kind: Union[int, str] = 'linear',
axis: int = -1,
copy: bool = True,
bounds_error: bool = None,
bounds_error: Optional[bool] = None,
fill_value: Union[float, str] = np.nan,
assume_sorted: bool = False,
num_threads: int = -1,
Expand Down
7 changes: 4 additions & 3 deletions imops/interp2d.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from platform import python_version
from typing import Optional

import numpy as np
from scipy.spatial import KDTree
Expand Down Expand Up @@ -47,9 +48,9 @@ class Linear2DInterpolator(Linear2DInterpolatorCpp):
def __init__(
self,
points: np.ndarray,
values: np.ndarray = None,
values: Optional[np.ndarray] = None,
num_threads: int = 1,
triangles: np.ndarray = None,
triangles: Optional[np.ndarray] = None,
**kwargs,
):
if triangles is not None:
Expand Down Expand Up @@ -77,7 +78,7 @@ def __init__(
# FIXME: add backend dispatch
self.num_threads = normalize_num_threads(num_threads, Cython(), warn_stacklevel=3)

def __call__(self, points: np.ndarray, values: np.ndarray = None, fill_value: float = 0.0) -> np.ndarray:
def __call__(self, points: np.ndarray, values: Optional[np.ndarray] = None, fill_value: float = 0.0) -> np.ndarray:
"""
Evaluate the interpolant
Expand Down
12 changes: 6 additions & 6 deletions imops/measure.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from collections import namedtuple
from platform import python_version
from typing import List, NamedTuple, Sequence, Tuple, Union
from typing import List, NamedTuple, Optional, Sequence, Tuple, Union
from warnings import warn

import numpy as np
Expand Down Expand Up @@ -32,12 +32,12 @@
# TODO: Make it work and test on immutable arrays as soon as `cc3d` package is fixed
def label(
label_image: np.ndarray,
background: int = None,
connectivity: int = None,
background: Optional[int] = None,
connectivity: Optional[int] = None,
return_num: bool = False,
return_labels: bool = False,
return_sizes: bool = False,
dtype: type = None,
dtype: Optional[type] = None,
) -> Union[np.ndarray, NamedTuple]:
"""
Fast version of `skimage.measure.label` which optionally returns number of connected components, labels and sizes.
Expand Down Expand Up @@ -139,8 +139,8 @@ def label(

def center_of_mass(
array: np.ndarray,
labels: np.ndarray = None,
index: Union[int, Sequence[int]] = None,
labels: Union[np.ndarray, None] = None,
index: Union[int, Sequence[int], None] = None,
num_threads: int = -1,
backend: BackendLike = None,
) -> Union[Tuple[float, ...], List[Tuple[float, ...]]]:
Expand Down
40 changes: 16 additions & 24 deletions imops/morphology.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,10 @@
from typing import Callable, Tuple, Union
from typing import Callable, Optional, Tuple, Union
from warnings import warn

import numpy as np
from edt import edt
from scipy.ndimage import distance_transform_edt as scipy_distance_transform_edt, generate_binary_structure
from scipy.ndimage._nd_image import euclidean_feature_transform
from scipy.spatial import ConvexHull


try:
from scipy.spatial import QhullError
except ImportError:
from scipy.spatial.qhull import QhullError # Old scipy has another structure

from skimage.morphology import (
binary_closing as scipy_binary_closing,
binary_dilation as scipy_binary_dilation,
Expand All @@ -23,7 +15,7 @@

from .backend import BackendLike, Cython, Scipy, resolve_backend
from .box import add_margin, box_to_shape, mask_to_box, shape_to_box
from .compat import _ni_support
from .compat import QhullError, euclidean_feature_transform, normalize_sequence
from .crop import crop_to_box
from .pad import restore_crop
from .src._convex_hull import _grid_points_in_poly, _left_right_bounds, _offset_unique
Expand All @@ -40,8 +32,8 @@ def morphology_op_wrapper(
) -> Callable:
def wrapped(
image: np.ndarray,
footprint: np.ndarray = None,
output: np.ndarray = None,
footprint: Optional[np.ndarray] = None,
output: Optional[np.ndarray] = None,
boxed: bool = False,
num_threads: int = -1,
backend: BackendLike = None,
Expand Down Expand Up @@ -171,8 +163,8 @@ def wrapped(

def binary_dilation(
image: np.ndarray,
footprint: np.ndarray = None,
output: np.ndarray = None,
footprint: Optional[np.ndarray] = None,
output: Optional[np.ndarray] = None,
boxed: bool = False,
num_threads: int = -1,
backend: BackendLike = None,
Expand Down Expand Up @@ -225,8 +217,8 @@ def binary_dilation(

def binary_erosion(
image: np.ndarray,
footprint: np.ndarray = None,
output: np.ndarray = None,
footprint: Optional[np.ndarray] = None,
output: Optional[np.ndarray] = None,
boxed: bool = False,
num_threads: int = -1,
backend: BackendLike = None,
Expand Down Expand Up @@ -279,8 +271,8 @@ def binary_erosion(

def binary_closing(
image: np.ndarray,
footprint: np.ndarray = None,
output: np.ndarray = None,
footprint: Optional[np.ndarray] = None,
output: Optional[np.ndarray] = None,
boxed: bool = False,
num_threads: int = -1,
backend: BackendLike = None,
Expand Down Expand Up @@ -334,8 +326,8 @@ def binary_closing(

def binary_opening(
image: np.ndarray,
footprint: np.ndarray = None,
output: np.ndarray = None,
footprint: Optional[np.ndarray] = None,
output: Optional[np.ndarray] = None,
boxed: bool = False,
num_threads: int = -1,
backend: BackendLike = None,
Expand Down Expand Up @@ -379,7 +371,7 @@ def binary_opening(

def distance_transform_edt(
image: np.ndarray,
sampling: Tuple[float] = None,
sampling: Optional[Tuple[float]] = None,
return_distances: bool = True,
return_indices: bool = False,
num_threads: int = -1,
Expand Down Expand Up @@ -499,7 +491,7 @@ def distance_transform_edt(
if image.dtype != bool:
image = np.atleast_1d(np.where(image, 1, 0))
if sampling is not None:
sampling = _ni_support._normalize_sequence(sampling, image.ndim)
sampling = normalize_sequence(sampling, image.ndim)
sampling = np.asarray(sampling, dtype=np.float64)
if not sampling.flags.contiguous:
sampling = sampling.copy()
Expand Down Expand Up @@ -529,7 +521,7 @@ def distance_transform_edt(
return None


def convex_hull_image(image, offset_coordinates=True):
def convex_hull_image(image: np.ndarray, offset_coordinates: bool = True) -> np.ndarray:
"""
Fast convex hull of an image. Similar to skimage.morphology.convex_hull_image with include_borders=True
Expand Down Expand Up @@ -560,7 +552,7 @@ def convex_hull_image(image, offset_coordinates=True):

if np.count_nonzero(image) == 0:
warn(
'Input image is entirely zero, no valid convex hull. ' 'Returning empty image',
'Input image is entirely zero, no valid convex hull. Returning empty image',
UserWarning,
)
return np.zeros(image.shape, dtype=bool)
Expand Down
Loading

0 comments on commit 52dcb78

Please sign in to comment.