SourceXtractorPlusPlus
0.21
SourceXtractor++, the next generation SExtractor
Loading...
Searching...
No Matches
SEFramework
src
lib
FITS
FitsImageSource.cpp
Go to the documentation of this file.
1
18
/*
19
* FitsImageSource.cpp
20
*
21
* Created on: Mar 21, 2018
22
* Author: mschefer
23
*/
24
25
#include "
SEFramework/FITS/FitsImageSource.h
"
26
#include "
SEFramework/FITS/FitsFile.h
"
27
#include "
SEUtils/VariantCast.h
"
28
#include <AlexandriaKernel/memory_tools.h>
29
#include <ElementsKernel/Exception.h>
30
#include <boost/algorithm/string/case_conv.hpp>
31
#include <boost/algorithm/string/trim.hpp>
32
#include <boost/filesystem/operations.hpp>
33
#include <boost/filesystem/path.hpp>
34
#include <boost/regex.hpp>
35
#include <fstream>
36
#include <iomanip>
37
#include <numeric>
38
#include <string>
39
40
namespace
SourceXtractor
{
41
42
using
Euclid::make_unique
;
43
44
namespace
{
45
46
ImageTile::ImageType
convertImageType(
int
bitpix) {
47
ImageTile::ImageType
image_type;
48
49
switch
(bitpix) {
50
case
FLOAT_IMG:
51
image_type =
ImageTile::FloatImage
;
52
break
;
53
case
DOUBLE_IMG:
54
image_type =
ImageTile::DoubleImage
;
55
break
;
56
case
LONG_IMG:
57
image_type =
ImageTile::IntImage
;
58
break
;
59
case
ULONG_IMG:
60
image_type =
ImageTile::UIntImage
;
61
break
;
62
case
LONGLONG_IMG:
63
image_type =
ImageTile::LongLongImage
;
64
break
;
65
default
:
66
throw
Elements::Exception
() <<
"Unsupported FITS image type: "
<< bitpix;
67
}
68
69
return
image_type;
70
}
71
72
}
73
74
FitsImageSource::FitsImageSource
(
const
std::string
& filename,
int
hdu_number
,
75
ImageTile::ImageType
image_type
,
76
std::shared_ptr<FileManager>
manager
)
77
: m_filename(filename)
78
, m_file_manager(
std
::
move
(
manager
))
79
, m_handler(m_file_manager->getFileHandler(filename))
80
, m_hdu_number(
hdu_number
) {
81
int
status
= 0;
82
int
bitpix
,
naxis
;
83
long
naxes
[3] = {1, 1, 1};
84
85
auto
acc
=
m_handler
->getAccessor<
FitsFile
>();
86
auto
fptr
=
acc
->m_fd.getFitsFilePtr();
87
88
if
(
m_hdu_number
<= 0) {
89
if
(
fits_get_hdu_num
(
fptr
, &
m_hdu_number
) < 0) {
90
throw
Elements::Exception
() <<
"Can't get the active HDU from the FITS file: "
<< filename;
91
}
92
}
93
else
{
94
switchHdu
(
fptr
,
m_hdu_number
);
95
}
96
97
fits_get_img_param
(
fptr
, 2, &
bitpix
, &
naxis
,
naxes
, &
status
);
98
if
(
status
!= 0 || (
naxis
!= 2 &&
naxis
!= 3)) {
99
char
error_message
[32];
100
fits_get_errstatus
(
status
,
error_message
);
101
throw
Elements::Exception
()
102
<<
"Can't find 2D image or data cube in FITS file: "
<< filename <<
"["
<<
m_hdu_number
<<
"]"
103
<<
" status: "
<<
status
<<
" = "
<<
error_message
;
104
}
105
106
m_width
=
naxes
[0];
107
m_height
=
naxes
[1];
108
m_depth
=
naxis
>= 3 ?
naxes
[2] : 1;
109
110
if
(
image_type
< 0) {
111
m_image_type
=
convertImageType
(
bitpix
);
112
}
113
else
{
114
m_image_type
=
image_type
;
115
}
116
}
117
118
FitsImageSource::FitsImageSource
(
const
std::string
& filename,
int
width,
int
height,
ImageTile::ImageType
image_type
,
119
const
std::shared_ptr<CoordinateSystem>
coord_system
,
bool
append,
bool
empty_primary
,
120
std::shared_ptr<FileManager>
manager
)
121
: m_filename(filename)
122
, m_file_manager(
std
::
move
(
manager
))
123
, m_handler(m_file_manager->getFileHandler(filename))
124
, m_width(width)
125
, m_height(height)
126
, m_image_type(
image_type
) {
127
128
int
status
= 0;
129
fitsfile
*
fptr
=
nullptr
;
130
131
if
(!append) {
132
// delete file if it exists already
133
boost::filesystem::remove(
m_filename
);
134
}
135
136
{
137
auto
acc
=
m_handler
->getAccessor<
FitsFile
>(
FileHandler::kWrite
);
138
fptr
=
acc
->m_fd.getFitsFilePtr();
139
140
assert
(
fptr
!=
nullptr
);
141
142
if
(
empty_primary
&&
acc
->m_fd.getImageHdus().empty()) {
143
fits_create_img
(
fptr
,
FLOAT_IMG
, 0,
nullptr
, &
status
);
144
if
(
status
!= 0) {
145
char
error_message
[32];
146
fits_get_errstatus
(
status
,
error_message
);
147
throw
Elements::Exception
() <<
"Can't create empty hdu: "
<< filename
148
<<
" status: "
<<
status
<<
" = "
<<
error_message
;
149
}
150
}
151
152
long
naxes
[2] = {width, height};
153
fits_create_img
(
fptr
,
getImageType
(), 2,
naxes
, &
status
);
154
155
if
(
fits_get_hdu_num
(
fptr
, &
m_hdu_number
) < 0) {
156
char
error_message
[32];
157
fits_get_errstatus
(
status
,
error_message
);
158
throw
Elements::Exception
() <<
"Can't get the active HDU from the FITS file: "
<< filename
159
<<
" status: "
<<
status
<<
" = "
<<
error_message
;
160
}
161
162
int
hdutype
= 0;
163
fits_movabs_hdu
(
fptr
,
m_hdu_number
, &
hdutype
, &
status
);
164
165
if
(
coord_system
) {
166
auto
headers
=
coord_system
->getFitsHeaders();
167
for
(
const
auto
&
h
:
headers
) {
168
std::ostringstream
padded_key
,
serializer
;
169
padded_key
<<
std::setw
(8) <<
std::left
<<
h
.first;
170
171
serializer
<<
padded_key
.str() <<
"= "
<<
std::left
<<
std::setw
(70) <<
h
.second;
172
auto
str =
serializer
.str();
173
174
fits_update_card
(
fptr
,
padded_key
.str().c_str(), str.c_str(), &
status
);
175
if
(
status
!= 0) {
176
char
error_message
[32];
177
fits_get_errstatus
(
status
,
error_message
);
178
throw
Elements::Exception
() <<
"Couldn't write the WCS headers: "
<< filename
179
<<
" status: "
<<
status
<<
" = "
<<
error_message
;
180
}
181
}
182
}
183
184
std::vector<char>
buffer
(width *
ImageTile::getTypeSize
(
image_type
));
185
for
(
int
i
= 0;
i
< height;
i
++) {
186
long
first_pixel
[2] = {1,
i
+ 1};
187
fits_write_pix
(
fptr
,
getDataType
(),
first_pixel
, width, &
buffer
[0], &
status
);
188
}
189
190
if
(
status
!= 0) {
191
char
error_message
[32];
192
fits_get_errstatus
(
status
,
error_message
);
193
throw
Elements::Exception
() <<
"Couldn't allocate space for new FITS file: "
<< filename
194
<<
" status: "
<<
status
<<
" = "
<<
error_message
;
195
}
196
197
acc
->m_fd.refresh();
// make sure changes to the file structure are taken into account
198
199
}
200
201
// work around for canonical name bug:
202
// our file's canonical name might be wrong if it didn't exist, so we need to make sure we get the correct handler
203
// after we created the file
204
205
m_handler
=
nullptr
;
206
m_handler
=
m_file_manager
->getFileHandler(filename);
207
}
208
209
std::shared_ptr<ImageTile>
FitsImageSource::getImageTile
(
int
x
,
int
y
,
int
width,
int
height)
const
{
210
auto
acc
=
m_handler
->getAccessor<
FitsFile
>();
211
auto
fptr
=
acc
->m_fd.getFitsFilePtr();
212
switchHdu
(
fptr
,
m_hdu_number
);
213
214
auto
tile
=
ImageTile::create
(
m_image_type
,
x
,
y
, width, height,
215
std::const_pointer_cast<ImageSource>
(
shared_from_this
()));
216
217
long
first_pixel
[3] = {
x
+ 1,
y
+ 1,
m_current_layer
+1};
218
long
last_pixel
[3] = {
x
+ width,
y
+ height,
m_current_layer
+1};
219
long
increment
[3] = {1, 1, 1};
220
int
status
= 0;
221
222
fits_read_subset
(
fptr
,
getDataType
(),
first_pixel
,
last_pixel
,
increment
,
223
nullptr
,
tile
->getDataPtr(),
nullptr
, &
status
);
224
if
(
status
!= 0) {
225
char
error_message
[32];
226
fits_get_errstatus
(
status
,
error_message
);
227
throw
Elements::Exception
() <<
"Error reading image tile from FITS file."
228
<<
" status: "
<<
status
<<
" = "
<<
error_message
;
229
}
230
231
return
tile
;
232
}
233
234
void
FitsImageSource::saveTile
(
ImageTile
&
tile
) {
235
auto
acc
=
m_handler
->getAccessor<
FitsFile
>(
FileHandler::kWrite
);
236
auto
fptr
=
acc
->m_fd.getFitsFilePtr();
237
switchHdu
(
fptr
,
m_hdu_number
);
238
239
int
x
=
tile
.getPosX();
240
int
y
=
tile
.getPosY();
241
int
width =
tile
.getWidth();
242
int
height =
tile
.getHeight();
243
244
long
first_pixel
[2] = {
x
+ 1,
y
+ 1};
245
long
last_pixel
[2] = {
x
+ width,
y
+ height};
246
int
status
= 0;
247
248
fits_write_subset
(
fptr
,
getDataType
(),
first_pixel
,
last_pixel
,
tile
.getDataPtr(), &
status
);
249
if
(
status
!= 0) {
250
char
error_message
[32];
251
fits_get_errstatus
(
status
,
error_message
);
252
throw
Elements::Exception
() <<
"Error saving image tile to FITS file."
253
<<
" status: "
<<
status
<<
" = "
<<
error_message
;
254
}
255
fits_flush_buffer
(
fptr
, 0, &
status
);
256
}
257
258
void
FitsImageSource::switchHdu
(
fitsfile
*
fptr
,
int
hdu_number
)
const
{
259
int
status
= 0;
260
int
hdu_type
= 0;
261
262
fits_movabs_hdu
(
fptr
,
hdu_number
, &
hdu_type
, &
status
);
263
264
if
(
status
!= 0) {
265
char
error_message
[32];
266
fits_get_errstatus
(
status
,
error_message
);
267
throw
Elements::Exception
() <<
"Could not switch to HDU # "
<<
hdu_number
<<
" in file "
<<
m_filename
268
<<
" status: "
<<
status
<<
" = "
<<
error_message
;
269
}
270
if
(
hdu_type
!=
IMAGE_HDU
) {
271
throw
Elements::Exception
() <<
"Trying to access non-image HDU in file "
<<
m_filename
;
272
}
273
}
274
275
void
FitsImageSource::setLayer
(
int
layer
) {
276
if
(
layer < 0 && layer >
=
m_depth
) {
277
throw
Elements::Exception
() <<
"Trying to access an inexistent data cube layer ("
<<
layer
<<
") in "
<<
m_filename
;
278
}
279
m_current_layer
=
layer
;
280
}
281
282
std::unique_ptr<std::vector<char>
>
FitsImageSource::getFitsHeaders
(
int
&
number_of_records
)
const
{
283
number_of_records
= 0;
284
std::string
records
;
285
286
auto
&
headers
=
getMetadata
();
287
for
(
const
auto
&
record
:
headers
) {
288
const
auto
&
key
=
record
.first;
289
290
std::string
record_string
(
key
);
291
if
(
record_string
.size() > 8) {
292
throw
Elements::Exception
() <<
"FITS keyword longer than 8 characters"
;
293
}
294
else
if
(
record_string
.size() < 8) {
295
record_string
+=
std::string
(8 -
record_string
.size(),
' '
);
296
}
297
298
if
(
headers
.at(
key
).m_value.type() ==
typeid
(
std::string
)) {
299
record_string
+=
"= '"
+
VariantCast<std::string>
(
headers
.at(
key
).m_value) +
"'"
;
300
}
301
else
{
302
record_string
+=
"= "
+
VariantCast<std::string>
(
headers
.at(
key
).m_value);
303
}
304
305
if
(
record_string
.size() > 80) {
306
throw
Elements::Exception
() <<
"FITS record longer than 80 characters"
;
307
}
308
309
310
if
(
record_string
.size() < 80) {
311
record_string
+=
std::string
(80 -
record_string
.size(),
' '
);
312
}
313
314
records
+=
record_string
;
315
number_of_records
++;
316
}
317
318
std::string
record_string
(
"END"
);
319
record_string
+=
std::string
(80 -
record_string
.size(),
' '
);
320
records
+=
record_string
;
321
322
auto
buffer
=
make_unique<std::vector<char>
>(
records
.begin(),
records
.end());
323
buffer
->emplace_back(0);
324
return
buffer
;
325
}
326
327
const
std::map<std::string, MetadataEntry>
&
FitsImageSource::getMetadata
()
const
{
328
auto
acc
=
m_handler
->getAccessor<
FitsFile
>();
329
return
acc
->m_fd.getHDUHeaders(
m_hdu_number
);
330
}
331
332
void
FitsImageSource::setMetadata
(
const
std::string
&
key
,
const
MetadataEntry
& value) {
333
auto
acc
=
m_handler
->getAccessor<
FitsFile
>(
FileHandler::kWrite
);
334
auto
fptr
=
acc
->m_fd.getFitsFilePtr();
335
switchHdu
(
fptr
,
m_hdu_number
);
336
337
std::ostringstream
padded_key
,
serializer
;
338
padded_key
<<
std::setw
(8) <<
std::left
<<
key
;
339
340
serializer
<<
padded_key
.str() <<
"= "
<<
std::left
<<
std::setw
(70)
341
<<
VariantCast<std::string>
(value.
m_value
);
342
auto
str =
serializer
.str();
343
344
int
status
= 0;
345
fits_update_card
(
fptr
,
padded_key
.str().c_str(), str.c_str(), &
status
);
346
347
if
(
status
!= 0) {
348
char
error_message
[32];
349
fits_get_errstatus
(
status
,
error_message
);
350
throw
Elements::Exception
() <<
"Couldn't write the metadata: "
<< str
351
<<
" status: "
<<
status
<<
" = "
<<
error_message
;
352
}
353
354
// update the metadata
355
acc
->m_fd.getHDUHeaders(
m_hdu_number
)[
key
] = value;
356
}
357
358
int
FitsImageSource::getDataType
()
const
{
359
switch
(
m_image_type
) {
360
default
:
361
case
ImageTile::FloatImage
:
362
return
TFLOAT
;
363
case
ImageTile::DoubleImage
:
364
return
TDOUBLE
;
365
case
ImageTile::IntImage
:
366
return
TINT
;
367
case
ImageTile::UIntImage
:
368
return
TUINT
;
369
case
ImageTile::LongLongImage
:
370
return
TLONGLONG
;
371
}
372
}
373
374
int
FitsImageSource::getImageType
()
const
{
375
switch
(
m_image_type
) {
376
default
:
377
case
ImageTile::FloatImage
:
378
return
FLOAT_IMG
;
379
case
ImageTile::DoubleImage
:
380
return
DOUBLE_IMG
;
381
case
ImageTile::IntImage
:
382
return
LONG_IMG
;
383
case
ImageTile::UIntImage
:
384
return
ULONG_IMG
;
385
case
ImageTile::LongLongImage
:
386
return
LONGLONG_IMG
;
387
}
388
}
389
390
//FIXME add missing types
391
392
}
FitsFile.h
FitsImageSource.h
x
std::shared_ptr< DependentParameter< std::shared_ptr< EngineParameter > > > x
Definition
MoffatModelFittingTask.cpp:94
y
std::shared_ptr< DependentParameter< std::shared_ptr< EngineParameter > > > y
Definition
MoffatModelFittingTask.cpp:94
VariantCast.h
std::ostringstream
std::string
Elements::Exception
Euclid::FilePool::FileHandler::kWrite
kWrite
SourceXtractor::FitsFile
represents access to a whole FITS file and handles loading and caching FITS headers
Definition
FitsFile.h:43
SourceXtractor::FitsImageSource::m_file_manager
std::shared_ptr< FileManager > m_file_manager
Definition
FitsImageSource.h:129
SourceXtractor::FitsImageSource::setLayer
void setLayer(int layer)
Definition
FitsImageSource.cpp:275
SourceXtractor::FitsImageSource::m_width
int m_width
Definition
FitsImageSource.h:134
SourceXtractor::FitsImageSource::m_filename
std::string m_filename
Definition
FitsImageSource.h:128
SourceXtractor::FitsImageSource::getMetadata
const std::map< std::string, MetadataEntry > & getMetadata() const override
Definition
FitsImageSource.cpp:327
SourceXtractor::FitsImageSource::m_hdu_number
int m_hdu_number
Definition
FitsImageSource.h:132
SourceXtractor::FitsImageSource::getImageTile
std::shared_ptr< ImageTile > getImageTile(int x, int y, int width, int height) const override
Definition
FitsImageSource.cpp:209
SourceXtractor::FitsImageSource::m_image_type
ImageTile::ImageType m_image_type
Definition
FitsImageSource.h:137
SourceXtractor::FitsImageSource::saveTile
void saveTile(ImageTile &tile) override
Definition
FitsImageSource.cpp:234
SourceXtractor::FitsImageSource::FitsImageSource
FitsImageSource(const std::string &filename, int hdu_number=0, ImageTile::ImageType image_type=ImageTile::AutoType, std::shared_ptr< FileManager > manager=FileManager::getDefault())
Definition
FitsImageSource.cpp:74
SourceXtractor::FitsImageSource::getFitsHeaders
std::unique_ptr< std::vector< char > > getFitsHeaders(int &number_of_records) const
Definition
FitsImageSource.cpp:282
SourceXtractor::FitsImageSource::m_height
int m_height
Definition
FitsImageSource.h:135
SourceXtractor::FitsImageSource::m_depth
int m_depth
Definition
FitsImageSource.h:136
SourceXtractor::FitsImageSource::getImageType
int getImageType() const
Definition
FitsImageSource.cpp:374
SourceXtractor::FitsImageSource::getDataType
int getDataType() const
Definition
FitsImageSource.cpp:358
SourceXtractor::FitsImageSource::setMetadata
void setMetadata(const std::string &key, const MetadataEntry &value) override
Definition
FitsImageSource.cpp:332
SourceXtractor::FitsImageSource::m_handler
std::shared_ptr< FileHandler > m_handler
Definition
FitsImageSource.h:130
SourceXtractor::FitsImageSource::switchHdu
void switchHdu(fitsfile *fptr, int hdu_number) const
Definition
FitsImageSource.cpp:258
SourceXtractor::FitsImageSource::m_current_layer
int m_current_layer
Definition
FitsImageSource.h:139
SourceXtractor::ImageTile
Definition
ImageTile.h:34
SourceXtractor::ImageTile::getTypeSize
static size_t getTypeSize(ImageType image_type)
Definition
ImageTile.h:117
SourceXtractor::ImageTile::ImageType
ImageType
Definition
ImageTile.h:37
SourceXtractor::ImageTile::UIntImage
@ UIntImage
Definition
ImageTile.h:42
SourceXtractor::ImageTile::DoubleImage
@ DoubleImage
Definition
ImageTile.h:40
SourceXtractor::ImageTile::FloatImage
@ FloatImage
Definition
ImageTile.h:39
SourceXtractor::ImageTile::IntImage
@ IntImage
Definition
ImageTile.h:41
SourceXtractor::ImageTile::LongLongImage
@ LongLongImage
Definition
ImageTile.h:43
SourceXtractor::ImageTile::create
static std::shared_ptr< ImageTile > create(ImageType image_type, int x, int y, int width, int height, std::shared_ptr< ImageSource > source=nullptr)
Definition
ImageTile.cpp:24
std::function
std::left
T left(T... args)
std::move
T move(T... args)
Euclid::make_unique
std::unique_ptr< T > make_unique(Args &&... args)
SourceXtractor
Definition
Aperture.h:30
std
STL namespace.
std::setw
T setw(T... args)
std::enable_shared_from_this< ImageSource >::shared_from_this
T shared_from_this(T... args)
SourceXtractor::MetadataEntry
Definition
ImageSource.h:42
SourceXtractor::MetadataEntry::m_value
value_t m_value
Definition
ImageSource.h:45
Generated by
1.10.0