-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathc2_processing.py
More file actions
192 lines (154 loc) · 7.7 KB
/
c2_processing.py
File metadata and controls
192 lines (154 loc) · 7.7 KB
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created October 2021
PURPOSE:
This code provides two very basic image processing algorithms that
are effective for removing the excess background signal (known as the "focorona")
from raw LASCO data. These are established, publicly released algorithms that are
well-known to the heliophysics community.
Details of the two enclosed algorithms - "median subtraction" and "running difference"
are provided as notes/comments in the code below.
USAGE:
Place a series (3 or more) of LASCO C2 .fts files into a 'C2DATA' folder
Run
>>> from c2_processing import c2_process
>>> c2_process( )
- or -
>>> c2_process( rundiff=True )
OUTPUT:
- A series of processed png files will be created in the 'C2DATA' folder
*** Please note: ***
There is very minimal fault-tolerance in this code. It is provided simply to
illustrate the basic algorithms, but does not perform any checks for bad, missing,
or incorrectly shaped data. There exist many different methods/packages/functions
to achieve the same, or similar, results as shown here, with differing levels of
efficiency.
DEPENDENCIES / REQUIRED PACKAGES:
matplotlib
numpy
scipy
astropy
datetime
glob
@author: Dr. Karl Battams
"""
import matplotlib.pyplot as plt
import glob
import numpy as np
from astropy.io import fits
from scipy.signal import medfilt2d
import datetime
import torch
import torch.nn.functional as F
import os
########################################################################
# Function to perform median subtraction and save resulting files as PNGs
########################################################################
def med_subtract( indata, dst_path, dateinfo, kern_sz = 25 , annotate_words=True):
dpi = 80 # dots per inch
width = 1024 # image size (assuming 1024x1024 images)
height = 1024 # image size (assuming 1024x1024 images)
kern = kern_sz # size of smoothing kernel <- User defined
imgmin = -3. # MAX value for display <- User defined
imgmax = 3. # MIN value for display <- User defined
figsize = width / float(dpi), height / float(dpi) # Set output image size
numfiles = indata.shape[2] # For loop counter
""" ## Note about median subtraction ##
The process of median subtraction uses medfilt2d to create a 'smoothed' version of the
image and then subtracts that smoothed image from the original, effectively operating
like a high-pass filter. The size of the smoothing kernel (default = 25) is variable.
"""
plt.ioff() # Turn off interactive plotting
# Create images
for i in range( numfiles ):
outname = dst_path + dateinfo[i].strftime('%Y%m%d_%H%M_C2_medfilt.png')
if os.path.exists(outname):
continue
print("Writing image %i of %i with median-subtraction" % (i+1,numfiles))
medsub = indata[:,:,i] - medfilt2d(indata[:,:,i], kernel_size=kern) # Apply filter; see note above
# The following commands just set up a figure with no borders, and writes the image to a png.
fig = plt.figure(figsize=figsize)
ax = fig.add_axes([0, 0, 1, 1])
ax.axis('off')
ax.imshow(np.fliplr(medsub), vmin=imgmin,vmax=imgmax,cmap='gray', interpolation='nearest',origin='lower')
if annotate_words:
ax.annotate(dateinfo[i].strftime('%Y/%m/%d %H:%M'), xy=(10,10), xytext=(320, 1010),color='cyan', size=30, ha='right')
ax.set(xlim=[0, width], ylim=[height, 0], aspect=1)
fig.savefig(outname, dpi=dpi, transparent=True)
plt.close()
print("Median filtering process complete.")
return 1
########################################################################
# Function to perform running difference and save resulting files as PNGs
########################################################################
def rdiff( indata, dateinfo ):
""" ## Note about running difference ##
The process of running difference involves subtracting the previous image
in a sequence from the current image. This process removes static structures
but emphasizes features in motion.
"""
#Perform running difference. See note above.
rdiff = np.diff(indata, axis=2)
# truncate date information as running difference "loses" the first image
dateinfo = dateinfo[1:]
# Write PNGS files
dpi = 80 # dots per inch
width = 1024 # image size (assuming 1024x1024 images)
height = 1024 # image size (assuming 1024x1024 images)
imgmin = -3. # MAX value for display <- User defined
imgmax = 3. # MIN value for display <- User defined
figsize = width / float(dpi), height / float(dpi) # Set output image size
numfiles = rdiff.shape[2] # For loop counter
plt.ioff() # Turn off interactive plotting
# Create images
for i in range( numfiles ):
print("Writing image %i of %i with running-difference processing" % (i+1,numfiles))
# The following commands just set up a figure with no borders, and writes the image to a png.
fig = plt.figure(figsize=figsize)
ax = fig.add_axes([0, 0, 1, 1])
ax.axis('off')
ax.imshow(np.fliplr(rdiff[:,:,i]), vmin=imgmin,vmax=imgmax,cmap='gray', interpolation='nearest',origin='lower')
ax.annotate(dateinfo[i].strftime('%Y/%m/%d %H:%M'), xy=(10,10), xytext=(320, 1010),color='cyan', size=30, ha='right')
outname='./C2DATA/'+dateinfo[i].strftime('%Y%m%d_%H%M_C2_rdiff.png')
ax.set(xlim=[0, width], ylim=[height, 0], aspect=1)
fig.savefig(outname, dpi=dpi, transparent=True)
plt.close()
print("Running Difference process complete.")
return 1
###################################################################################
# MAIN (control) routine to read/prepare data and call desired processing algorithm
###################################################################################
def c2_process(fts_path, dst_path, rundiff=False, annotate_words=True, batch_mode=False):
os.makedirs(dst_path) if not os.path.isdir(dst_path) else None
dst_path_list = os.listdir(dst_path)
if not batch_mode:
for file in dst_path_list:
os.remove(dst_path + file)
# Gather list of file names
lasco_files = sorted(glob.glob('{}*.fts'.format(fts_path)))
# number of files
nf = len(lasco_files)
# Create 3D data cube to hold data, assuming all LASCO C2 data have
# array sizes of 1024x1024 pixels.
data_cube = np.empty((1024,1024,nf))
# Create an empty list to hold date/time values, which are later used for output png filenames
dates_times = []
for i in range(nf):
# read image and header from FITS file
img,hdr = fits.getdata(lasco_files[i], header=True)
# Normalize by exposure time (a good practice for LASCO data)
img = img.astype('float64') / hdr['EXPTIME']
if img.shape[0] == 512 and img.shape[1] == 512:
img = torch.from_numpy(img)
img = F.interpolate(img[None, None, :, :], size=(1024, 1024), mode='bilinear')[0, 0, :, :]
img = img.numpy()
data_cube[:, :, i] = img
# Retrieve image date/time from header; store as datetime object
dates_times.append( datetime.datetime.strptime( hdr['DATE-OBS']+' '+hdr['TIME-OBS'], '%Y/%m/%d %H:%M:%S.%f') )
print('processing med_subtract...')
# Call processing routine. Defaults to median subtraction.
if rundiff:
_ = rdiff( data_cube, dates_times )
else:
_ = med_subtract( data_cube, dst_path, dates_times , annotate_words=annotate_words)