Skip to content

Commit

Permalink
refactor fits handling and added tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mworion committed Sep 17, 2024
1 parent 2967be0 commit 3d9cf91
Show file tree
Hide file tree
Showing 12 changed files with 182 additions and 294 deletions.
4 changes: 2 additions & 2 deletions mw4/gui/extWindows/imageW.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@

# local import
from mountcontrol.convert import convertToDMS, convertToHMS
from base.fitsHeader import getCoordinatesFromHeader, getSQMFromHeader
from base.fitsHeader import getExposureFromHeader, getScaleFromHeader
from logic.fits.fitsFunction import getCoordinatesFromHeader, getSQMFromHeader
from logic.fits.fitsFunction import getExposureFromHeader, getScaleFromHeader
from gui.utilities import toolsQtWidget
from gui.utilities.slewInterface import SlewInterface
from gui.widgets import image_ui
Expand Down
2 changes: 1 addition & 1 deletion mw4/logic/camera/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
# local imports
from gui.utilities.toolsQtWidget import sleepAndEvents
from base.driverDataClass import Signals
from base.fitsHeader import writeHeaderCamera, writeHeaderPointing
from logic.fits.fitsFunction import writeHeaderCamera, writeHeaderPointing
from logic.camera.cameraIndi import CameraIndi
from logic.camera.cameraAlpaca import CameraAlpaca
if platform.system() == 'Windows':
Expand Down
Empty file added mw4/logic/fits/__init__.py
Empty file.
69 changes: 66 additions & 3 deletions mw4/base/fitsHeader.py → mw4/logic/fits/fitsFunction.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@
###########################################################
# standard libraries
import logging
from pathlib import Path

# external packages
import numpy as np
from skyfield.api import Angle
from astropy.io import fits
from skyfield.units import Angle

# local import
from base.transform import JNowToJ2000
Expand All @@ -31,6 +32,13 @@
log = logging.getLogger()


def getImageHeader(imagePath: Path) -> fits.Header:
"""
"""
with fits.open(imagePath) as HDU:
return HDU[0].header


def getCoordinatesFromHeader(header: fits.Header) -> [Angle, Angle]:
"""
"""
Expand Down Expand Up @@ -90,8 +98,7 @@ def getScaleFromHeader(header: fits.Header) -> float:
focalLength = float(header.get('FOCALLEN', 0))
binning = float(header.get('XBINNING', 0))
pixelSize = max(float(header.get('XPIXSZ', 0)),
float(header.get('PIXSIZE1', 0)),
)
float(header.get('PIXSIZE1', 0)))
hasAlternatives = focalLength and binning and pixelSize

if hasScale:
Expand All @@ -103,6 +110,15 @@ def getScaleFromHeader(header: fits.Header) -> float:
return scale


def getHintFromImageFile(imagePath: Path) -> [Angle, Angle, float]:
"""
"""
header = getImageHeader(imagePath)
raHint, decHint = getCoordinatesFromHeader(header)
scaleHint = getScaleFromHeader(header)
return raHint, decHint, scaleHint


def getCoordinatesFromWCSHeader(header: fits.Header) -> [Angle, Angle]:
"""
"""
Expand Down Expand Up @@ -165,3 +181,50 @@ def writeHeaderPointing(header: fits.Header, camera) -> fits.Header:
header.append(('RA', ra._degrees, 'Float value in degree'))
header.append(('DEC', dec.degrees, 'Float value in degree'))
return header


def writeSolutionToHeader(header: fits.Header, solution: dict) -> fits.Header:
"""
"""
header.append(('RA', solution['raJ2000S']._degrees, 'MW4 - processed'))
header.append(('DEC', solution['decJ2000S'].degrees, 'MW4 - processed'))
header.append(('SCALE', solution['scaleS'], 'MW4 - processed'))
header.append(('PIXSCALE', solution['scaleS'], 'MW4 - processed'))
header.append(('ANGLE', solution['angleS'].degrees, 'MW4 - processed'))
header.append(('MIRRORED', solution['mirroredS'], 'MW4 - processed'))
return header


def updateImageFileHeaderWithSolution(imagePath: Path, solution: dict) -> fits.Header:
"""
"""
with fits.open(imagePath, mode='update', output_verify='silentfix+warn') as HDU:
HDU[0].header = writeSolutionToHeader(HDU[0].header, solution)


def getSolutionFromWCSHeader(wcsHeader: fits.Header, imageHeader: fits.Header) -> dict:
"""
CRVAL1 and CRVAL2 give the center coordinate as right ascension and
declination or longitude and latitude in decimal degrees.
"""
raJ2000 = convertToAngle(wcsHeader.get('CRVAL1', 0), isHours=True)
decJ2000 = convertToAngle(wcsHeader.get('CRVAL2', 0), isHours=False)

angle, scale, mirrored = calcAngleScaleFromWCSHeader(header=wcsHeader)
raMount, decMount = getCoordinatesFromHeader(header=imageHeader)

deltaRA_raw = raJ2000._degrees - raMount._degrees
deltaDEC_raw = decJ2000.degrees - decMount.degrees
error = np.sqrt(np.square(deltaRA_raw) + np.square(deltaDEC_raw))

solution = {
'raJ2000S': raJ2000,
'decJ2000S': decJ2000,
'errorRA_S': Angle(degrees=deltaRA_raw),
'errorDEC_S': Angle(degrees=deltaDEC_raw),
'angleS': angle,
'scaleS': scale,
'errorRMS_S': error,
'mirroredS': mirrored,
}
return solution
5 changes: 2 additions & 3 deletions mw4/logic/plateSolve/astap.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,8 @@
# external packages

# local imports
from logic.plateSolve.fitsFunctions import getSolutionFromWCSHeader
from logic.plateSolve.fitsFunctions import updateImageFileHeaderWithSolution
from logic.plateSolve.fitsFunctions import getImageHeader
from logic.fits.fitsFunction import getSolutionFromWCSHeader, getImageHeader, \
updateImageFileHeaderWithSolution


class ASTAP(object):
Expand Down
7 changes: 3 additions & 4 deletions mw4/logic/plateSolve/astrometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,8 @@

# local imports
from mountcontrol import convert
from logic.plateSolve.fitsFunctions import getSolutionFromWCSHeader
from logic.plateSolve.fitsFunctions import updateImageFileHeaderWithSolution
from logic.plateSolve.fitsFunctions import getImageHeader, readImageHeaderHintData
from logic.fits.fitsFunction import getSolutionFromWCSHeader, getImageHeader, \
getHintFromHeader, updateImageFileHeaderWithSolution


class Astrometry(object):
Expand Down Expand Up @@ -181,7 +180,7 @@ def solve(self, imagePath: Path, updateHeader: bool) -> dict:
self.result['message'] = 'image2xy failed'
return result

raHint, decHint, scaleHint = readImageHeaderHintData(imagePath=imagePath)
raHint, decHint, scaleHint = getHintFromHeader(imagePath=imagePath)
searchRatio = 1.1
ra = convert.convertToHMS(raHint)
dec = convert.convertToDMS(decHint)
Expand Down
90 changes: 0 additions & 90 deletions mw4/logic/plateSolve/fitsFunctions.py

This file was deleted.

5 changes: 2 additions & 3 deletions mw4/logic/plateSolve/watney.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,8 @@
# external packages

# local imports
from logic.plateSolve.fitsFunctions import getSolutionFromWCSHeader
from logic.plateSolve.fitsFunctions import updateImageFileHeaderWithSolution
from logic.plateSolve.fitsFunctions import getImageHeader
from logic.fits.fitsFunction import getSolutionFromWCSHeader, getImageHeader, \
updateImageFileHeaderWithSolution


class Watney(object):
Expand Down
2 changes: 0 additions & 2 deletions tests/unit_tests/logic/camera/test_cameraAlpaca.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
###########################################################
# standard libraries
import pytest
import astropy
import unittest.mock as mock

# external packages
Expand All @@ -27,7 +26,6 @@
from tests.unit_tests.unitTestAddOns.baseTestApp import App
from logic.camera.camera import Camera
from logic.camera.cameraAlpaca import CameraAlpaca
from base.driverDataClass import Signals
from base.loggerMW import setupLogging
setupLogging()

Expand Down
Loading

0 comments on commit 3d9cf91

Please sign in to comment.