-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Test image processors module
- Loading branch information
Showing
38 changed files
with
1,491 additions
and
405 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
from typing import Tuple | ||
|
||
import numpy as np | ||
from astropy.stats import SigmaClip | ||
|
||
from pyobs.images import Image | ||
|
||
|
||
class _DaoBackgroundRemover: | ||
def __init__(self, sigma: float, box_size: Tuple[int, int], filter_size: Tuple[int, int]): | ||
from photutils.background import MedianBackground | ||
|
||
self._sigma_clip = SigmaClip(sigma=sigma) | ||
self._box_size = box_size | ||
self._filter_size = filter_size | ||
|
||
self._bkg_estimator = MedianBackground() | ||
|
||
def __call__(self, image: Image) -> Image: | ||
background = self._estimate_background(image) | ||
return self._remove_background(image, background) | ||
|
||
def _estimate_background(self, image: Image): | ||
from photutils.background import Background2D | ||
|
||
bkg = Background2D( | ||
image.data, box_size=self._box_size, filter_size=self._filter_size, sigma_clip=self._sigma_clip, | ||
bkg_estimator=self._bkg_estimator, mask=image.mask | ||
) | ||
|
||
return bkg.background | ||
|
||
@staticmethod | ||
def _remove_background(image: Image, background: np.ndarray) -> Image: | ||
output_image = image.copy() | ||
output_image.data = output_image.data - background | ||
return output_image |
99 changes: 99 additions & 0 deletions
99
pyobs/images/processors/detection/_pysep_stats_calculator.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
import asyncio | ||
from copy import copy | ||
from functools import partial | ||
from typing import Optional | ||
|
||
import numpy as np | ||
|
||
from pyobs.images.processors.detection._source_catalog import _SourceCatalog | ||
|
||
|
||
class PySepStatsCalculator: | ||
def __init__(self, catalog: _SourceCatalog, data: np.ndarray, mask: np.ndarray, gain: Optional[float]): | ||
self._catalog = copy(catalog) | ||
self._data = data | ||
self._mask = mask | ||
self._gain = gain | ||
|
||
async def __call__(self, *args, **kwargs) -> _SourceCatalog: | ||
self._calc_ellipticity() | ||
self._calc_fwhm() | ||
self._calc_kron_radius() | ||
|
||
loop = asyncio.get_running_loop() | ||
await loop.run_in_executor(None, partial(self._calc_flux)) | ||
|
||
self._calc_flux_radii() | ||
self._calc_winpos() | ||
|
||
return self._catalog | ||
|
||
def _calc_ellipticity(self): | ||
self._catalog.sources["ellipticity"] = 1.0 - (self._catalog.sources["b"] / self._catalog.sources["a"]) | ||
|
||
def _calc_fwhm(self): | ||
fwhm = 2.0 * (np.log(2) * (self._catalog.sources["a"] ** 2.0 + self._catalog.sources["b"] ** 2.0)) ** 0.5 | ||
self._catalog.sources["fwhm"] = fwhm | ||
|
||
def _calc_kron_radius(self): | ||
import sep | ||
|
||
kronrad, krflag = sep.kron_radius( | ||
self._data, | ||
self._catalog.sources["x"], | ||
self._catalog.sources["y"], | ||
self._catalog.sources["a"], | ||
self._catalog.sources["b"], | ||
self._catalog.sources["theta"], | ||
6.0, | ||
) | ||
self._catalog.sources["flag"] |= krflag | ||
self._catalog.sources["kronrad"] = kronrad | ||
|
||
def _calc_flux(self): | ||
import sep | ||
|
||
flux, _, flag = sep.sum_ellipse( | ||
self._data, | ||
self._catalog.sources["x"], | ||
self._catalog.sources["y"], | ||
self._catalog.sources["a"], | ||
self._catalog.sources["b"], | ||
self._catalog.sources["theta"], | ||
2.5 * self._catalog.sources["kronrad"], | ||
subpix=5, | ||
mask=self._mask, | ||
gain=self._gain, | ||
) | ||
|
||
self._catalog.sources["flag"] |= flag | ||
self._catalog.sources["flux"] = flux | ||
|
||
def _calc_flux_radii(self): | ||
import sep | ||
|
||
flux_radii, flag = sep.flux_radius( | ||
self._data, | ||
self._catalog.sources["x"], | ||
self._catalog.sources["y"], | ||
6.0 * self._catalog.sources["a"], | ||
[0.25, 0.5, 0.75], | ||
normflux=self._catalog.sources["flux"], | ||
subpix=5, | ||
) | ||
|
||
self._catalog.sources["flag"] |= flag | ||
self._catalog.sources["fluxrad25"] = flux_radii[:, 0] | ||
self._catalog.sources["fluxrad50"] = flux_radii[:, 1] | ||
self._catalog.sources["fluxrad75"] = flux_radii[:, 2] | ||
|
||
def _calc_winpos(self): | ||
import sep | ||
|
||
sig = 2.0 / 2.35 * self._catalog.sources["fluxrad50"] | ||
xwin, ywin, flag = sep.winpos(self._data, self._catalog.sources["x"], self._catalog.sources["y"], sig) | ||
|
||
self._catalog.sources["flag"] |= flag | ||
self._catalog.sources["xwin"] = xwin | ||
self._catalog.sources["ywin"] = ywin | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
from copy import copy | ||
from typing import Optional, List | ||
|
||
import numpy as np | ||
import pandas as pd | ||
from astropy.coordinates import Angle | ||
from astropy.table import Table | ||
|
||
from pyobs.images import Image | ||
|
||
|
||
class _SourceCatalog: | ||
def __init__(self, sources: pd.DataFrame): | ||
self.sources = sources | ||
|
||
@classmethod | ||
def from_array(cls, sources: np.ndarray): | ||
source_dataframe = pd.DataFrame(sources) | ||
return cls(source_dataframe) | ||
|
||
@classmethod | ||
def from_table(cls, sources: Table): | ||
sources.rename_column("xcentroid", "x") | ||
sources.rename_column("ycentroid", "y") | ||
|
||
source_dataframe = sources.to_pandas() | ||
return cls(source_dataframe) | ||
|
||
def filter_detection_flag(self): | ||
if "flag" not in self.sources: | ||
return | ||
|
||
self.sources = self.sources[self.sources["flag"] < 8] | ||
|
||
def wrap_rotation_angle_at_ninty_deg(self): | ||
if "theta" not in self.sources: | ||
return | ||
|
||
self.sources["theta"] = np.arcsin(np.sin(self.sources["theta"])) | ||
|
||
def rotation_angle_to_degree(self): | ||
if "theta" not in self.sources: | ||
return | ||
|
||
self.sources["theta"] = np.degrees(self.sources["theta"]) | ||
|
||
def apply_fits_origin_convention(self): | ||
self.sources["x"] += 1 | ||
self.sources["y"] += 1 | ||
|
||
def save_to_image(self, image: Image, keys: List[str]) -> Image: | ||
cat = self.sources[keys] | ||
|
||
output_image = copy(image) | ||
output_image.catalog = Table.from_pandas(cat) | ||
return output_image |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.