-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcalibration.py
95 lines (78 loc) · 4.31 KB
/
calibration.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import numpy as np
import cv2
from astropy.io import fits
# The aia image size is fixed by the size of the detector. For AIA raw data, this has no reason to change.
aia_image_size = 4096
def scale_rotate(image, angle=0, scale_factor=1, reference_pixel=None):
"""
Perform scaled rotation with opencv. About 20 times faster than with Sunpy & scikit/skimage warp methods.
The output is a padded image that holds the entire rescaled,rotated image, recentered around the reference pixel.
Positive-angle rotation will go counterclockwise if the array is displayed with the origin on top (default),
and clockwise with the origin at bottom.
:param image: Numpy 2D array
:param angle: rotation angle in degrees. Positive angle will rotate counterclocwise if array origin on top-left
:param scale_factor: ratio of the wavelength-dependent pixel scale over the target scale of 0.6 arcsec
:param reference_pixel: tuple of (x, y) coordinate. Given as (x, y) = (col, row) and not (row, col).
:return: padded scaled and rotated image
"""
array_center = (np.array(image.shape)[::-1] - 1) / 2.0
if reference_pixel is None:
reference_pixel = array_center
# convert angle to radian
angler = angle * np.pi / 180
# Get basic rotation matrix to calculate initial padding extent
rmatrix = np.matrix([[np.cos(angler), -np.sin(angler)],
[np.sin(angler), np.cos(angler)]])
extent = np.max(np.abs(np.vstack((image.shape * rmatrix,
image.shape * rmatrix.T))), axis=0)
# Calculate the needed padding or unpadding
diff = np.asarray(np.ceil((extent - image.shape) / 2), dtype=int).ravel()
diff2 = np.max(np.abs(reference_pixel - array_center)) + 1
# Pad the image array
pad_x = int(np.ceil(np.max((diff[1], 0)) + diff2))
pad_y = int(np.ceil(np.max((diff[0], 0)) + diff2))
padded_reference_pixel = reference_pixel + np.array([pad_x, pad_y])
#padded_image = np.pad(image, ((pad_y, pad_y), (pad_x, pad_x)), mode='constant', constant_values=(0, 0))
padded_image = aia_pad(image, pad_x, pad_y)
padded_array_center = (np.array(padded_image.shape)[::-1] - 1) / 2.0
# Get scaled rotation matrix accounting for padding
rmatrix_cv = cv2.getRotationMatrix2D((padded_reference_pixel[0], padded_reference_pixel[1]), angle, scale_factor)
# Adding extra shift to recenter:
# move image so the reference pixel aligns with the center of the padded array
shift = padded_array_center - padded_reference_pixel
rmatrix_cv[0, 2] += shift[0]
rmatrix_cv[1, 2] += shift[1]
# Do the scaled rotation with opencv. ~20x faster than Sunpy's map.rotate()
rotated_image = cv2.warpAffine(padded_image, rmatrix_cv, padded_image.shape, cv2.INTER_CUBIC)
return rotated_image
def aiaprep(fitsfile, cropsize=aia_image_size):
hdul = fits.open(fitsfile)
hdul[1].verify('silentfix')
header = hdul[1].header
data = hdul[1].data.astype(np.float64)
data /= header['EXPTIME']
# Target scale is 0.6 arcsec/px
target_scale = 0.6
scale_factor = header['CDELT1'] / target_scale
# Center of rotation at reference pixel converted to a coordinate origin at 0
reference_pixel = [header['CRPIX1'] - 1, header['CRPIX2'] - 1]
# Rotation angle with openCV uses coordinate origin at top-left corner. For solar images in numpy we need to invert the angle.
angle = -header['CROTA2']
# Run scaled rotation. The output will be a rotated, rescaled, padded array.
prepdata = scale_rotate(data, angle=angle, scale_factor=scale_factor, reference_pixel=reference_pixel)
prepdata[prepdata < 0] = 0
if cropsize is not None:
center = ((np.array(prepdata.shape) - 1) / 2.0).astype(int)
half_size = int(cropsize / 2)
prepdata = prepdata[center[1] - half_size:center[1] + half_size, center[0] - half_size:center[0] + half_size]
return prepdata
# Alternate padding method. On AIA, it is ~6x faster than numpy.pad used in Sunpy's aiaprep
def aia_pad(image, pad_x, pad_y):
newsize = [image.shape[0]+2*pad_y, image.shape[1]+2*pad_x]
pimage = np.empty(newsize)
pimage[0:pad_y,:] = 0
pimage[:,0:pad_x]=0
pimage[pad_y+image.shape[0]:, :] = 0
pimage[:, pad_x+image.shape[1]:] = 0
pimage[pad_y:image.shape[0]+pad_y, pad_x:image.shape[1]+pad_x] = image
return pimage