Add ColorFilterArray

This commit is contained in:
2023-02-05 09:20:56 +01:00
parent 024f770ee0
commit c264ca12eb
2 changed files with 127 additions and 6 deletions
+98 -6
View File
@@ -90,6 +90,36 @@ static std::unordered_map<Image::ColorSpace, QString> colorSpaceToString;
static std::unordered_map<int, size_t> vectorTypeSizes;
static std::unordered_map<int, size_t> matrixTypeSizes;
static const std::unordered_map<QString, std::pair<QString, int>> fitsNameToPropertyIdTypeConvert = {
{"OBSERVER", {"Observer:Name", QMetaType::QString}},
{"RADECSYS", {"Observation:CelestialReferenceSystem", QMetaType::QString}},
{"CRVAL1", {"Observation:Center:Dec", QMetaType::Double}},
{"CRVAL2", {"Observation:Center:RA", QMetaType::Double}},
{"CRPIX1", {"Observation:Center:X", QMetaType::Double}},
{"CRPIX2", {"Observation:Center:Y", QMetaType::Double}},
{"EQUINOX", {"Observation:Equinox", QMetaType::Double}},
{"SITELAT", {"Observation:Location:Latitude", QMetaType::Double}},
{"SITELONG", {"Observation:Location:Longitude", QMetaType::Double}},
{"OBJECT", {"Observation:Object:Name", QMetaType::QString}},
{"DEC", {"Observation:Object:Dec", QMetaType::Double}},
{"RA", {"Observation:Object:RA", QMetaType::Double}},
{"DATE-OBS", {"Observation:Time:Start", QMetaType::QDateTime}},
{"DATE-END", {"Observation:Time:End", QMetaType::QDateTime}},
{"GAIN", {"Instrument:Camera:Gain", QMetaType::Float}},
{"ISOSPEED", {"Instrument:Camera:ISOSpeed", QMetaType::Int}},
{"INSTRUME", {"Instrument:Camera:Name", QMetaType::QString}},
{"ROTATANG", {"Instrument:Camera:Rotation", QMetaType::Float}},
{"XBINNING", {"Instrument:Camera:XBinning", QMetaType::Int}},
{"YBINNING", {"Instrument:Camera:YBinning", QMetaType::Int}},
{"EXPTIME", {"Instrument:ExposureTime", QMetaType::Float}},
{"FILTER", {"Instrument:Filter:Name", QMetaType::QString}},
{"FOCUSPOS", {"Instrument:Focuser:Position", QMetaType::Float}},
{"CCD-TEMP", {"Instrument:Sensor:Temperature", QMetaType::Float}},
{"APTDIA", {"Instrument:Telescope:Aperture", QMetaType::Float}},
{"FOCALLEN", {"Instrument:Telescope:FocalLength", QMetaType::Float}},
{"TELESCOP", {"Instrument:Telescope:Name", QMetaType::QString}},
};
static void byteShuffle(QByteArray &data, int itemSize)
{
if(itemSize > 1)
@@ -310,6 +340,16 @@ void Image::setColorSpace(ColorSpace newColorSpace)
_colorSpace = newColorSpace;
}
const ColorFilterArray Image::colorFilterArray() const
{
return _cfa;
}
void Image::setColorFilterArray(const ColorFilterArray cfa)
{
_cfa = cfa;
}
const std::vector<Property>& Image::imageProperties() const
{
return _properties;
@@ -317,14 +357,21 @@ const std::vector<Property>& Image::imageProperties() const
void Image::addProperty(const Property &property)
{
for(auto &p : _properties)
{
if(p.id == property.id)
throw Error("Duplicate property id");
}
if(_propertiesId.count(property.id))
throw Error("Duplicate property id");
_propertiesId[property.id] = _properties.size();
_properties.push_back(property);
}
void Image::updateProperty(const Property &property)
{
if(!_propertiesId.count(property.id))
addProperty(property);
else
_properties[_propertiesId[property.id]] = property;
}
const std::vector<FITSKeyword> Image::fitsKeywords() const
{
return _fitsKeywords;
@@ -335,6 +382,19 @@ void Image::addFITSKeyword(const FITSKeyword &keyword)
_fitsKeywords.push_back(keyword);
}
bool Image::addFITSKeywordAsProperty(const QString &name, const QVariant &value)
{
if(fitsNameToPropertyIdTypeConvert.count(name))
{
auto &c = fitsNameToPropertyIdTypeConvert.at(name);
Property prop(c.first, value);
prop.value.convert(c.second);
updateProperty(prop);
return true;
}
return false;
}
void *Image::imageData()
{
return _dataBlock.data.data();
@@ -603,9 +663,11 @@ void XISFReader::readImageElement()
if(_xml->tokenType() == QXmlStreamReader::StartElement)
{
if(_xml->name() == "Property")
image._properties.push_back(readPropertyElement());
image.addProperty(readPropertyElement());
else if(_xml->name() == "FITSKeyword")
image._fitsKeywords.push_back(readFITSKeyword());
else if(_xml->name() == "ColorFilterArray")
image._cfa = readCFA();
else if(_xml->name() == "ICCProfile")
{
DataBlock icc = readDataBlock();
@@ -764,6 +826,23 @@ void XISFReader::readCompression(DataBlock &dataBlock)
}
}
ColorFilterArray XISFReader::readCFA()
{
ColorFilterArray cfa;
QXmlStreamAttributes attributes = _xml->attributes();
if(attributes.hasAttribute("pattern") && attributes.hasAttribute("width") && attributes.hasAttribute("height"))
{
cfa.pattern = attributes.value("pattern").toString();
cfa.width = attributes.value("width").toInt();
cfa.height = attributes.value("height").toInt();
}
else
{
throw Error("ColorFilterArray element missing one of mandatory attributes");
}
return cfa;
}
XISFWriter::XISFWriter()
{
_xml = std::make_unique<QXmlStreamWriter>();
@@ -874,6 +953,8 @@ void XISFWriter::writeImageElement(const Image &image)
for(auto &fitsKeyword : image._fitsKeywords)
writeFITSKeyword(fitsKeyword);
writeCFA(image);
_xml->writeEndElement();
}
@@ -979,6 +1060,17 @@ void XISFWriter::writeMetadata()
_xml->writeEndElement();
}
void XISFWriter::writeCFA(const Image &image)
{
if(image._cfa.width && image._cfa.height)
{
_xml->writeEmptyElement("ColorFilterArray");
_xml->writeAttribute("pattern", image._cfa.pattern);
_xml->writeAttribute("width", QString::number(image._cfa.width));
_xml->writeAttribute("height", QString::number(image._cfa.height));
}
}
#define REGISTER_METATYPE(type) { int id = qMetaTypeId<type>(); \
typeToId.insert({#type, id}); idToType.insert({id, #type}); }
+29
View File
@@ -74,6 +74,24 @@ struct LIBXISF_EXPORT FITSKeyword
QString comment;
};
/**
Describe color filter array. Each letter in pattern describe color of element.
0 - A nonexistent or undefined CFA element
R - Red
G - Green
B - Blue
W - White or panchromatic
C - Cyan
M - Magenta
Y - Yellow
*/
struct LIBXISF_EXPORT ColorFilterArray
{
int width = 0;
int height = 0;
QString pattern;
};
typedef std::pair<double, double> Bounds;
class LIBXISF_EXPORT Image
@@ -138,10 +156,17 @@ public:
void setSampleFormat(SampleFormat newSampleFormat);
ColorSpace colorSpace() const;
void setColorSpace(ColorSpace newColorSpace);
const ColorFilterArray colorFilterArray() const;
void setColorFilterArray(const ColorFilterArray cfa);
const std::vector<Property> &imageProperties() const;
void addProperty(const Property &property);
void updateProperty(const Property &property);
const std::vector<FITSKeyword> fitsKeywords() const;
void addFITSKeyword(const FITSKeyword &keyword);
/** Add image property while doing automatic conversion of FITS name to XISF property
* For example OBSERVER => Observer:Name, SITELAT => Observation:Location:Latitude
*/
bool addFITSKeywordAsProperty(const QString &name, const QVariant &value);
void* imageData();
template<typename T>
@@ -178,7 +203,9 @@ private:
ColorSpace _colorSpace = Gray;
DataBlock _dataBlock;
QByteArray _iccProfile;
ColorFilterArray _cfa;
std::vector<Property> _properties;
std::map<QString, uint32_t> _propertiesId;
std::vector<FITSKeyword> _fitsKeywords;
friend class XISFReader;
@@ -207,6 +234,7 @@ private:
void readDataElement(DataBlock &dataBlock);
DataBlock readDataBlock();
void readCompression(DataBlock &dataBlock);
ColorFilterArray readCFA();
std::unique_ptr<QIODevice> _io;
std::unique_ptr<QXmlStreamReader> _xml;
@@ -230,6 +258,7 @@ private:
void writePropertyElement(const Property &property);
void writeFITSKeyword(const FITSKeyword &keyword);
void writeMetadata();
void writeCFA(const Image &image);
std::unique_ptr<QXmlStreamWriter> _xml;
QByteArray _xisfHeader;
QByteArray _attachmentsData;