Skip to content

Commit

Permalink
Merge pull request #63 from neuro-ml/convex_hull_2d
Browse files Browse the repository at this point in the history
20x fast convex_hull_image for 2D
  • Loading branch information
vovaf709 authored Dec 4, 2024
2 parents 8fa3f5b + aa5deac commit 331f68a
Show file tree
Hide file tree
Showing 24 changed files with 570 additions and 101 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: 2 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ pip install imops[numba] # additionally install Numba backend

::: imops.morphology.distance_transform_edt

::: imops.morphology.convex_hull_image

::: imops.measure.label

::: imops.measure.center_of_mass
Expand Down
2 changes: 1 addition & 1 deletion imops/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '0.9.0'
__version__ = '0.9.1'
4 changes: 2 additions & 2 deletions _build_utils.py → imops/_build_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,10 @@ def get_ext_modules():
'/O3' if on_windows else '-O3',
] # FIXME: account for higher gcc versions

modules = ['backprojection', 'measure', 'morphology', 'numeric', 'radon', 'zoom']
modules = ['backprojection', 'measure', 'morphology', 'numeric', 'radon', 'zoom', 'convex_hull']
modules_to_link_against_numpy_core_math_lib = ['numeric']

src_dir = Path(__file__).parent / name / 'src'
src_dir = Path(__file__).parent / 'src'
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
Loading

0 comments on commit 331f68a

Please sign in to comment.