Skip to content

Commit

Permalink
Addressed comments from Albert
Browse files Browse the repository at this point in the history
  • Loading branch information
nabobalis committed Nov 13, 2024
1 parent 1be344f commit f8dc488
Show file tree
Hide file tree
Showing 12 changed files with 65 additions and 95 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/PyCQA/docformatter
rev: v1.7.5
rev: master
hooks:
- id: docformatter
args: ["--in-place", "--pre-summary-newline", "--make-summary-multi"]
Expand Down
35 changes: 2 additions & 33 deletions changelog/207.breaking.rst
Original file line number Diff line number Diff line change
@@ -1,33 +1,2 @@
**New Coalignment API in sunkit_image.coalignment**

The new coalignment API, developed as part of GSoC 2024, addresses the need for a more precise and flexible approach to image coalignment within the `sunkit_image.coalignment` module.
As solar imaging data continues to grow in complexity, the existing coalignment functions from ``sunpy.image.coalignment`` and ``sunpy.physics.solar_rotation`` were found to be scattered and lacked a unified interface, leading to confusion and redundant code.

**New Features:**

- **Coalignment Interface** (`sunkit_image.coalignment.interface`):

- ``coalign`` function: A high-level function for image coalignment with a specified method. Default method: :func:`~sunkit_image.coalignment.match_template.match_template_coalign`.
- ``AffineParams`` NamedTuple: Stores and passes affine transformation parameters.

- **Template Matching Coalignment** (`sunkit_image.coalignment.match_template`):

- ``match_template_coalign`` function: A coalignment method that uses template matching.

- **Decorator Utility** (`sunkit_image.coalignment.decorators`):

- ``register_coalignment_method`` decorator: Enables easy registration of coalignment methods.
- Global Registry: Maintains a dictionary of registered coalignment methods.

**Enhancements:**

- Improved Metadata Handling: Updates WCS metadata based on affine transformation parameters.
- User Warnings: Alerts users to significant spatial or temporal separations between maps.

**Documentation:**

- All functions are well-documented in the API reference.

**Examples**

- Please find the examples related to the :ref:`adding of coalignment method <sunkit-image-how-to-guide-add-a-new-coalignment-method>` and using a coalignment method here :ref:`sphx_glr_generated_gallery_aligning_aia_with_eis_maps.py`
The previous coalignment API has been deleted and replaced with a new set of imports and functions.
Please see this example: :ref:`sphx_glr_generated_gallery_aligning_aia_with_eis_maps.py`.
4 changes: 1 addition & 3 deletions docs/code_ref/coalignment.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,10 @@ Coalignment Package
The main entry point is the `~sunkit_image.coalignment.coalign` function, which accepts a reference map, a target map, and a specified method for coalignment.
This method returns a new map with updated metadata reflecting the applied affine transformations, such as scaling, rotation, and translation.

The module supports various transformation methods registered via the `~sunkit_image.coalignment.decorators.register_coalignment_method` decorator, allowing for flexible coalignment strategies based on the specific needs of the data.
The module supports various transformation methods registered via the `~sunkit_image.coalignment.interface.register_coalignment_method` decorator, allowing for flexible coalignment strategies based on the specific needs of the data.

.. automodapi:: sunkit_image.coalignment

.. automodapi:: sunkit_image.coalignment.interface

.. automodapi:: sunkit_image.coalignment.match_template

.. automodapi:: sunkit_image.coalignment.decorators
7 changes: 3 additions & 4 deletions docs/how_to_guide/adding_a_coalignment_method.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@
Add a New Coalignment Method
****************************

If you want to register a new coalignment method that can be used by :func:`~sunkit_image.coalignment.coalign`, you can use :func:`~sunkit_image.coalignment.decorators.register_coalignment_method`:
If you want to register a new coalignment method that can be used by :func:`~sunkit_image.coalignment.coalign`, you can use :func:`~sunkit_image.coalignment.interface.register_coalignment_method`:

.. code-block:: python
from sunkit_image.coalignment.decorators import register_coalignment_method
from sunkit_image.coalignment.interface import AffineParams
from sunkit_image.coalignment.interface import AffineParams, register_coalignment_method
@register_coalignment_method("my_coalign")
def my_coalignment_method(input_array, target_array):
Expand Down Expand Up @@ -55,5 +54,5 @@ To check if your method is registered, you can check if it is present in the reg

.. code-block:: python
from sunkit_image.coalignment.decorators import REGISTERED_METHODS
from sunkit_image.coalignment.interface import REGISTERED_METHODS
print(REGISTERED_METHODS)
12 changes: 6 additions & 6 deletions examples/aligning_aia_with_eis_maps.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
###################################################################################
# Firstly, let us acquire the EIS and AIA data we need for this example.
#
# For this example, we will use the IS data from the sunpy data repository.
# This is a preprocessed IS raster data.
# For this example, we will use the EIS data from the sunpy data repository.
# This is a preprocessed EIS raster data.


eis_map = sunpy.map.Map("https://github.com/sunpy/data/raw/main/sunkit-image/eis_20140108_095727.fe_12_195_119.2c-0.int.fits")
Expand All @@ -35,30 +35,30 @@

###################################################################################
# Lets find the AIA image that we want to use as a reference.
# We want to be using an image near the "date_average" of the IS raster.
# We want to be using an image near the "date_average" of the EIS raster.

query = Fido.search(a.Time(start=eis_map.meta["date_beg"], near=eis_map.meta["date_avg"], end=eis_map.meta["date_end"]), a.Instrument('aia'), a.Wavelength(193*u.angstrom))
aia_file = Fido.fetch(query)
aia_map = sunpy.map.Map(aia_file)

####################################################################################
# Before coaligning the images, we first downsample the AIA image to the same plate
# scale as the IS image. This is not done automatically.
# scale as the EIS image. This is not done automatically.

nx = (aia_map.scale.axis1 * aia_map.dimensions.x) / eis_map.scale.axis1
ny = (aia_map.scale.axis2 * aia_map.dimensions.y) / eis_map.scale.axis2

aia_downsampled = aia_map.resample(u.Quantity([nx, ny]))

####################################################################################
# Now we can coalign IS to AIA using cross-correlation. For this we would be using the
# Now we can coalign EIS to AIA using cross-correlation. For this we would be using the
# "match_template" method. For details of the implementation refer to the
# documentation of `~sunkit_image.coalignment.match_template.match_template_coalign`.

coaligned_eis_map = coalign(aia_downsampled, eis_map)

####################################################################################
# To check now effective this has been, we will plot the IS data and
# To check now effective this has been, we will plot the EIS data and
# overlap the bright regions from AIA before and after the coalignment.

levels = [800] * aia_map.unit
Expand Down
3 changes: 2 additions & 1 deletion sunkit_image/coalignment/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# This will register the function
from sunkit_image.coalignment.interface import coalign
from sunkit_image.coalignment.match_template import match_template_coalign as _ # NOQA: F401
from sunkit_image.coalignment.match_template import match_template_coalign # NOQA: F401

__all__ = ["coalign"]
21 changes: 0 additions & 21 deletions sunkit_image/coalignment/decorators.py

This file was deleted.

38 changes: 33 additions & 5 deletions sunkit_image/coalignment/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@
from sunpy.sun.models import differential_rotation
from sunpy.util.exceptions import SunpyUserWarning

from sunkit_image.coalignment.decorators import REGISTERED_METHODS
__all__ = ["AffineParams", "register_coalignment_method", "REGISTERED_METHODS"]

__all__ = ["AffineParams"]
# Global Dictionary to store the registered methods and their names
REGISTERED_METHODS = {}


class AffineParams(NamedTuple):
Expand All @@ -32,6 +33,23 @@ class AffineParams(NamedTuple):
translation: tuple[float, float]


def register_coalignment_method(name):
"""
Registers a coalignment method to be used by the coalignment interface.
Parameters
----------
name : str
The name of the coalignment method.
"""

def decorator(func):
REGISTERED_METHODS[name] = func
return func

return decorator


def _update_fits_wcs_metadata(reference_map, target_map, affine_params):
"""
Update the metadata of a sunpy.map.Map` based on affine transformation
Expand Down Expand Up @@ -115,7 +133,7 @@ def _warn_user_of_separation(reference_map, target_map):
)


def coalign(reference_map, target_map, method='match_template'):
def coalign(reference_map, target_map, method='match_template', **kwargs):
"""
Performs image coalignment using the specified method.
Expand All @@ -134,8 +152,11 @@ def coalign(reference_map, target_map, method='match_template'):
The reference map to which the target map is to be coaligned.
target_map : `sunpy.map.Map`

Check warning on line 153 in sunkit_image/coalignment/interface.py

View check run for this annotation

Codecov / codecov/patch

sunkit_image/coalignment/interface.py#L153

Added line #L153 was not covered by tests
The target map to be coaligned to the reference map.
method : `str`
method : {{{coalignment_function_names}}}, optional
The name of the registered coalignment method to use.
Defaults to 'match_template'.
kwargs : `dict`
Additional keyword arguments to pass to the registered method.
Returns
-------
Expand All @@ -154,5 +175,12 @@ def coalign(reference_map, target_map, method='match_template'):
target_array = target_map.data
reference_array = reference_map.data
_warn_user_of_separation(reference_map, target_map)
affine_params = REGISTERED_METHODS[method](reference_array, target_array)
affine_params = REGISTERED_METHODS[method](reference_array, target_array, **kwargs)
return _update_fits_wcs_metadata(reference_map, target_map, affine_params)


# Generate the string with allowable coalignment-function names for use in docstrings
_coalignment_function_names = ", ".join([f"``'{name}'``" for name in REGISTERED_METHODS])
# Insert into the docstring for coalign. We cannot use the add_common_docstring decorator
# due to what would be a circular loop in definitions.
coalign.__doc__ = coalign.__doc__.format(coalignment_function_names=_coalignment_function_names) # type: ignore
9 changes: 4 additions & 5 deletions sunkit_image/coalignment/match_template.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import numpy as np
from skimage.feature import match_template

from sunkit_image.coalignment.decorators import register_coalignment_method
from sunkit_image.coalignment.interface import AffineParams
from sunkit_image.coalignment.interface import AffineParams, register_coalignment_method

__all__ = ["match_template_coalign"]

Expand Down Expand Up @@ -88,7 +87,7 @@ def _find_best_match_location(corr):


@register_coalignment_method("match_template")
def match_template_coalign(reference_array, target_array):
def match_template_coalign(input_array, target_array, **kwargs):
"""
Perform coalignment by matching the template array to the input array.
Expand All @@ -111,11 +110,11 @@ def match_template_coalign(reference_array, target_array):
- translation : `tuple`
A tuple containing the x and y translation values.
"""
corr = match_template(np.float64(reference_array), np.float64(target_array))
corr = match_template(np.float64(input_array), np.float64(target_array))
# Find the best match location
y_shift, x_shift = _find_best_match_location(corr)
# Particularly for this method, there is no change in the rotation or scaling,
# hence the hardcoded values of scale to 1.0 & rotation to identity matrix
scale = np.array([1.0, 1.0])
rotation_matrix = np.eye(2)
return AffineParams(scale=scale, rotation_matrix=rotation_matrix, translation=(x_shift , y_shift ))
return AffineParams(scale=scale, rotation_matrix=rotation_matrix, translation=(x_shift, y_shift))
16 changes: 12 additions & 4 deletions sunkit_image/coalignment/tests/test_coalignment.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
from sunpy.net import attrs as a

from sunkit_image.coalignment import coalign
from sunkit_image.coalignment.decorators import register_coalignment_method
from sunkit_image.coalignment.interface import AffineParams
from sunkit_image.coalignment.interface import REGISTERED_METHODS, AffineParams, register_coalignment_method
from sunkit_image.tests.helpers import figure_test


Expand Down Expand Up @@ -41,8 +40,7 @@ def cutout_map(aia171_test_map):
aia_map = sunpy.map.Map(aia171_test_map)
bottom_left = SkyCoord(-300 * u.arcsec, -300 * u.arcsec, frame = aia_map.coordinate_frame)
top_right = SkyCoord(800 * u.arcsec, 600 * u.arcsec, frame = aia_map.coordinate_frame)
cutout_map = aia_map.submap(bottom_left, top_right=top_right)
return cutout_map
return aia_map.submap(bottom_left, top_right=top_right)


def test_coalignment_reflects_pixel_shifts(cutout_map, aia171_test_map):
Expand Down Expand Up @@ -108,3 +106,13 @@ def test_coalignment_reflects_rotation(cutout_map, aia171_test_map):
fixed_cutout_map = coalign(aia171_test_map, rotated_map, method="rotation")
assert_allclose(fixed_cutout_map.rotation_matrix[0, 0], cutout_map.rotation_matrix[0, 0], rtol=1e-4, atol=0)
assert_allclose(fixed_cutout_map.rotation_matrix[1, 1], cutout_map.rotation_matrix[1, 1], rtol=1e-4, atol=0)


Check warning on line 110 in sunkit_image/coalignment/tests/test_coalignment.py

View check run for this annotation

Codecov / codecov/patch

sunkit_image/coalignment/tests/test_coalignment.py#L106-L110

Added lines #L106 - L110 were not covered by tests
def test_register_coalignment_method():
@register_coalignment_method("test_method")
def test_func():
return "Test function"

assert "test_method" in REGISTERED_METHODS
assert REGISTERED_METHODS["test_method"] == test_func
assert test_func() == "Test function"
11 changes: 0 additions & 11 deletions sunkit_image/coalignment/tests/test_decorators.py

This file was deleted.

2 changes: 1 addition & 1 deletion sunkit_image/coalignment/tests/test_match_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import astropy.units as u

from sunkit_image.coalignment.decorators import REGISTERED_METHODS
from sunkit_image.coalignment.interface import REGISTERED_METHODS
from sunkit_image.coalignment.match_template import (
_find_best_match_location,
_get_correlation_shifts,
Expand Down

0 comments on commit f8dc488

Please sign in to comment.