# imagej-rolling-ball
Python wrapper for [ImageJ's rolling ball background
subtraction](https://imagej.net/ij/developer/api/ij/ij/plugin/filter/BackgroundSubtracter.html#rollingBallBackground(ij.process.ImageProcessor,double,boolean,boolean,boolean,boolean,boolean))
using [pyimagej](https://github.com/imagej/pyimagej).
## Install
1. Follow [pyimagej's installation
instruction](https://py.imagej.net/en/latest/Install.html)
1. Install `imagej-rolling-ball` from pypi
```bash
python -m pip install imagej-rolling-ball
```
1. To work with large images, `dask` and `zarr` were used in the package. You
can install them yourself or specify the `[large]` install
```bash
python -m pip install imagej-rolling-ball[large]
```
1. To work with pyramidal ome-tiff images, `palom` was used. Install the `[wsi]`
extras
```bash
python -m pip install imagej-rolling-ball[wsi]
```
## Usage
The key parameter is the rolling ball radius, according to the
[doc](https://imagej.nih.gov/ij/docs/menus/process.html#background), the radius
> should be at least as large as the radius of the largest object in the image
> that is not part of the background
**NOTE:** While the java class `BackgroundSubtracter` handles RGB image, the
current wrapper methods only accepts 2D arrays. One can process each channel
separately and combine all the processed channels using `numpy.array` or
`numpy.dstack`
### Basic usage
```python
import imagej_rolling_ball
import numpy
bg_subtracter = imagej_rolling_ball.BackgroundSubtracter(java_options='-Xmx1g')
img = numpy.eye(5) + 1
print('img\n', img, '\n')
print('radius=1')
print(bg_subtracter.rolling_ball_background(img, 1), '\n')
print('radius=2.5')
print(bg_subtracter.rolling_ball_background(img, 2.5), '\n')
```
And the output of the above script should be
```python
img
[[2. 1. 1. 1. 1.]
[1. 2. 1. 1. 1.]
[1. 1. 2. 1. 1.]
[1. 1. 1. 2. 1.]
[1. 1. 1. 1. 2.]]
radius=1
[[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]]
radius=2
[[0. 0. 0. 0. 0. ]
[0. 0.7912879 0. 0. 0. ]
[0. 0. 0.7912879 0. 0. ]
[0. 0. 0. 0.7912879 0. ]
[0. 0. 0. 0. 0. ]]
```
### Process large image
For large array (e.g. array that contains more than 2,147,483,647 elements), the
`BackgroundSubtracter.rolling_ball_background_chunked` method is for such use
case. It returns a `dask.array` by default or a `zarr.core.Array` if
`compute=True` is set.
```python
In [1]: import imagej_rolling_ball
...: import numpy
...:
...: bg_subtracter = imagej_rolling_ball.BackgroundSubtracter(java_options='-Xmx4g')
...: img = numpy.eye(10_000, dtype='uint8') + 1
ImageJ Version: 2.14.0/1.54f
In [2]: bg_subtracter.rolling_ball_background_chunked(img, 50, 1024*5)
Operating in headless mode - the original ImageJ will have limited functionality.
Out[2]: dask.array<_trim, shape=(10000, 10000), dtype=uint8, chunksize=(5120, 5120), chunktype=numpy.ndarray>
In [3]: bg_subtracter.rolling_ball_background_chunked(img, 50, 1024*5).compute()
Out[3]:
array([[1, 0, 0, ..., 0, 0, 0],
[0, 1, 0, ..., 0, 0, 0],
[0, 0, 1, ..., 0, 0, 0],
...,
[0, 0, 0, ..., 1, 0, 0],
[0, 0, 0, ..., 0, 1, 0],
[0, 0, 0, ..., 0, 0, 1]], dtype=uint8)
In [4]: bg_subtracter.rolling_ball_background_chunked(img, 50, 1024*5, compute=True)
Out[4]: <zarr.core.Array (10000, 10000) uint8>
```
### Process chunked ome-tiff in command line interface
Use `rolling-ball` command to process multi-channel tiff file and write the
processed image to disk as a pyramidal ome-tiff. `python -m pip install
imagej-rolling-ball[wsi]` is required.
```bash
NAME
rolling-ball
SYNOPSIS
rolling-ball IMG_PATH RADIUS <flags>
POSITIONAL ARGUMENTS
IMG_PATH
RADIUS
FLAGS
--out_path=OUT_PATH
Type: Optional[str]
Default: None
-t, --target_chunk_size=TARGET_CHUNK_SIZE
Type: int
Default: 5120
--overwrite=OVERWRITE
Type: bool
Default: False
-j, --java_options=JAVA_OPTIONS
Type: Optional[str]
Default: None
-i, --imagej_version=IMAGEJ_VERSION
Type: Optional[str]
Default: None
-p, --pyramid_config=PYRAMID_CONFIG
Type: Optional[dict]
Default: None
--rolling_ball_kwargs=ROLLING_BALL_KWARGS
Type: Optional[dict]
Default: None
-n, --num_workers=NUM_WORKERS
Type: int
Default: 4
```
**NOTES:**
- To pass in JVM options, e.g. set max heap size (`-Xmx4g`), use the syntax of
`-j="-Xmx4g"`
- The defaut Java heap size is 70% of the available memory
- Increase `--num_workers` may speed up processing time, default is `4`
- The default output file will be generated next to the input file, the file
name ends with `-ij_rolling_ball_{radius}.ome.tif`
**Example commands:**
- Minimal command, process file using rolling ball radius of `100` and
writebackground-subtracted image to disk
```bash
rolling-ball path/to/input/file.ome.tif 100
```
- Write background image instead of subtracted image (`--rolling_ball_kwargs
"{'create_background': True}"`) to file; set JVM max heap size to 4 GB
(`-j="-Xmx4g"`) and use 8 threads (`-n=8`)
```bash
rolling-ball path/to/input/file.ome.tif 100 \
--out_path path/to/input/file-background_100.ome.tif \
--rolling_ball_kwargs "{'create_background': True}" \
-j="-Xmx4g" \
--overwrite \
-n=8
```
### Docker usage
The docker image can be build from the github repo or be pulled from the docker
hub.
To process an image file (`input.ome.tif`) with rolling ball radius `50` in the
current directory:
```bash
docker run -it --rm -v "$(pwd)":/data \
yuanchen12/imagej-rolling-ball \
rolling-ball /data/input.ome.tif 50
```
When the process is completed, output file `input-ij_rolling_ball_50.ome.tif`
will be generated.
Raw data
{
"_id": null,
"home_page": "https://pypi.org/project/imagej-rolling-ball",
"name": "imagej-rolling-ball",
"maintainer": null,
"docs_url": null,
"requires_python": "<4.0,>=3.8",
"maintainer_email": null,
"keywords": "microscopy, imagej, background subtraction, image processing",
"author": "Yu-An Chen",
"author_email": "atwood12@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/43/4e/de939f15749e0939f65f71fad6b5bf6ead1c4e92e0582fda3ed339e185ff/imagej_rolling_ball-2024.6.1.tar.gz",
"platform": null,
"description": "# imagej-rolling-ball\n\nPython wrapper for [ImageJ's rolling ball background\nsubtraction](https://imagej.net/ij/developer/api/ij/ij/plugin/filter/BackgroundSubtracter.html#rollingBallBackground(ij.process.ImageProcessor,double,boolean,boolean,boolean,boolean,boolean))\nusing [pyimagej](https://github.com/imagej/pyimagej).\n\n## Install\n\n1. Follow [pyimagej's installation\n instruction](https://py.imagej.net/en/latest/Install.html)\n\n1. Install `imagej-rolling-ball` from pypi\n\n ```bash\n python -m pip install imagej-rolling-ball\n ```\n\n1. To work with large images, `dask` and `zarr` were used in the package. You\n can install them yourself or specify the `[large]` install\n\n ```bash\n python -m pip install imagej-rolling-ball[large]\n ```\n\n1. To work with pyramidal ome-tiff images, `palom` was used. Install the `[wsi]`\n extras\n\n ```bash\n python -m pip install imagej-rolling-ball[wsi]\n ```\n\n## Usage\n\nThe key parameter is the rolling ball radius, according to the\n[doc](https://imagej.nih.gov/ij/docs/menus/process.html#background), the radius\n\n> should be at least as large as the radius of the largest object in the image\n> that is not part of the background\n\n**NOTE:** While the java class `BackgroundSubtracter` handles RGB image, the\ncurrent wrapper methods only accepts 2D arrays. One can process each channel\nseparately and combine all the processed channels using `numpy.array` or\n`numpy.dstack`\n\n\n### Basic usage\n\n```python\nimport imagej_rolling_ball\nimport numpy\n\nbg_subtracter = imagej_rolling_ball.BackgroundSubtracter(java_options='-Xmx1g')\nimg = numpy.eye(5) + 1\n\nprint('img\\n', img, '\\n')\nprint('radius=1')\nprint(bg_subtracter.rolling_ball_background(img, 1), '\\n')\nprint('radius=2.5')\nprint(bg_subtracter.rolling_ball_background(img, 2.5), '\\n')\n```\n\nAnd the output of the above script should be\n\n```python\nimg\n [[2. 1. 1. 1. 1.]\n [1. 2. 1. 1. 1.]\n [1. 1. 2. 1. 1.]\n [1. 1. 1. 2. 1.]\n [1. 1. 1. 1. 2.]] \n\nradius=1\n[[0. 0. 0. 0. 0.]\n [0. 0. 0. 0. 0.]\n [0. 0. 0. 0. 0.]\n [0. 0. 0. 0. 0.]\n [0. 0. 0. 0. 0.]] \n\nradius=2\n[[0. 0. 0. 0. 0. ]\n [0. 0.7912879 0. 0. 0. ]\n [0. 0. 0.7912879 0. 0. ]\n [0. 0. 0. 0.7912879 0. ]\n [0. 0. 0. 0. 0. ]] \n```\n\n### Process large image\n\nFor large array (e.g. array that contains more than 2,147,483,647 elements), the\n`BackgroundSubtracter.rolling_ball_background_chunked` method is for such use\ncase. It returns a `dask.array` by default or a `zarr.core.Array` if\n`compute=True` is set.\n\n\n```python\nIn [1]: import imagej_rolling_ball\n ...: import numpy\n ...: \n ...: bg_subtracter = imagej_rolling_ball.BackgroundSubtracter(java_options='-Xmx4g')\n ...: img = numpy.eye(10_000, dtype='uint8') + 1\nImageJ Version: 2.14.0/1.54f\n\nIn [2]: bg_subtracter.rolling_ball_background_chunked(img, 50, 1024*5)\nOperating in headless mode - the original ImageJ will have limited functionality.\nOut[2]: dask.array<_trim, shape=(10000, 10000), dtype=uint8, chunksize=(5120, 5120), chunktype=numpy.ndarray>\n\nIn [3]: bg_subtracter.rolling_ball_background_chunked(img, 50, 1024*5).compute()\nOut[3]: \narray([[1, 0, 0, ..., 0, 0, 0],\n [0, 1, 0, ..., 0, 0, 0],\n [0, 0, 1, ..., 0, 0, 0],\n ...,\n [0, 0, 0, ..., 1, 0, 0],\n [0, 0, 0, ..., 0, 1, 0],\n [0, 0, 0, ..., 0, 0, 1]], dtype=uint8)\n\nIn [4]: bg_subtracter.rolling_ball_background_chunked(img, 50, 1024*5, compute=True)\nOut[4]: <zarr.core.Array (10000, 10000) uint8>\n```\n\n### Process chunked ome-tiff in command line interface\n\nUse `rolling-ball` command to process multi-channel tiff file and write the\nprocessed image to disk as a pyramidal ome-tiff. `python -m pip install\nimagej-rolling-ball[wsi]` is required.\n\n```bash\nNAME\n rolling-ball\n\nSYNOPSIS\n rolling-ball IMG_PATH RADIUS <flags>\n\nPOSITIONAL ARGUMENTS\n IMG_PATH\n RADIUS\n\nFLAGS\n --out_path=OUT_PATH\n Type: Optional[str]\n Default: None\n -t, --target_chunk_size=TARGET_CHUNK_SIZE\n Type: int\n Default: 5120\n --overwrite=OVERWRITE\n Type: bool\n Default: False\n -j, --java_options=JAVA_OPTIONS\n Type: Optional[str]\n Default: None\n -i, --imagej_version=IMAGEJ_VERSION\n Type: Optional[str]\n Default: None\n -p, --pyramid_config=PYRAMID_CONFIG\n Type: Optional[dict]\n Default: None\n --rolling_ball_kwargs=ROLLING_BALL_KWARGS\n Type: Optional[dict]\n Default: None\n -n, --num_workers=NUM_WORKERS\n Type: int\n Default: 4\n```\n\n**NOTES:**\n\n- To pass in JVM options, e.g. set max heap size (`-Xmx4g`), use the syntax of\n `-j=\"-Xmx4g\"`\n- The defaut Java heap size is 70% of the available memory\n- Increase `--num_workers` may speed up processing time, default is `4`\n- The default output file will be generated next to the input file, the file\n name ends with `-ij_rolling_ball_{radius}.ome.tif`\n\n**Example commands:**\n\n- Minimal command, process file using rolling ball radius of `100` and\n writebackground-subtracted image to disk\n\n ```bash\n rolling-ball path/to/input/file.ome.tif 100\n ```\n\n- Write background image instead of subtracted image (`--rolling_ball_kwargs\n \"{'create_background': True}\"`) to file; set JVM max heap size to 4 GB\n (`-j=\"-Xmx4g\"`) and use 8 threads (`-n=8`)\n\n ```bash\n rolling-ball path/to/input/file.ome.tif 100 \\\n --out_path path/to/input/file-background_100.ome.tif \\\n --rolling_ball_kwargs \"{'create_background': True}\" \\\n -j=\"-Xmx4g\" \\ \n --overwrite \\\n -n=8\n ```\n\n### Docker usage\n\nThe docker image can be build from the github repo or be pulled from the docker\nhub.\n\nTo process an image file (`input.ome.tif`) with rolling ball radius `50` in the\ncurrent directory:\n\n```bash\n docker run -it --rm -v \"$(pwd)\":/data \\\n yuanchen12/imagej-rolling-ball \\\n rolling-ball /data/input.ome.tif 50\n```\n\nWhen the process is completed, output file `input-ij_rolling_ball_50.ome.tif`\nwill be generated.\n",
"bugtrack_url": null,
"license": null,
"summary": "Python wrapper for ImageJ's rolling ball background subtraction using pyimagej",
"version": "2024.6.1",
"project_urls": {
"Homepage": "https://pypi.org/project/imagej-rolling-ball",
"Repository": "https://github.com/Yu-AnChen/imagej-rolling-ball"
},
"split_keywords": [
"microscopy",
" imagej",
" background subtraction",
" image processing"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "068e2af5f8dcedbae4d1dd0c3a22c876ca89e2b58636d0cc8d47bfea40f70ef9",
"md5": "3836387eb57f118109b35a8056b3348d",
"sha256": "13fad3a1faa0df751e4cf378b5826556b647700e3ee8df25312d1f91fc0fbd2b"
},
"downloads": -1,
"filename": "imagej_rolling_ball-2024.6.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "3836387eb57f118109b35a8056b3348d",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4.0,>=3.8",
"size": 8925,
"upload_time": "2024-07-10T04:37:31",
"upload_time_iso_8601": "2024-07-10T04:37:31.053262Z",
"url": "https://files.pythonhosted.org/packages/06/8e/2af5f8dcedbae4d1dd0c3a22c876ca89e2b58636d0cc8d47bfea40f70ef9/imagej_rolling_ball-2024.6.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "434ede939f15749e0939f65f71fad6b5bf6ead1c4e92e0582fda3ed339e185ff",
"md5": "9f14d920b15cc8e6f5ab8f17aaf5c930",
"sha256": "f27a76dc19f009d46a6bc1b5bc3f26320448b76b9121ca84594f63ec932e9754"
},
"downloads": -1,
"filename": "imagej_rolling_ball-2024.6.1.tar.gz",
"has_sig": false,
"md5_digest": "9f14d920b15cc8e6f5ab8f17aaf5c930",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4.0,>=3.8",
"size": 7252,
"upload_time": "2024-07-10T04:37:32",
"upload_time_iso_8601": "2024-07-10T04:37:32.958957Z",
"url": "https://files.pythonhosted.org/packages/43/4e/de939f15749e0939f65f71fad6b5bf6ead1c4e92e0582fda3ed339e185ff/imagej_rolling_ball-2024.6.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-07-10 04:37:32",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "Yu-AnChen",
"github_project": "imagej-rolling-ball",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "imagej-rolling-ball"
}