pyarcfire


Namepyarcfire JSON
Version 0.1.1 PyPI version JSON
download
home_pageNone
SummaryA port of SpArcFiRe, a spiral arc finder
upload_time2024-11-21 07:16:25
maintainerNone
docs_urlNone
authorPavadol Yamsiri
requires_python>=3.10.15
licenseBSD 3-Clause License
keywords arc astronomy finder spiral
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # PyArcFiRe

PyArcFiRe is a python port of [SpArcFiRe](https://github.com/waynebhayes/SpArcFiRe) which is written primarily in MatLab.
Like SpArcFiRe it can be used to detect spiral arcs in images, mostly for galaxy images however it perhaps may work in other contexts.

## Limitations

Note that this is currently a work in progress and the project may change greatly over time.

### Functionality

This port does not have all of the functionality and features of SpArcFiRe such as bar finding and fitting, automatic centering and deprojection, etc.

## Installation

You can install this package by simply using the command

```
$ pip install pyarcfire
```

## Interface

There are two main ways of using PyArcFiRe

1. As a python package to use in your own programs.
2. As a command line interface.

### Package

Create an instance of `SpiralFinder` and then call the `extract` method on a 2D array to run the spiral finding algorithm.

```python
from pyarcfire import SpiralFinder
import numpy as np

# Example: Load a grayscale image
image = ... # Replace with an actual 2D image array

# Create a SpiralFinder instance
finder = SpiralFinder()

# Extract spiral features
result = finder.extract(image)
```

Then to extract the spiral arm masks you can simply use the `mask` property to get a 2D array of integers. The non-zero values of the `mask` array is the cluster id of
the pixel.

For example, you can plot just the first cluster like this

```python
import matplotlib.pyplot as plt

fig = plt.figure()
axes = fig.add_subplot(111)
axes.imshow(result.mask == 1)
plt.show()
plt.close(fig)
```

The original image and the preprocessed image can be accessed as well.

```python
import matplotlib.pyplot as plt

fig = plt.figure()
original_axes = fig.add_subplot(121)
original_axes.imshow(result.original_image)
processed_axes = fig.add_subplot(122)
processed_axes.imshow(result.processed_image)
plt.show()
plt.close(fig)
```

Additionally, you can get the dominant chirality and overall pitch angle of the result like so

```python
print(result.get_dominant_chirality()) # Chirality.NONE | Chirality.CLOCKWISE | Chirality.COUNTER_CLOCKWISE
print(result.get_overall_pitch_angle()) # +- n degrees
```

or get the log spiral fits to each cluster and plot them like so
```python
import matplotlib.pyplot as plt

fig = plt.figure()
axes = fig.add_subplot(111)

for cluster_index in range(result.num_clusters):
    fit = result.get_fit(cluster_index)
    x, y = spiral_fit.calculate_cartesian_coordinates(100, pixel_to_distance=1, flip_y=False) # `pixel_to_distance` converts from pixel units to your desired distance units
    axes.plot(x, y)
plt.show()
plt.close()
```

#### Algorithm Parameters

The spiral finding algorithm has many configurable parameters for each step.

When computing the orientation field the parameters are:

- `neighbour_distance (int)`: The distance in pixels between a cell and its neighbour when denoising the orientation field.
- `kernel_radius (int)`: The radius of the orientation filter kernel in pixels.
- `num_levels (int)`: The number of image rescalings to create orientation fields of and then join.

When computing the similarity matrix:

- `similarity_cutoff (float)`: The minimum allowed similarity between orientation field pixels.

When clustering pixels:

- `error_ratio_threshold (float)`: The maximum error ratio allowed for a merge between two clusters to be permitted.
- `merge_check_mininum_cluster_size (int)`: The maximum size of a cluster before merges with other clusters become checked.
- `minimum_cluster_size (int)`: The minimum cluster size allowed after all merges are completed.
- `remove_central_cluster (bool)`: A flag to remove remove the clusters that touch the center of the image.

When merging nearby clusters by checking their log spiral fits:

- `stop_threshold (float)`: The maximum merge error ratio before stopping merges.

These parameters can be configured by calling the associated methods on `SpiralFinder`

```python
from pyarcfire import SpiralFinder


# Create a SpiralFinder instance
finder = SpiralFinder()

# Adjust orientation field generation
finder = finder.with_orientation_field_settings(
    neighbour_distance=4,
    kernel_radius=None, # Set to `None` to keep the old value.
    # num_levels=3, # Omit the parameter if you want to keep the old value as well.
)

# Adjust similarity matrix generation
finder = finder.with_similarity_matrix_settings(
    cutoff=0.15,
)

# Adjust clustering
finder = finder.with_clustering_settings(
    error_ratio_threshold=2.5,
    merge_check_minimum_cluster_size=25,
    minimum_cluster_size=120,
    remove_central_cluster=False,
)

# Adjust merging by fit
finder = finder.with_merge_fit_settings(
    stop_threshold=2.4,
)
```

#### Preprocessing

In order for an image to be ran through the algorithm, some preprocessing may be necessary. The requirements are that:

- The array is 2D.
- The array values are normalized in the range [0, 1].
- The array's height and width must be divisible by 2^N where N is the number of orientation field levels.

Therefore `SpiralFinder` will by default perform the following:

1. It will first check that the array is 2D. If not an exception will be raised.
2. It will normalize the values in the array using a linear scale.
3. It will resize the image so that the height and width are valid by finding the closest valid size.

Also as part of the algorithm, a contrast boosting step will be performed. By default this is an unsharp mask.

These preprocessing steps can be changed however and in fact can be turned entirely off.

```python
from pyarcfire import SpiralFinder
from pyarcfire.preprocess import ImageIdentityNormalizer

# Turn off all preprocessing
finder = SpiralFinder().with_normalizer(None).with_resizer(None).with_booster(None)

# Change the normalizer
finder = SpiralFinder().with_normalizer(ImageIdentityNormalizer())
```

You can create custom preprocessors as well by implementing the `ImageNormalizer`, `ImageResizer` and `ImageContrastBooster` protocols (see `pyarcfire.preprocess`).


### Command Line Interface

PyArcFiRe can also be interacted with through the command line interface via `python -m pyarcfire ...`. Currently this is a work in progress and is mainly
a way to drive debugging code.

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "pyarcfire",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10.15",
    "maintainer_email": null,
    "keywords": "arc, astronomy, finder, spiral",
    "author": "Pavadol Yamsiri",
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/21/29/22709b9a0922733fca400753262b5b024707f66198104fdc3a8fbfe33b55/pyarcfire-0.1.1.tar.gz",
    "platform": null,
    "description": "# PyArcFiRe\n\nPyArcFiRe is a python port of [SpArcFiRe](https://github.com/waynebhayes/SpArcFiRe) which is written primarily in MatLab.\nLike SpArcFiRe it can be used to detect spiral arcs in images, mostly for galaxy images however it perhaps may work in other contexts.\n\n## Limitations\n\nNote that this is currently a work in progress and the project may change greatly over time.\n\n### Functionality\n\nThis port does not have all of the functionality and features of SpArcFiRe such as bar finding and fitting, automatic centering and deprojection, etc.\n\n## Installation\n\nYou can install this package by simply using the command\n\n```\n$ pip install pyarcfire\n```\n\n## Interface\n\nThere are two main ways of using PyArcFiRe\n\n1. As a python package to use in your own programs.\n2. As a command line interface.\n\n### Package\n\nCreate an instance of `SpiralFinder` and then call the `extract` method on a 2D array to run the spiral finding algorithm.\n\n```python\nfrom pyarcfire import SpiralFinder\nimport numpy as np\n\n# Example: Load a grayscale image\nimage = ... # Replace with an actual 2D image array\n\n# Create a SpiralFinder instance\nfinder = SpiralFinder()\n\n# Extract spiral features\nresult = finder.extract(image)\n```\n\nThen to extract the spiral arm masks you can simply use the `mask` property to get a 2D array of integers. The non-zero values of the `mask` array is the cluster id of\nthe pixel.\n\nFor example, you can plot just the first cluster like this\n\n```python\nimport matplotlib.pyplot as plt\n\nfig = plt.figure()\naxes = fig.add_subplot(111)\naxes.imshow(result.mask == 1)\nplt.show()\nplt.close(fig)\n```\n\nThe original image and the preprocessed image can be accessed as well.\n\n```python\nimport matplotlib.pyplot as plt\n\nfig = plt.figure()\noriginal_axes = fig.add_subplot(121)\noriginal_axes.imshow(result.original_image)\nprocessed_axes = fig.add_subplot(122)\nprocessed_axes.imshow(result.processed_image)\nplt.show()\nplt.close(fig)\n```\n\nAdditionally, you can get the dominant chirality and overall pitch angle of the result like so\n\n```python\nprint(result.get_dominant_chirality()) # Chirality.NONE | Chirality.CLOCKWISE | Chirality.COUNTER_CLOCKWISE\nprint(result.get_overall_pitch_angle()) # +- n degrees\n```\n\nor get the log spiral fits to each cluster and plot them like so\n```python\nimport matplotlib.pyplot as plt\n\nfig = plt.figure()\naxes = fig.add_subplot(111)\n\nfor cluster_index in range(result.num_clusters):\n    fit = result.get_fit(cluster_index)\n    x, y = spiral_fit.calculate_cartesian_coordinates(100, pixel_to_distance=1, flip_y=False) # `pixel_to_distance` converts from pixel units to your desired distance units\n    axes.plot(x, y)\nplt.show()\nplt.close()\n```\n\n#### Algorithm Parameters\n\nThe spiral finding algorithm has many configurable parameters for each step.\n\nWhen computing the orientation field the parameters are:\n\n- `neighbour_distance (int)`: The distance in pixels between a cell and its neighbour when denoising the orientation field.\n- `kernel_radius (int)`: The radius of the orientation filter kernel in pixels.\n- `num_levels (int)`: The number of image rescalings to create orientation fields of and then join.\n\nWhen computing the similarity matrix:\n\n- `similarity_cutoff (float)`: The minimum allowed similarity between orientation field pixels.\n\nWhen clustering pixels:\n\n- `error_ratio_threshold (float)`: The maximum error ratio allowed for a merge between two clusters to be permitted.\n- `merge_check_mininum_cluster_size (int)`: The maximum size of a cluster before merges with other clusters become checked.\n- `minimum_cluster_size (int)`: The minimum cluster size allowed after all merges are completed.\n- `remove_central_cluster (bool)`: A flag to remove remove the clusters that touch the center of the image.\n\nWhen merging nearby clusters by checking their log spiral fits:\n\n- `stop_threshold (float)`: The maximum merge error ratio before stopping merges.\n\nThese parameters can be configured by calling the associated methods on `SpiralFinder`\n\n```python\nfrom pyarcfire import SpiralFinder\n\n\n# Create a SpiralFinder instance\nfinder = SpiralFinder()\n\n# Adjust orientation field generation\nfinder = finder.with_orientation_field_settings(\n    neighbour_distance=4,\n    kernel_radius=None, # Set to `None` to keep the old value.\n    # num_levels=3, # Omit the parameter if you want to keep the old value as well.\n)\n\n# Adjust similarity matrix generation\nfinder = finder.with_similarity_matrix_settings(\n    cutoff=0.15,\n)\n\n# Adjust clustering\nfinder = finder.with_clustering_settings(\n    error_ratio_threshold=2.5,\n    merge_check_minimum_cluster_size=25,\n    minimum_cluster_size=120,\n    remove_central_cluster=False,\n)\n\n# Adjust merging by fit\nfinder = finder.with_merge_fit_settings(\n    stop_threshold=2.4,\n)\n```\n\n#### Preprocessing\n\nIn order for an image to be ran through the algorithm, some preprocessing may be necessary. The requirements are that:\n\n- The array is 2D.\n- The array values are normalized in the range [0, 1].\n- The array's height and width must be divisible by 2^N where N is the number of orientation field levels.\n\nTherefore `SpiralFinder` will by default perform the following:\n\n1. It will first check that the array is 2D. If not an exception will be raised.\n2. It will normalize the values in the array using a linear scale.\n3. It will resize the image so that the height and width are valid by finding the closest valid size.\n\nAlso as part of the algorithm, a contrast boosting step will be performed. By default this is an unsharp mask.\n\nThese preprocessing steps can be changed however and in fact can be turned entirely off.\n\n```python\nfrom pyarcfire import SpiralFinder\nfrom pyarcfire.preprocess import ImageIdentityNormalizer\n\n# Turn off all preprocessing\nfinder = SpiralFinder().with_normalizer(None).with_resizer(None).with_booster(None)\n\n# Change the normalizer\nfinder = SpiralFinder().with_normalizer(ImageIdentityNormalizer())\n```\n\nYou can create custom preprocessors as well by implementing the `ImageNormalizer`, `ImageResizer` and `ImageContrastBooster` protocols (see `pyarcfire.preprocess`).\n\n\n### Command Line Interface\n\nPyArcFiRe can also be interacted with through the command line interface via `python -m pyarcfire ...`. Currently this is a work in progress and is mainly\na way to drive debugging code.\n",
    "bugtrack_url": null,
    "license": "BSD 3-Clause License",
    "summary": "A port of SpArcFiRe, a spiral arc finder",
    "version": "0.1.1",
    "project_urls": {
        "Issues": "https://github.com/pavyamsiri/pyarcfire/issues",
        "Source": "https://github.com/pavyamsiri/pyarcfire.git"
    },
    "split_keywords": [
        "arc",
        " astronomy",
        " finder",
        " spiral"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "4e5be63866c95293a9cfadaf69b8272d9c429fefe5cfa100d06281802ea63e40",
                "md5": "069a36359a8c2ec67e646bdbb410e9b3",
                "sha256": "a4b5a1d9e4f77d3674daca1f4956aaa7aba2db94de28f39365d05a03226ee220"
            },
            "downloads": -1,
            "filename": "pyarcfire-0.1.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "069a36359a8c2ec67e646bdbb410e9b3",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10.15",
            "size": 49294,
            "upload_time": "2024-11-21T07:16:21",
            "upload_time_iso_8601": "2024-11-21T07:16:21.870166Z",
            "url": "https://files.pythonhosted.org/packages/4e/5b/e63866c95293a9cfadaf69b8272d9c429fefe5cfa100d06281802ea63e40/pyarcfire-0.1.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "212922709b9a0922733fca400753262b5b024707f66198104fdc3a8fbfe33b55",
                "md5": "7fd15aeb206ac5ebf2a9f1a29827eb57",
                "sha256": "13601190a77dddb55eaad8503f10efefba5ddb963f17bdbd94506f3d360c7c6a"
            },
            "downloads": -1,
            "filename": "pyarcfire-0.1.1.tar.gz",
            "has_sig": false,
            "md5_digest": "7fd15aeb206ac5ebf2a9f1a29827eb57",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10.15",
            "size": 79821,
            "upload_time": "2024-11-21T07:16:25",
            "upload_time_iso_8601": "2024-11-21T07:16:25.474288Z",
            "url": "https://files.pythonhosted.org/packages/21/29/22709b9a0922733fca400753262b5b024707f66198104fdc3a8fbfe33b55/pyarcfire-0.1.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-11-21 07:16:25",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "pavyamsiri",
    "github_project": "pyarcfire",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "pyarcfire"
}
        
Elapsed time: 0.37361s