# ImageOperations
**ImageOperations** is a minimal, device‑aware image ops library built on top of OpenCV and NumPy.
You can call functions directly **without initialization**, or use a small facade class with a
**default device** (CPU/GPU/MPS placeholder). When the requested device is unavailable, the library
**transparently falls back to CPU**.
- ✅ Functional API *and* OOP API
- ✅ Device selection per call (`device="cpu"|"gpu"|"mps"`)
- ✅ Safe fallback (GPU/MPS → CPU)
- ✅ Typed (PEP 561, `py.typed`)
- ✅ Clean, modular structure (`ops/`, `registry`, `device`, `types`)
- 🔧 Easy to extend: add new ops or backends without touching the public API
> **Note:** MPS (Apple Metal) is reserved in `ComputeDevice` but currently falls back to CPU.
---
## Installation
```bash
poetry add img-ops
# or with pip:
# pip install img-ops
```
**Headless environments:** replace `opencv-python` with `opencv-python-headless` in your environment
if you don't need GUI capabilities.
---
## Quick Start
### Functional API
```python
from img_ops import bgr_to_hsv, in_range, gauss_blur, ComputeDevice
hsv = bgr_to_hsv(img, device="gpu") # uses GPU if CUDA available; else CPU
mask = in_range(hsv, (0, 80, 80), (10, 255, 255)) # default device (CPU)
blur = gauss_blur(img, (5, 5), 1.2, device=ComputeDevice.CPU)
```
### OOP API with default device
```python
from img_ops import ImageProcessor
proc = ImageProcessor(default_device="gpu")
hsv = proc.bgr_to_hsv(img) # defaults to GPU (fallback → CPU)
mask = proc.in_range(hsv, (0, 80, 80), (10, 255, 255)) # uses proc.default_device
blur = proc.gauss_blur(img, (5, 5), 1.2, device="cpu") # per-call override → CPU
```
---
## Supported Operations (initial set)
- **Color**: `bgr_to_rgb`, `bgr_to_hsv`, `in_range`
- **Filters**: `gauss_blur`
- **Segmentation (CPU-only)**: `find_contours`, `connected_components`
- **Utils**: `sum_masks` (internal registry op)
Add more ops by editing `registry.py` and adding thin wrappers in `ops/`.
---
## Devices
```python
from img_ops import ComputeDevice
# ComputeDevice.GPU -> CUDA (if available)
# ComputeDevice.MPS -> reserved (falls back to CPU)
# ComputeDevice.CPU -> always available
```
### Fallback behavior
- If you request `GPU` and CUDA is unavailable, the call automatically falls back to `CPU`.
- `MPS` is a placeholder and currently always falls back to `CPU`.
---
## Types
The library ships with type hints and `py.typed`.
```python
from img_ops import CvImage, PointHSV
# CvImage: NDArray[uint8 | float32] # shape (H,W,3) or (H,W)
# PointHSV: tuple[int, int, int] # (H, S, V)
```
Shape is not fixed in the type system; keep (H, W) or (H, W, 3) by convention.
---
## Error Handling
- Unknown device strings raise `ValueError` with allowed values.
- Missing implementations raise `NotImplementedError` (after attempting CPU fallback).
---
## Extending the Library
### Add a new operation
1. Implement CPU/GPU/MPS callables in `registry.py` under `_cpu()`, `_gpu()`, `_mps()`.
2. Add a thin function wrapper in `ops/<category>.py` that normalizes `device` and calls `dispatch(...)`.
3. (Optional) Expose it in `ops/__init__.py` and the package `__init__.py`.
### Add a new device
1. Extend `ComputeDevice` (e.g., `OPENCL`, `TORCH`).
2. Add a registry builder (e.g., `_opencl()`), wire it in `REGISTRY`.
3. Add availability checks in `device.py` and normalization in each `ops/*.py` wrapper.
This keeps public API stable while evolving internals.
---
## Performance Notes
- GPU helps mostly for larger images or heavy kernels; small images can be faster on CPU due to
upload/download overhead.
- Prefer `cv2.add` over `a + b` for masks to handle saturation properly.
---
## Testing
```bash
poetry run pytest
poetry run mypy src/img_ops
poetry run ruff check .
```
---
## Author
[](https://t.me/omigutin)
[](https://github.com/omigutin)
**Project:** <https://github.com/omigutin/img_ops>
**Project Tracker:** <https://github.com/users/omigutin/projects/4>
**Contact:** [migutin83@yandex.ru](mailto:migutin83@yandex.ru)
---
## License
MIT License.
See [LICENSE](LICENSE) for details.
Raw data
{
"_id": null,
"home_page": "https://github.com/omigutin/img_ops",
"name": "img-ops",
"maintainer": null,
"docs_url": null,
"requires_python": "<3.13,>=3.10",
"maintainer_email": null,
"keywords": "image-processing, image-operations, computer-vision, opencv, cuda, gpu, cpu, preprocessing, ndarray, numpy, contours, segmentation, hsv, gaussian-blur, python-library",
"author": "migutin83",
"author_email": "migutin83@yandex.ru",
"download_url": "https://files.pythonhosted.org/packages/f1/a9/fad2fc4746c803ab08a7beae791dcb72ea11b298a8840c2f8e71a54db2ee/img_ops-0.1.2.tar.gz",
"platform": null,
"description": "# ImageOperations\n\n**ImageOperations** is a minimal, device\u2011aware image ops library built on top of OpenCV and NumPy.\nYou can call functions directly **without initialization**, or use a small facade class with a\n**default device** (CPU/GPU/MPS placeholder). When the requested device is unavailable, the library\n**transparently falls back to CPU**.\n\n- \u2705 Functional API *and* OOP API\n- \u2705 Device selection per call (`device=\"cpu\"|\"gpu\"|\"mps\"`)\n- \u2705 Safe fallback (GPU/MPS \u2192 CPU)\n- \u2705 Typed (PEP 561, `py.typed`)\n- \u2705 Clean, modular structure (`ops/`, `registry`, `device`, `types`)\n- \ud83d\udd27 Easy to extend: add new ops or backends without touching the public API\n\n> **Note:** MPS (Apple Metal) is reserved in `ComputeDevice` but currently falls back to CPU.\n\n---\n\n## Installation\n\n```bash\npoetry add img-ops\n# or with pip:\n# pip install img-ops\n```\n\n**Headless environments:** replace `opencv-python` with `opencv-python-headless` in your environment\nif you don't need GUI capabilities.\n\n---\n\n## Quick Start\n\n### Functional API\n\n```python\nfrom img_ops import bgr_to_hsv, in_range, gauss_blur, ComputeDevice\n\nhsv = bgr_to_hsv(img, device=\"gpu\") # uses GPU if CUDA available; else CPU\nmask = in_range(hsv, (0, 80, 80), (10, 255, 255)) # default device (CPU)\nblur = gauss_blur(img, (5, 5), 1.2, device=ComputeDevice.CPU)\n```\n\n### OOP API with default device\n\n```python\nfrom img_ops import ImageProcessor\n\nproc = ImageProcessor(default_device=\"gpu\")\nhsv = proc.bgr_to_hsv(img) # defaults to GPU (fallback \u2192 CPU)\nmask = proc.in_range(hsv, (0, 80, 80), (10, 255, 255)) # uses proc.default_device\nblur = proc.gauss_blur(img, (5, 5), 1.2, device=\"cpu\") # per-call override \u2192 CPU\n```\n\n---\n\n## Supported Operations (initial set)\n\n- **Color**: `bgr_to_rgb`, `bgr_to_hsv`, `in_range`\n- **Filters**: `gauss_blur`\n- **Segmentation (CPU-only)**: `find_contours`, `connected_components`\n- **Utils**: `sum_masks` (internal registry op)\n\nAdd more ops by editing `registry.py` and adding thin wrappers in `ops/`.\n\n---\n\n## Devices\n\n```python\nfrom img_ops import ComputeDevice\n# ComputeDevice.GPU -> CUDA (if available)\n# ComputeDevice.MPS -> reserved (falls back to CPU)\n# ComputeDevice.CPU -> always available\n```\n\n### Fallback behavior\n- If you request `GPU` and CUDA is unavailable, the call automatically falls back to `CPU`.\n- `MPS` is a placeholder and currently always falls back to `CPU`.\n\n---\n\n## Types\n\nThe library ships with type hints and `py.typed`.\n\n```python\nfrom img_ops import CvImage, PointHSV\n\n# CvImage: NDArray[uint8 | float32] # shape (H,W,3) or (H,W)\n# PointHSV: tuple[int, int, int] # (H, S, V)\n```\n\nShape is not fixed in the type system; keep (H, W) or (H, W, 3) by convention.\n\n---\n\n## Error Handling\n\n- Unknown device strings raise `ValueError` with allowed values.\n- Missing implementations raise `NotImplementedError` (after attempting CPU fallback).\n\n---\n\n## Extending the Library\n\n### Add a new operation\n1. Implement CPU/GPU/MPS callables in `registry.py` under `_cpu()`, `_gpu()`, `_mps()`.\n2. Add a thin function wrapper in `ops/<category>.py` that normalizes `device` and calls `dispatch(...)`.\n3. (Optional) Expose it in `ops/__init__.py` and the package `__init__.py`.\n\n### Add a new device\n1. Extend `ComputeDevice` (e.g., `OPENCL`, `TORCH`).\n2. Add a registry builder (e.g., `_opencl()`), wire it in `REGISTRY`.\n3. Add availability checks in `device.py` and normalization in each `ops/*.py` wrapper.\n\nThis keeps public API stable while evolving internals.\n\n---\n\n## Performance Notes\n\n- GPU helps mostly for larger images or heavy kernels; small images can be faster on CPU due to\n upload/download overhead.\n- Prefer `cv2.add` over `a + b` for masks to handle saturation properly.\n\n---\n\n## Testing\n\n```bash\npoetry run pytest\npoetry run mypy src/img_ops\npoetry run ruff check .\n```\n\n---\n## Author\n\n[](https://t.me/omigutin)\n[](https://github.com/omigutin)\n\n**Project:** <https://github.com/omigutin/img_ops>\n\n**Project Tracker:** <https://github.com/users/omigutin/projects/4>\n\n**Contact:** [migutin83@yandex.ru](mailto:migutin83@yandex.ru)\n\n---\n\n## License\n\nMIT License.\nSee [LICENSE](LICENSE) for details.\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Device-aware image operations (CPU/GPU/MPS fallback) with a clean Python API for preprocessing tasks.",
"version": "0.1.2",
"project_urls": {
"Documentation": "https://github.com/omigutin/img_ops#readme",
"Homepage": "https://github.com/omigutin/img_ops",
"Repository": "https://github.com/users/omigutin/projects/4"
},
"split_keywords": [
"image-processing",
" image-operations",
" computer-vision",
" opencv",
" cuda",
" gpu",
" cpu",
" preprocessing",
" ndarray",
" numpy",
" contours",
" segmentation",
" hsv",
" gaussian-blur",
" python-library"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "7559f7f713af8868f88f7753eba1c24b1228e228d2b392a91ac8f1da41b032fe",
"md5": "f6261a60f0190ea6736574db4ce583ae",
"sha256": "3e2f500234ea1a3241f708f454d4fad594f31bf399fa6c917be2db0b44652a2b"
},
"downloads": -1,
"filename": "img_ops-0.1.2-py3-none-any.whl",
"has_sig": false,
"md5_digest": "f6261a60f0190ea6736574db4ce583ae",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<3.13,>=3.10",
"size": 15519,
"upload_time": "2025-08-18T16:38:36",
"upload_time_iso_8601": "2025-08-18T16:38:36.348066Z",
"url": "https://files.pythonhosted.org/packages/75/59/f7f713af8868f88f7753eba1c24b1228e228d2b392a91ac8f1da41b032fe/img_ops-0.1.2-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "f1a9fad2fc4746c803ab08a7beae791dcb72ea11b298a8840c2f8e71a54db2ee",
"md5": "ef090785e1ef2df64ccdd8a572417d18",
"sha256": "fc699db06cfb37c0899e1ace0469cd7fc29f609030ab075b81ad8574ef5f38d2"
},
"downloads": -1,
"filename": "img_ops-0.1.2.tar.gz",
"has_sig": false,
"md5_digest": "ef090785e1ef2df64ccdd8a572417d18",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<3.13,>=3.10",
"size": 12491,
"upload_time": "2025-08-18T16:38:37",
"upload_time_iso_8601": "2025-08-18T16:38:37.488454Z",
"url": "https://files.pythonhosted.org/packages/f1/a9/fad2fc4746c803ab08a7beae791dcb72ea11b298a8840c2f8e71a54db2ee/img_ops-0.1.2.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-18 16:38:37",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "omigutin",
"github_project": "img_ops",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "img-ops"
}