Replace PCL with LibXISF

This commit is contained in:
2023-02-10 09:10:57 +01:00
parent c7f4e3747a
commit c47ecbedb8
290 changed files with 117 additions and 209222 deletions
+93 -120
View File
@@ -9,14 +9,13 @@
#include <iostream>
#include <libexif/exif-data.h>
#include <fitsio2.h>
#include <pcl/XISF.h>
#include <libxisf.h>
#include "rawimage.h"
#include "starfit.h"
#include "wcslib/wcshdr.h"
#ifdef COLOR_MANAGMENT
#include <QColorSpace>
static pcl::ICCProfile sRgbIccProfile((void*)QColorSpace(QColorSpace::SRgb).iccProfile().data());
#endif
LoadRunable::LoadRunable(const QString &file, Image *receiver, AnalyzeLevel level, bool thumbnail) :
@@ -286,97 +285,82 @@ bool loadFITS(const QString path, ImageInfoData &info, RawImage **image)
return true;
}
#include "pcl/ICCProfileTransformation.h"
template<typename T, typename PCLtype, int CVtype>
bool loadPCLImage(pcl::XISFReader &xisf, RawImage **image)
{
PCLtype pclImage;
xisf.ReadImage(pclImage);
pclImage.Status().DisableInitialization();
#ifdef COLOR_MANAGMENT
pcl::ICCProfile iccProfile = xisf.ReadICCProfile();
if(iccProfile.IsProfile() && iccProfile != sRgbIccProfile)
{
pcl::ICCProfileTransformation iccTran;
iccTran.DisableParallelProcessing();
iccTran.Add(iccProfile);
iccTran.Add(sRgbIccProfile);
iccTran >> pclImage;
}
#endif
int numChannels = pclImage.NumberOfChannels();
cv::Mat cvImg[numChannels];
for(int i=0; i<numChannels; i++)
{
T *p = pclImage.PixelData(i);
cvImg[i].create(pclImage.Height(), pclImage.Width(), CVtype);
memcpy(cvImg[i].ptr(0), p, pclImage.Width()*pclImage.Height()*sizeof(T));
}
if(numChannels==3)
{
cv::Mat merged;
cv::merge(cvImg, 3, merged);
*image = new RawImage(merged);
return true;
}
if(numChannels==1)
{
*image = new RawImage(cvImg[0]);
return true;
}
return false;
}
bool loadXISF(const QString &path, ImageInfoData &info, RawImage **image)
{
try
{
pcl::XISF::EnsurePTLUTInitialized();
pcl::String pclPath = path.utf16();
pcl::XISFReader xisf;
xisf.Open(pclPath);
uint8_t bps = xisf.ImageOptions().bitsPerSample;
bool floatType = xisf.ImageOptions().ieeefpSampleFormat;
bool signedInt = xisf.ImageOptions().signedIntegers;
bool complex = xisf.ImageOptions().complexSample;
LibXISF::XISFReader xisf;
xisf.open(path);
auto fitskeywords = xisf.ReadFITSKeywords();
const LibXISF::Image &xisfImage = xisf.getImage(0);
auto fitskeywords = xisfImage.fitsKeywords();
for(auto fits : fitskeywords)
{
info.fitsHeader.append(fits);
}
auto imageproperties = xisf.ReadImageProperties();
auto imageproperties = xisfImage.imageProperties();
for(auto prop : imageproperties)
{
info.fitsHeader.append(prop);
}
info.wcs = std::make_shared<WCSData>(xisf.ImageInfo().width, xisf.ImageInfo().height, info.fitsHeader);
info.info.append({QObject::tr("Width"), QString::number(xisf.ImageInfo().width)});
info.info.append({QObject::tr("Height"), QString::number(xisf.ImageInfo().height)});
info.wcs = std::make_shared<WCSData>(xisfImage.width(), xisfImage.height(), info.fitsHeader);
info.info.append({QObject::tr("Width"), QString::number(xisfImage.width())});
info.info.append({QObject::tr("Height"), QString::number(xisfImage.height())});
if(!info.wcs->valid())info.wcs.reset();
if(floatType && bps == 32)
return loadPCLImage<float, pcl::FImage, CV_32F>(xisf, image);
if(!complex && !signedInt)
if(xisfImage.channelCount() == 1)
{
switch(bps)
switch(xisfImage.sampleFormat())
{
case 8:
return loadPCLImage<uint8_t, pcl::UInt8Image, CV_8U>(xisf, image);
case 16:
return loadPCLImage<uint16_t, pcl::UInt16Image, CV_16U>(xisf, image);
case LibXISF::Image::UInt8:
*image = new RawImage(xisfImage.width(), xisfImage.height(), RawImage::UINT8);
std::memcpy((*image)->data(), xisfImage.imageData(), xisfImage.imageDataSize());
break;
case LibXISF::Image::UInt16:
*image = new RawImage(xisfImage.width(), xisfImage.height(), RawImage::UINT16);
std::memcpy((*image)->data(), xisfImage.imageData(), xisfImage.imageDataSize());
break;
case LibXISF::Image::Float32:
*image = new RawImage(xisfImage.width(), xisfImage.height(), RawImage::FLOAT32);
std::memcpy((*image)->data(), xisfImage.imageData(), xisfImage.imageDataSize());
break;
default:
break;
}
}
else if(xisfImage.channelCount() == 3)
{
LibXISF::Image tmpImage = xisfImage;
tmpImage.convertPixelStorageTo(LibXISF::Image::Normal);
switch(tmpImage.sampleFormat())
{
case LibXISF::Image::UInt8:
*image = new RawImage(tmpImage.width(), tmpImage.height(), RawImage::UINT8C3);
std::memcpy((*image)->data(), tmpImage.imageData(), tmpImage.imageDataSize());
break;
case LibXISF::Image::UInt16:
*image = new RawImage(tmpImage.width(), tmpImage.height(), RawImage::UINT16C3);
std::memcpy((*image)->data(), tmpImage.imageData(), tmpImage.imageDataSize());
break;
case LibXISF::Image::Float32:
*image = new RawImage(tmpImage.width(), tmpImage.height(), RawImage::FLOAT32C3);
std::memcpy((*image)->data(), tmpImage.imageData(), tmpImage.imageDataSize());
break;
default:
break;
}
}
if(*image)
return true;
}
catch (pcl::Error err)
catch (LibXISF::Error &err)
{
info.info.append(QPair<QString, QString>("Error", err.FormatInfo().ToUTF8().c_str()));
qDebug() << "Failed to load XISF" << err.FormatInfo().ToUTF8().c_str();
info.info.append(QPair<QString, QString>("Error", err.what()));
qDebug() << "Failed to load XISF" << err.what();
return false;
}
info.info.append({QObject::tr("Error"), QObject::tr("Unsupported sample format")});
return false;
@@ -433,6 +417,7 @@ void LoadRunable::run()
exif_data_free(exif);
}
rawImage = new RawImage(img);
qDebug() << "LoadQImage" << timer.elapsed();
}
if(rawImage && m_analyzeLevel >= Statistics && !m_thumbnail)
@@ -541,27 +526,27 @@ bool readXISFHeader(const QString &path, ImageInfoData &info)
{
try
{
pcl::String pclPath = path.utf16();
pcl::XISFReader xisf;
xisf.Open(pclPath);
LibXISF::XISFReader xisf;
const LibXISF::Image &image = xisf.getImage(0, false);
xisf.open(path);
auto fitskeywords = xisf.ReadFITSKeywords();
auto fitskeywords = image.fitsKeywords();
for(auto fits : fitskeywords)
{
info.fitsHeader.append(fits);
}
auto imageproperties = xisf.ReadImageProperties();
auto imageproperties = image.fitsKeywords();
for(auto prop : imageproperties)
{
info.fitsHeader.append(prop);
}
info.wcs = std::make_shared<WCSData>(xisf.ImageInfo().width, xisf.ImageInfo().height, info.fitsHeader);
info.wcs = std::make_shared<WCSData>(image.width(), image.height(), info.fitsHeader);
if(!info.wcs->valid())info.wcs.reset();
}
catch (pcl::Error err)
catch (LibXISF::Error &err)
{
qDebug() << err.FormatInfo().ToUTF8().c_str();
qDebug() << err.what();
return false;
}
return true;
@@ -574,26 +559,6 @@ ConvertRunable::ConvertRunable(const QString &in, const QString &out, const QStr
{
}
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"};
@@ -677,29 +642,37 @@ void ConvertRunable::run()
{
if(m_format == "XISF")
{
pcl::XISFOptions options;
pcl::FITSKeywordArray fitskeywords;
for(auto &record : imageinfo.fitsHeader)
try
{
pcl::FITSHeaderKeyword key(pcl::IsoString(record.key.data()), pcl::IsoString(record.valueToByteArray().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;
}
LibXISF::XISFWriter xisf;
int channelCount = rawimage->mat().channels();
LibXISF::Image::SampleFormat sampleFormat;
switch(CV_MAT_DEPTH(rawimage->dataType()))
{
case CV_8U: sampleFormat = LibXISF::Image::UInt8; break;
case CV_16U: sampleFormat = LibXISF::Image::UInt16; break;
case CV_32F: sampleFormat = LibXISF::Image::Float32; break;
default: return;
}
LibXISF::Image image(rawimage->width(), rawimage->height(), channelCount, sampleFormat, channelCount == 1 ? LibXISF::Image::Gray : LibXISF::Image::RGB, LibXISF::Image::Normal);
std::memcpy(image.imageData(), rawimage->data(), image.imageDataSize());
for(auto &record : imageinfo.fitsHeader)
{
if(record.value.type() == QVariant::Bool)
image.addFITSKeyword({record.key, record.value.toBool() ? "T" : "F", record.comment});
else
image.addFITSKeyword({record.key, record.value.toString(), record.comment});
}
xisf.writeImage(image);
xisf.save(m_outfile);
}
catch(LibXISF::Error &err)
{
qDebug() << "Failed to save XISF image" << err.what();
delete rawimage;
}
}
if(m_format == "FITS")