Open lgrcia opened 1 year ago
First attempt to satellite trace detection using prose:
from prose import Sequence, blocks
SatDetection = Sequence([
blocks.detection.AutoSourceDetection(), # source detection
blocks.Get('sources', 'path')
])
SatDetection.run(fm.all_images)
from prose.core.source import TraceSource
traces = []
for sources, path in zip(SatDetection.get.values['sources'], SatDetection.get.values['path']):
long_sources = [source for source in sources if isinstance(source, TraceSource)]
long_sources = [source for source in long_sources if source.a > 200] # Not elegant way to discriminate between any source and a Satellite trace
if len(long_sources) > 0:
traces.append([path,long_sources])
def plot_trace(path, traces):
im = Image(path)
im.show()
for t in traces:
t.plot()
#Check the trace
plot_trace(*traces[2])
Is working but in order to look at LEO satellites databases and to detect which satellite constellation correspond the trace we need to get from the image the JD, FoV, approximated image center, exp time and observatory location.
Thanks @szunigaf!
for sources, path in zip(SatDetection.get.values['sources'], SatDetection.get.values['path']): long_sources = [source for source in sources if isinstance(source, TraceSource)] long_sources = [source for source in long_sources if source.a > 200] if len(long_sources) > 0: traces.append([path,long_sources])
I think the
TraceDetection
block now does most of this task (otherwise it should).JD, FoV, approximated image center, exp time and observatory location
These should be easily obtained through the Image
and Telescope
objects.
As I told you the trace vertexes are computed the same way as any other sources, using the semi major axis assuming traces are elongated ellipses (this was pointed out by @MouradGHACHOUI). As this is wrong, it bias the true coordinates of the vertexes. In prose/blocks/detection.py - line 237
sources = np.array([TraceSource.from_region(region) for region in regions])
i.e. sources are created from skimage region properties. This object contains the bounding box of the source (the trace) that can be used to locate the trace vertexes. We could simply reimplement the from_region for the TraceSource
object.
It could be a nice first contribution if you like :) (I can help with the process)
New version of LEO detection sequence:
# LEO detection sequence
SatDetection = Sequence([
#blocks.detection.AutoSourceDetection(minor_length=200), # source detection
blocks.detection.TraceDetection(minor_length=200), # source detection
blocks.Get(
"sources",
"fov",
"filter",
jd=lambda im: im.fits_header[im.telescope.keyword_jd], # JD at the start of the exposure
date_utc=lambda im: Time(im.date).fits, # Datetime (UTC) at the start of the exposure
c=lambda im: im.skycoord, # center approx (deg)
earth_location=lambda im: im.telescope.earth_location, # telescope location
telescope=lambda im: im.telescope.name,
exp_time=lambda im: im.fits_header[im.telescope.keyword_exposure_time], # exposure time
path=lambda im: im.metadata['path'], #path of the image
arrays = False,
),
])
SatDetection.run(fm.all_images)
SatTraces = SatDetection[1]
# Check the data
print(SatTraces.jd)
print(SatTraces.date_utc)
print(SatTraces.exp_time)
print(SatTraces.earth_location[0].geodetic)
# sources[image][trace source]
SatTraces.sources[0][0].vertexes
Then plot the results just to double check:
def plot_trace(path, traces):
im = FITSImage(path)
im.show()
for t in traces:
t.plot()
# Example
plot_trace(SatTraces.path[0],SatTraces.sources[0])
To do: Adapt the Tracesource
to get the real vertices value.
May be we can update a
and b
after create TraceSource
in the following way. region_parser
is a custom region parser function, can be passed to TraceDetection
. The custom region parser is support in #95.
def region_parser(source, region):
if isinstance(source, TraceSource):
width = region.bbox[3] - region.bbox[1]
height = region.bbox[2] - region.bbox[0]
theta = source.orientation
source.a = (np.sin(theta) * height - np.cos(theta) * width) / (
np.sin(theta) ** 2 - np.cos(theta) ** 2
)
source.b = (np.sin(theta) * width - np.cos(theta) * height) / (
np.sin(theta) ** 2 - np.cos(theta) ** 2
)
...
TraceDetection(parser=region_parser).run(image)
'''
The equation used to update
a
,b
is not checked and may be wrong.
Indeed! I think once #95 is done we will have a very elegant way to define how the sources properties are set!
I think for the TraceSource
it makes sense to define a default parser like the one you just wrote.
Edit: Actually the default TraceSource
creation can simply be handled by implementing its from_region
class method, as suggested above. But providing a callable for specific properties setting (without subclassing, which is the only difference here) might be interesting for some applications.
Started with @szunigaf and @MouradGHACHOUI.
TraceSource
(for now based on semi-major axis but it is wrong)