Add saving to FITS and XISF

This commit is contained in:
2022-04-19 16:57:54 +02:00
parent f68a9c4d7c
commit 92f9920f24
6 changed files with 198 additions and 4 deletions
+147
View File
@@ -492,3 +492,150 @@ bool readXISFHeader(const QString &path, ImageInfoData &info)
}
return true;
}
ConvertRunable::ConvertRunable(const QString &in, const QString &out) :
m_infile(in),
m_outfile(out)
{
}
template<typename T>
void writeXISFImage(pcl::XISFWriter &writer, RawImage *rawimg)
{
const cv::Mat &cvmat = rawimg->mat();
T pclimg(rawimg->width(), rawimg->height(), cvmat.channels() == 1 ? pcl::ColorSpace::Gray : pcl::ColorSpace::RGB);
if(cvmat.channels() == 1)
{
memcpy(pclimg.PixelData(0), rawimg->data(), rawimg->size()*sizeof(typename T::sample));
}
if(cvmat.channels() == 3)
{
std::vector<cv::Mat> channels;
cv::split(cvmat, channels);
memcpy(pclimg.PixelData(0), channels[0].data, rawimg->size()*sizeof(typename T::sample));
memcpy(pclimg.PixelData(1), channels[1].data, rawimg->size()*sizeof(typename T::sample));
memcpy(pclimg.PixelData(2), channels[2].data, rawimg->size()*sizeof(typename T::sample));
}
writer.WriteImage(pclimg);
}
void writeFITSImage(fitsfile *fw, RawImage *rawimage, ImageInfoData &imageinfo)
{
static QStringList skipKeys = {"SIMPLE", "BITPIX", "NAXIS", "NAXIS1", "NAXIS2", "NAXIS3", "BZERO", "BSCALE", "EXTEND"};
int status = 0;
long firstpix[3] = {1,1,1};
int channels = rawimage->mat().channels();
int naxis = channels == 1 ? 2 : 3;
long naxes[3] = {(int)rawimage->width(), (int)rawimage->height(), rawimage->mat().channels()};
std::vector<cv::Mat> mat;
if(channels == 1)
mat.push_back(rawimage->mat());
else
cv::split(rawimage->mat(), mat);
switch(CV_MAT_DEPTH(rawimage->dataType()))
{
case CV_8U:
fits_create_img(fw, BYTE_IMG, naxis, naxes, &status);
for(int i=0; i<channels; i++)
{
firstpix[2] = i+1;
fits_write_pix(fw, TBYTE, firstpix, rawimage->size(), mat[i].data, &status);
}
break;
case CV_16U:
fits_create_img(fw, USHORT_IMG, naxis, naxes, &status);
for(int i=0; i<channels; i++)
{
firstpix[2] = i+1;
fits_write_pix(fw, TUSHORT, firstpix, rawimage->size(), mat[i].data, &status);
}
break;
case CV_32F:
fits_create_img(fw, FLOAT_IMG, naxis, naxes, &status);
for(int i=0; i<channels; i++)
{
firstpix[2] = i+1;
fits_write_pix(fw, TFLOAT, firstpix, rawimage->size(), mat[i].data, &status);
}
break;
}
for(const FITSRecord &record : imageinfo.fitsHeader)
{
if(skipKeys.contains(record.key))continue;
bool isdouble;
bool isint;
bool isbool = record.value.toString() == "T" || record.value.toString() == "F";
double vald = record.value.toDouble(&isdouble);
int valb = record.value.toString() == "T";
long long vall = record.value.toLongLong(&isint);
QByteArray str = record.value.toString().toLatin1();
if(isdouble)
fits_write_key(fw, TDOUBLE, record.key.data(), &vald, record.comment.isEmpty() ? nullptr : record.comment.data(), &status);
else if(isint)
fits_write_key(fw, TLONGLONG, record.key.data(), &vall, record.comment.isEmpty() ? nullptr : record.comment.data(), &status);
else if(isbool)
fits_write_key(fw, TLOGICAL, record.key.data(), &valb, record.comment.isEmpty() ? nullptr : record.comment.data(), &status);
else if(record.key == "COMMENT")
fits_write_comment(fw, record.comment.isEmpty() ? nullptr : record.comment.data(), &status);
else if(record.key == "HISTORY")
fits_write_history(fw, record.comment.isEmpty() ? nullptr : record.comment.data(), &status);
else
fits_write_key(fw, TSTRING, record.key.data(), str.isEmpty() ? nullptr : str.data(), record.comment.isEmpty() ? nullptr : record.comment.data(), &status);
}
}
void ConvertRunable::run()
{
ImageInfoData imageinfo;
RawImage *rawimage = nullptr;
if(m_infile.endsWith(".FITS", Qt::CaseInsensitive) || m_infile.endsWith(".FIT", Qt::CaseInsensitive))
loadFITS(m_infile, imageinfo, &rawimage);
if(m_infile.endsWith(".XISF", Qt::CaseInsensitive))
loadXISF(m_infile, imageinfo, &rawimage);
if(rawimage)
{
if(m_outfile.endsWith(".XISF", Qt::CaseInsensitive))
{
pcl::XISFOptions options;
pcl::FITSKeywordArray fitskeywords;
for(auto &record : imageinfo.fitsHeader)
{
pcl::FITSHeaderKeyword key(pcl::IsoString(record.key.data()), pcl::IsoString(record.value.toString().toLatin1().data()), pcl::IsoString(record.comment.data()));
fitskeywords.Append(key);
}
pcl::XISFWriter xisf;
xisf.Create(m_outfile.utf16(), 1);
xisf.WriteFITSKeywords(fitskeywords);
switch(CV_MAT_DEPTH(rawimage->dataType()))
{
case CV_8U:
writeXISFImage<pcl::UInt8Image>(xisf, rawimage);
break;
case CV_16U:
writeXISFImage<pcl::UInt16Image>(xisf, rawimage);
break;
case CV_32F:
writeXISFImage<pcl::Image>(xisf, rawimage);
break;
}
}
if(m_outfile.endsWith(".FITS", Qt::CaseInsensitive) || m_outfile.endsWith(".FIT", Qt::CaseInsensitive))
{
int status = 0;
fitsfile *fw;
if(QFileInfo(m_outfile).exists())QFile::remove(m_outfile);
fits_create_diskfile(&fw, m_outfile.toLocal8Bit().data(), &status);
writeFITSImage(fw, rawimage, imageinfo);
fits_close_file(fw, &status);
}
delete rawimage;
}
}