torch-transform-image 0.0.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,11 @@
1
+ # Do not edit - changes here will be overwritten by Copier
2
+ _commit: v1
3
+ _src_path: gh:pydev-guide/pyrepo-copier
4
+ author_email: alisterburt@gmail.com
5
+ author_name: Alister Burt
6
+ github_username: teamtomo
7
+ mode: simple
8
+ module_name: torch_transform_image
9
+ project_name: torch-transform-image
10
+ project_short_description: Real space transformations of 2D/3D images in PyTorch
11
+
@@ -0,0 +1,15 @@
1
+ * torch-transform-image version:
2
+ * Python version:
3
+ * Operating System:
4
+
5
+ ### Description
6
+
7
+ Describe what you were trying to get done.
8
+ Tell us what happened, what went wrong, and what you expected to happen.
9
+
10
+ ### What I Did
11
+
12
+ ```
13
+ Paste the command(s) you ran and the output.
14
+ If there was a crash, please include the traceback here.
15
+ ```
@@ -0,0 +1,12 @@
1
+ ---
2
+ title: "{{ env.TITLE }}"
3
+ labels: [bug]
4
+ ---
5
+ The {{ workflow }} workflow failed on {{ date | date("YYYY-MM-DD HH:mm") }} UTC
6
+
7
+ The most recent failing test was on {{ env.PLATFORM }} py{{ env.PYTHON }}
8
+ with commit: {{ sha }}
9
+
10
+ Full run: https://github.com/{{ repo }}/actions/runs/{{ env.RUN_ID }}
11
+
12
+ (This post will be updated if another test fails, as long as this issue remains open.)
@@ -0,0 +1,10 @@
1
+ # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
2
+
3
+ version: 2
4
+ updates:
5
+ - package-ecosystem: "github-actions"
6
+ directory: "/"
7
+ schedule:
8
+ interval: "weekly"
9
+ commit-message:
10
+ prefix: "ci(dependabot):"
@@ -0,0 +1,83 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ tags:
8
+ - "v*"
9
+ pull_request:
10
+ workflow_dispatch:
11
+
12
+
13
+ # cancel in-progress runs that use the same workflow and branch
14
+ concurrency:
15
+ group: ${{ github.workflow }}-${{ github.ref }}
16
+ cancel-in-progress: true
17
+
18
+ jobs:
19
+ test:
20
+ name: ${{ matrix.platform }} (${{ matrix.python-version }})
21
+ runs-on: ${{ matrix.platform }}
22
+ strategy:
23
+ fail-fast: false
24
+ matrix:
25
+ python-version: [ "3.10", "3.11", "3.12" ] # , "3.13"]
26
+ platform: [ ubuntu-latest, macos-latest ] # windows-latest]
27
+
28
+ steps:
29
+ - uses: actions/checkout@v4
30
+
31
+ - name: 🐍 Set up Python ${{ matrix.python-version }}
32
+ uses: actions/setup-python@v5
33
+ with:
34
+ python-version: ${{ matrix.python-version }}
35
+ cache-dependency-path: "pyproject.toml"
36
+ cache: "pip"
37
+
38
+ - name: Install Dependencies
39
+ run: |
40
+ python -m pip install -U pip
41
+ python -m pip install .[test]
42
+
43
+ - name: 🧪 Run Tests
44
+ run: pytest --color=yes --cov --cov-report=xml --cov-report=term-missing
45
+
46
+ - name: Coverage
47
+ uses: codecov/codecov-action@v5
48
+
49
+ deploy:
50
+ name: Deploy
51
+ needs: test
52
+ if: success() && startsWith(github.ref, 'refs/tags/')
53
+ runs-on: ubuntu-latest
54
+
55
+ permissions:
56
+ # IMPORTANT: this permission is mandatory for trusted publishing on PyPi
57
+ # see https://docs.pypi.org/trusted-publishers/
58
+ id-token: write
59
+ # This permission allows writing releases
60
+ contents: write
61
+
62
+ steps:
63
+ - uses: actions/checkout@v4
64
+ with:
65
+ fetch-depth: 0
66
+
67
+ - name: 🐍 Set up Python
68
+ uses: actions/setup-python@v5
69
+ with:
70
+ python-version: "3.x"
71
+
72
+ - name: 👷 Build
73
+ run: |
74
+ python -m pip install build
75
+ python -m build
76
+
77
+ - name: 🚢 Publish to PyPI
78
+ uses: pypa/gh-action-pypi-publish@release/v1
79
+
80
+ - uses: softprops/action-gh-release@v2
81
+ with:
82
+ generate_release_notes: true
83
+ files: './dist/*'
@@ -0,0 +1,111 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ env/
12
+ build/
13
+ develop-eggs/
14
+ dist/
15
+ downloads/
16
+ eggs/
17
+ .eggs/
18
+ lib/
19
+ lib64/
20
+ parts/
21
+ sdist/
22
+ var/
23
+ wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+
28
+ .DS_Store
29
+
30
+ # PyInstaller
31
+ # Usually these files are written by a python script from a template
32
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
33
+ *.manifest
34
+ *.spec
35
+
36
+ # Installer logs
37
+ pip-log.txt
38
+ pip-delete-this-directory.txt
39
+
40
+ # Unit test / coverage reports
41
+ htmlcov/
42
+ .tox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ .hypothesis/
50
+ .pytest_cache/
51
+
52
+ # Translations
53
+ *.mo
54
+ *.pot
55
+
56
+ # Django stuff:
57
+ *.log
58
+ local_settings.py
59
+
60
+ # Flask stuff:
61
+ instance/
62
+ .webassets-cache
63
+
64
+ # Scrapy stuff:
65
+ .scrapy
66
+
67
+ # Sphinx documentation
68
+ docs/_build/
69
+
70
+ # PyBuilder
71
+ target/
72
+
73
+ # Jupyter Notebook
74
+ .ipynb_checkpoints
75
+
76
+ # pyenv
77
+ .python-version
78
+
79
+ # celery beat schedule file
80
+ celerybeat-schedule
81
+
82
+ # SageMath parsed files
83
+ *.sage.py
84
+
85
+ # dotenv
86
+ .env
87
+
88
+ # virtualenv
89
+ .venv
90
+ venv/
91
+ ENV/
92
+
93
+ # Spyder project settings
94
+ .spyderproject
95
+ .spyproject
96
+
97
+ # Rope project settings
98
+ .ropeproject
99
+
100
+ # mkdocs documentation
101
+ /site
102
+
103
+ # mypy
104
+ .mypy_cache/
105
+
106
+ # ruff
107
+ .ruff_cache/
108
+
109
+ # IDE settings
110
+ .vscode/
111
+ .idea/
@@ -0,0 +1,28 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2023, Alister Burt
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,157 @@
1
+ Metadata-Version: 2.4
2
+ Name: torch-transform-image
3
+ Version: 0.0.2
4
+ Summary: Real space transformations of 2D/3D images in PyTorch
5
+ Project-URL: homepage, https://github.com/teamtomo/torch-transform-image
6
+ Project-URL: repository, https://github.com/teamtomo/torch-transform-image
7
+ Author-email: Alister Burt <alisterburt@gmail.com>
8
+ License: BSD-3-Clause
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: License :: OSI Approved :: BSD License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Typing :: Typed
19
+ Requires-Python: >=3.9
20
+ Requires-Dist: torch
21
+ Requires-Dist: torch-affine-utils
22
+ Requires-Dist: torch-grid-utils
23
+ Requires-Dist: torch-image-interpolation
24
+ Provides-Extra: dev
25
+ Requires-Dist: ipython; extra == 'dev'
26
+ Requires-Dist: pdbpp; extra == 'dev'
27
+ Requires-Dist: rich; extra == 'dev'
28
+ Provides-Extra: test
29
+ Requires-Dist: pytest; extra == 'test'
30
+ Requires-Dist: pytest-cov; extra == 'test'
31
+ Description-Content-Type: text/markdown
32
+
33
+ # torch-transform-image
34
+
35
+ [![License](https://img.shields.io/pypi/l/torch-transform-image.svg?color=green)](https://github.com/teamtomo/torch-transform-image/raw/main/LICENSE)
36
+ [![PyPI](https://img.shields.io/pypi/v/torch-transform-image.svg?color=green)](https://pypi.org/project/torch-transform-image)
37
+ [![Python Version](https://img.shields.io/pypi/pyversions/torch-transform-image.svg?color=green)](https://python.org)
38
+ [![CI](https://github.com/teamtomo/torch-transform-image/actions/workflows/ci.yml/badge.svg)](https://github.com/teamtomo/torch-transform-image/actions/workflows/ci.yml)
39
+ [![codecov](https://codecov.io/gh/teamtomo/torch-transform-image/branch/main/graph/badge.svg)](https://codecov.io/gh/teamtomo/torch-transform-image)
40
+
41
+ Real space transformations of 2D/3D images in PyTorch
42
+
43
+ ## Motivation
44
+
45
+ This package provides a simple, consistent API for applying affine transformations to 2D/3D images in PyTorch.
46
+ It enables efficient, GPU-accelerated geometric transformations of images.
47
+
48
+ ## Installation
49
+
50
+ ```bash
51
+ pip install torch-transform-image
52
+ ```
53
+
54
+ ## Features
55
+
56
+ - Apply arbitrary affine transformations to 2D and 3D images
57
+ - Support for various interpolation methods (nearest, bilinear, bicubic for 2D; nearest, trilinear for 3D)
58
+ - Batched operations for efficient processing
59
+ - Fully differentiable operations compatible with PyTorch's autograd
60
+
61
+ ## Coordinate System
62
+
63
+ This package uses the same coordinate system as NumPy/PyTorch array indexing:
64
+ - For 2D images: coordinates are ordered as `[y, x]` for dimensions `(height, width)`
65
+ - For 3D images: coordinates are ordered as `[z, y, x]` for dimensions `(depth, height, width)`
66
+
67
+ Transformation matrices left-multiply homogeneous pixel coordinates (`[y, x, 1]` for 2D and `[z, y, x, 1]` for 3D).
68
+
69
+ ### Generating Transformation Matrices
70
+
71
+ The companion package [torch-affine-utils](https://github.com/teamtomo/torch-affine-utils) provides convenient functions
72
+ to generate transformation matrices that work with homogenous pixel coordinates (`yxw`/`zyxw`):
73
+
74
+ ```python
75
+ from torch_affine_utils.transforms_2d import R, T, S # Rotation, Translation, Scale for 2D
76
+ from torch_affine_utils.transforms_3d import Rx, Ry, Rz, T, S # Rotation, Translation, Scale for 3D
77
+ ```
78
+
79
+ ## Usage
80
+
81
+ ### 2D Transformations
82
+
83
+ ```python
84
+ import torch
85
+ from torch_transform_image import affine_transform_image_2d
86
+ from torch_affine_utils.transforms_2d import R, T, S # Rotation, Translation, Scale
87
+
88
+ # Create a test image (28×28)
89
+ image = torch.zeros((28, 28), dtype=torch.float32)
90
+ image[14, 14] = 1 # Place a dot at the center
91
+
92
+ # Create a transformation matrix to translate coordinates 4 pixels in y direction
93
+ translation = T([4, 0]) # Uses [y, x] coordinate order matching dimensions (h, w)
94
+
95
+ # Apply the transformation
96
+ result = affine_transform_image_2d(
97
+ image=image,
98
+ matrices=translation,
99
+ interpolation='bilinear', # Options: 'nearest', 'bilinear', 'bicubic'
100
+ yx_matrices=True, # The generated translations have [y, x] order
101
+ )
102
+
103
+ # Compose multiple transformations
104
+ # First translate to origin, then rotate, then translate back
105
+ T1 = T([-14, -14]) # Move center to origin
106
+ R1 = R(45, yx=True) # Rotate 45 degrees
107
+ T2 = T([14, 14]) # Move back
108
+ transform = T2 @ R1 @ T1 # Matrix composition (applied right-to-left)
109
+
110
+ # Apply the composed transformation
111
+ rotated = affine_transform_image_2d(
112
+ image=image,
113
+ matrices=transform,
114
+ interpolation='bicubic',
115
+ yx_matrices=True,
116
+ )
117
+ ```
118
+
119
+ ### 3D Transformations
120
+
121
+ ```python
122
+ import torch
123
+ from torch_transform_image import affine_transform_image_3d
124
+ from torch_affine_utils.transforms_3d import R, T, S # Rotation, Translation, Scale
125
+
126
+ # Create a test volume (64×64×64)
127
+ volume = torch.zeros((64, 64, 64), dtype=torch.float32)
128
+ volume[32, 32, 32] = 1 # Place a dot at the center
129
+
130
+ # Create a transformation matrix (translate coordinates 5 voxels in z direction)
131
+ translation = T([5, 0, 0]) # Uses [z, y, x] coordinate order matching dimensions (d, h, w)
132
+
133
+ # Apply the transformation
134
+ result = affine_transform_image_3d(
135
+ image=volume,
136
+ matrices=translation,
137
+ interpolation='trilinear', # Options: 'nearest', 'trilinear'
138
+ zyx_matrices=True, # The generated translations have [z, y, x] order
139
+ )
140
+ ```
141
+
142
+ ## How It Works
143
+
144
+ Under the hood, the package:
145
+ 1. Creates a coordinate grid for the input image
146
+ 2. Applies the transformation matrix to these coordinates
147
+ 3. Samples the original image at the transformed coordinates using the specified interpolation method
148
+
149
+ All operations are performed in PyTorch, making them fully differentiable and GPU-compatible.
150
+
151
+ ## License
152
+
153
+ This project is licensed under the BSD 3-Clause License - see the LICENSE file for details.
154
+
155
+ ## Contributing
156
+
157
+ Contributions are welcome! Please feel free to submit a Pull Request.
@@ -0,0 +1,125 @@
1
+ # torch-transform-image
2
+
3
+ [![License](https://img.shields.io/pypi/l/torch-transform-image.svg?color=green)](https://github.com/teamtomo/torch-transform-image/raw/main/LICENSE)
4
+ [![PyPI](https://img.shields.io/pypi/v/torch-transform-image.svg?color=green)](https://pypi.org/project/torch-transform-image)
5
+ [![Python Version](https://img.shields.io/pypi/pyversions/torch-transform-image.svg?color=green)](https://python.org)
6
+ [![CI](https://github.com/teamtomo/torch-transform-image/actions/workflows/ci.yml/badge.svg)](https://github.com/teamtomo/torch-transform-image/actions/workflows/ci.yml)
7
+ [![codecov](https://codecov.io/gh/teamtomo/torch-transform-image/branch/main/graph/badge.svg)](https://codecov.io/gh/teamtomo/torch-transform-image)
8
+
9
+ Real space transformations of 2D/3D images in PyTorch
10
+
11
+ ## Motivation
12
+
13
+ This package provides a simple, consistent API for applying affine transformations to 2D/3D images in PyTorch.
14
+ It enables efficient, GPU-accelerated geometric transformations of images.
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ pip install torch-transform-image
20
+ ```
21
+
22
+ ## Features
23
+
24
+ - Apply arbitrary affine transformations to 2D and 3D images
25
+ - Support for various interpolation methods (nearest, bilinear, bicubic for 2D; nearest, trilinear for 3D)
26
+ - Batched operations for efficient processing
27
+ - Fully differentiable operations compatible with PyTorch's autograd
28
+
29
+ ## Coordinate System
30
+
31
+ This package uses the same coordinate system as NumPy/PyTorch array indexing:
32
+ - For 2D images: coordinates are ordered as `[y, x]` for dimensions `(height, width)`
33
+ - For 3D images: coordinates are ordered as `[z, y, x]` for dimensions `(depth, height, width)`
34
+
35
+ Transformation matrices left-multiply homogeneous pixel coordinates (`[y, x, 1]` for 2D and `[z, y, x, 1]` for 3D).
36
+
37
+ ### Generating Transformation Matrices
38
+
39
+ The companion package [torch-affine-utils](https://github.com/teamtomo/torch-affine-utils) provides convenient functions
40
+ to generate transformation matrices that work with homogenous pixel coordinates (`yxw`/`zyxw`):
41
+
42
+ ```python
43
+ from torch_affine_utils.transforms_2d import R, T, S # Rotation, Translation, Scale for 2D
44
+ from torch_affine_utils.transforms_3d import Rx, Ry, Rz, T, S # Rotation, Translation, Scale for 3D
45
+ ```
46
+
47
+ ## Usage
48
+
49
+ ### 2D Transformations
50
+
51
+ ```python
52
+ import torch
53
+ from torch_transform_image import affine_transform_image_2d
54
+ from torch_affine_utils.transforms_2d import R, T, S # Rotation, Translation, Scale
55
+
56
+ # Create a test image (28×28)
57
+ image = torch.zeros((28, 28), dtype=torch.float32)
58
+ image[14, 14] = 1 # Place a dot at the center
59
+
60
+ # Create a transformation matrix to translate coordinates 4 pixels in y direction
61
+ translation = T([4, 0]) # Uses [y, x] coordinate order matching dimensions (h, w)
62
+
63
+ # Apply the transformation
64
+ result = affine_transform_image_2d(
65
+ image=image,
66
+ matrices=translation,
67
+ interpolation='bilinear', # Options: 'nearest', 'bilinear', 'bicubic'
68
+ yx_matrices=True, # The generated translations have [y, x] order
69
+ )
70
+
71
+ # Compose multiple transformations
72
+ # First translate to origin, then rotate, then translate back
73
+ T1 = T([-14, -14]) # Move center to origin
74
+ R1 = R(45, yx=True) # Rotate 45 degrees
75
+ T2 = T([14, 14]) # Move back
76
+ transform = T2 @ R1 @ T1 # Matrix composition (applied right-to-left)
77
+
78
+ # Apply the composed transformation
79
+ rotated = affine_transform_image_2d(
80
+ image=image,
81
+ matrices=transform,
82
+ interpolation='bicubic',
83
+ yx_matrices=True,
84
+ )
85
+ ```
86
+
87
+ ### 3D Transformations
88
+
89
+ ```python
90
+ import torch
91
+ from torch_transform_image import affine_transform_image_3d
92
+ from torch_affine_utils.transforms_3d import R, T, S # Rotation, Translation, Scale
93
+
94
+ # Create a test volume (64×64×64)
95
+ volume = torch.zeros((64, 64, 64), dtype=torch.float32)
96
+ volume[32, 32, 32] = 1 # Place a dot at the center
97
+
98
+ # Create a transformation matrix (translate coordinates 5 voxels in z direction)
99
+ translation = T([5, 0, 0]) # Uses [z, y, x] coordinate order matching dimensions (d, h, w)
100
+
101
+ # Apply the transformation
102
+ result = affine_transform_image_3d(
103
+ image=volume,
104
+ matrices=translation,
105
+ interpolation='trilinear', # Options: 'nearest', 'trilinear'
106
+ zyx_matrices=True, # The generated translations have [z, y, x] order
107
+ )
108
+ ```
109
+
110
+ ## How It Works
111
+
112
+ Under the hood, the package:
113
+ 1. Creates a coordinate grid for the input image
114
+ 2. Applies the transformation matrix to these coordinates
115
+ 3. Samples the original image at the transformed coordinates using the specified interpolation method
116
+
117
+ All operations are performed in PyTorch, making them fully differentiable and GPU-compatible.
118
+
119
+ ## License
120
+
121
+ This project is licensed under the BSD 3-Clause License - see the LICENSE file for details.
122
+
123
+ ## Contributing
124
+
125
+ Contributions are welcome! Please feel free to submit a Pull Request.
@@ -0,0 +1,102 @@
1
+ # https://peps.python.org/pep-0517/
2
+ [build-system]
3
+ requires = ["hatchling", "hatch-vcs"]
4
+ build-backend = "hatchling.build"
5
+
6
+ # https://hatch.pypa.io/latest/config/metadata/
7
+ [tool.hatch.version]
8
+ source = "vcs"
9
+
10
+ # read more about configuring hatch at:
11
+ # https://hatch.pypa.io/latest/config/build/
12
+ [tool.hatch.build.targets.wheel]
13
+ only-include = ["src"]
14
+ sources = ["src"]
15
+
16
+ # https://peps.python.org/pep-0621/
17
+ [project]
18
+ name = "torch-transform-image"
19
+ dynamic = ["version"]
20
+ description = "Real space transformations of 2D/3D images in PyTorch"
21
+ readme = "README.md"
22
+ requires-python = ">=3.9"
23
+ license = { text = "BSD-3-Clause" }
24
+ authors = [{ name = "Alister Burt", email = "alisterburt@gmail.com" }]
25
+ # https://pypi.org/classifiers/
26
+ classifiers = [
27
+ "Development Status :: 3 - Alpha",
28
+ "License :: OSI Approved :: BSD License",
29
+ "Programming Language :: Python :: 3",
30
+ "Programming Language :: Python :: 3.9",
31
+ "Programming Language :: Python :: 3.10",
32
+ "Programming Language :: Python :: 3.11",
33
+ "Programming Language :: Python :: 3.12",
34
+ "Programming Language :: Python :: 3.13",
35
+ "Typing :: Typed",
36
+ ]
37
+ # add your package dependencies here
38
+ dependencies = [
39
+ "torch",
40
+ "torch-image-interpolation",
41
+ "torch-grid-utils",
42
+ "torch-affine-utils",
43
+ ]
44
+
45
+ # https://peps.python.org/pep-0621/#dependencies-optional-dependencies
46
+ # "extras" (e.g. for `pip install .[test]`)
47
+ [project.optional-dependencies]
48
+ # add dependencies used for testing here
49
+ test = ["pytest", "pytest-cov"]
50
+ # add anything else you like to have in your dev environment here
51
+ dev = [
52
+ "ipython",
53
+ "pdbpp", # https://github.com/pdbpp/pdbpp
54
+ "rich", # https://github.com/Textualize/rich
55
+ ]
56
+
57
+ [project.urls]
58
+ homepage = "https://github.com/teamtomo/torch-transform-image"
59
+ repository = "https://github.com/teamtomo/torch-transform-image"
60
+
61
+ # Entry points
62
+ # https://peps.python.org/pep-0621/#entry-points
63
+ # same as console_scripts entry point
64
+ # [project.scripts]
65
+ # torch-transform-image-cli = "torch_transform_image:main_cli"
66
+
67
+ # [project.entry-points."some.group"]
68
+ # tomatoes = "torch_transform_image:main_tomatoes"
69
+
70
+
71
+
72
+ # https://docs.pytest.org/
73
+ [tool.pytest.ini_options]
74
+ minversion = "7.0"
75
+ testpaths = ["tests"]
76
+ filterwarnings = ["error"]
77
+
78
+ # https://coverage.readthedocs.io/
79
+ [tool.coverage.report]
80
+ show_missing = true
81
+ exclude_lines = [
82
+ "pragma: no cover",
83
+ "if TYPE_CHECKING:",
84
+ "@overload",
85
+ "except ImportError",
86
+ "\\.\\.\\.",
87
+ "raise NotImplementedError()",
88
+ "pass",
89
+ ]
90
+
91
+ [tool.coverage.run]
92
+ source = ["torch_transform_image"]
93
+
94
+ # https://github.com/mgedmin/check-manifest#configuration
95
+ # add files that you want check-manifest to explicitly ignore here
96
+ # (files that are in the repo but shouldn't go in the package)
97
+ [tool.check-manifest]
98
+ ignore = [
99
+ ".pre-commit-config.yaml",
100
+ ".ruff_cache/**/*",
101
+ "tests/**/*",
102
+ ]
@@ -0,0 +1,18 @@
1
+ """Real space transformations of 2D/3D images in PyTorch"""
2
+
3
+ from importlib.metadata import PackageNotFoundError, version
4
+
5
+ try:
6
+ __version__ = version("torch-transform-image")
7
+ except PackageNotFoundError:
8
+ __version__ = "uninstalled"
9
+ __author__ = "Alister Burt"
10
+ __email__ = "alisterburt@gmail.com"
11
+
12
+ from torch_transform_image.transforms_2d import affine_transform_image_2d
13
+ from torch_transform_image.transforms_3d import affine_transform_image_3d
14
+
15
+ __all__ = [
16
+ 'affine_transform_image_2d',
17
+ 'affine_transform_image_3d',
18
+ ]
@@ -0,0 +1,5 @@
1
+ You may remove this file if you don't intend to add types to your package
2
+
3
+ Details at:
4
+
5
+ https://mypy.readthedocs.io/en/stable/installed_packages.html#creating-pep-561-compatible-packages
@@ -0,0 +1,36 @@
1
+ from typing import Literal
2
+
3
+ import einops
4
+ import torch
5
+ from torch_affine_utils import homogenise_coordinates
6
+ from torch_grid_utils import coordinate_grid
7
+ from torch_image_interpolation import sample_image_2d
8
+
9
+
10
+ def affine_transform_image_2d(
11
+ image: torch.Tensor,
12
+ matrices: torch.Tensor,
13
+ interpolation: Literal['nearest', 'bilinear', 'bicubic'],
14
+ yx_matrices: bool = False,
15
+ ) -> torch.Tensor:
16
+ # grab image dimensions
17
+ h, w = image.shape[-2:]
18
+
19
+ if not yx_matrices:
20
+ matrices[..., :2, :2] = (
21
+ torch.flip(matrices[..., :2, :2], dims=(-2, -1))
22
+ )
23
+ matrices[..., :2, 2] = torch.flip(matrices[..., :2, 2], dims=(-1,))
24
+
25
+ # generate grid of pixel coordinates
26
+ grid = coordinate_grid(image_shape=(h, w), device=image.device)
27
+
28
+ # apply matrix to coordinates
29
+ grid = homogenise_coordinates(grid) # (h, w, yxw)
30
+ grid = einops.rearrange(grid, 'h w yxw -> h w yxw 1')
31
+ grid = matrices @ grid
32
+ grid = grid[..., :2, 0] # dehomogenise coordinates: (..., h, w, yxw, 1) -> (..., h, w, yx)
33
+
34
+ # sample image at transformed positions
35
+ result = sample_image_2d(image, coordinates=grid, interpolation=interpolation)
36
+ return result
@@ -0,0 +1,36 @@
1
+ from typing import Literal
2
+
3
+ import einops
4
+ import torch
5
+ from torch_affine_utils import homogenise_coordinates
6
+ from torch_grid_utils import coordinate_grid
7
+ from torch_image_interpolation import sample_image_3d
8
+
9
+
10
+ def affine_transform_image_3d(
11
+ image: torch.Tensor,
12
+ matrices: torch.Tensor,
13
+ interpolation: Literal['nearest', 'trilinear'],
14
+ zyx_matrices: bool = False,
15
+ ) -> torch.Tensor:
16
+ # grab image dimensions
17
+ d, h, w = image.shape[-3:]
18
+
19
+ if not zyx_matrices:
20
+ matrices[..., :3, :3] = (
21
+ torch.flip(matrices[..., :3, :3], dims=(-2, -1))
22
+ )
23
+ matrices[..., :3, 3] = torch.flip(matrices[..., :3, 3], dims=(-1,))
24
+
25
+ # generate grid of pixel coordinates
26
+ grid = coordinate_grid(image_shape=(d, h, w), device=image.device)
27
+
28
+ # apply matrix to coordinates
29
+ grid = homogenise_coordinates(grid) # (d, h, w, zyxw)
30
+ grid = einops.rearrange(grid, 'd h w zyxw -> d h w zyxw 1')
31
+ grid = matrices @ grid
32
+ grid = grid[..., :3, 0] # dehomogenise coordinates: (..., d, h, w, zyxw, 1) -> (..., d, h, w, zyx)
33
+
34
+ # sample image at transformed positions
35
+ result = sample_image_3d(image, coordinates=grid, interpolation=interpolation)
36
+ return result
@@ -0,0 +1,50 @@
1
+ import torch
2
+ from torch_transform_image import affine_transform_image_2d, affine_transform_image_3d
3
+ from torch_affine_utils.transforms_2d import T as T_2d
4
+ from torch_affine_utils.transforms_3d import T as T_3d
5
+
6
+
7
+ def test_affine_transform_image_2d():
8
+ # set up test image with dot at (18, 14)
9
+ image = torch.zeros((28, 28), dtype=torch.float32)
10
+ image[18, 14] = 1
11
+ image = image.float()
12
+
13
+ # check that image is zero at center
14
+ assert image[14, 14] == 0
15
+
16
+ # define transform
17
+ M = T_2d([4, 0]) # move coordinates up 4 in h dim
18
+
19
+ # sample
20
+ result = affine_transform_image_2d(
21
+ image, M, interpolation='bicubic', yx_matrices=True,
22
+ )
23
+
24
+ # sanity check, array center which was 4 voxels below the dot should now be 1
25
+ assert result.shape == image.shape
26
+ assert result[14, 14] == 1
27
+ assert result[18, 14] == 0
28
+
29
+
30
+ def test_affine_transform_image_3d():
31
+ # set up test image with dot at (18, 14)
32
+ image = torch.zeros((28, 28, 28), dtype=torch.float32)
33
+ image[18, 14, 14] = 1
34
+ image = image.float()
35
+
36
+ # check that image is zero at center
37
+ assert image[14, 14, 14] == 0
38
+
39
+ # define transform
40
+ M = T_3d([4, 0, 0]) # move coordinates up 4 in d dim
41
+
42
+ # sample
43
+ result = affine_transform_image_3d(
44
+ image, M, interpolation='trilinear', zyx_matrices=True,
45
+ )
46
+
47
+ # sanity check, array center which was 4 voxels below the dot should now be 1
48
+ assert result.shape == image.shape
49
+ assert result[14, 14, 14] == 1
50
+ assert result[18, 14, 14] == 0