From 6b9ea5e4b96b2dd94d81b500c1ed247b2593f1b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Du=C5=A1an=20Poizl?= Date: Mon, 13 Jun 2022 18:02:58 +0200 Subject: [PATCH] Add support for WCS --- CMakeLists.txt | 3 +- imageinfo.cpp | 90 +++++++++++++++++++++++++++++++++++++++++++ imageinfo.h | 30 +++++++++++++++ imagescrollareagl.cpp | 34 +++++++++++----- imagescrollareagl.h | 6 ++- loadrunable.cpp | 10 +++++ mainwindow.cpp | 2 +- 7 files changed, 162 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2c95b7d..c79e3c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,7 @@ find_library(GSLCBLAS_LIB gslcblas REQUIRED) find_library(EXIF_LIB exif REQUIRED) find_library(FITS_LIB cfitsio REQUIRED) find_library(RAW_LIB NAMES raw_r REQUIRED) +find_library(WCS_LIB wcs REQUIRED) set(TENMON_SRC about.cpp @@ -58,7 +59,7 @@ else() target_link_directories(tenmon PRIVATE 3rdparty/lib/Linux) endif() -target_link_libraries(tenmon Qt5::Widgets Qt5::Sql ${OpenCV_LIBS} ${GSL_LIB} ${GSLCBLAS_LIB} ${EXIF_LIB} ${FITS_LIB} ${RAW_LIB}) +target_link_libraries(tenmon Qt5::Widgets Qt5::Sql ${OpenCV_LIBS} ${GSL_LIB} ${GSLCBLAS_LIB} ${EXIF_LIB} ${FITS_LIB} ${RAW_LIB} ${WCS_LIB}) target_link_libraries(tenmon PCL lcms lz4 RFC6234 zlib) if(LIBRAW_STATIC) diff --git a/imageinfo.cpp b/imageinfo.cpp index 544fae6..0ebacd5 100644 --- a/imageinfo.cpp +++ b/imageinfo.cpp @@ -1,6 +1,9 @@ #include "imageinfo.h" #include +#include #include +#include +#include static const QVector noEditableKey = {"SIMPLE", "BITPIX", "NAXIS", "NAXIS1", "NAXIS2", "NAXIS3", "EXTEND", "BZERO", "BSCALE"}; @@ -47,3 +50,90 @@ void ImageInfo::setInfo(const ImageInfoData &info) } expandAll(); } + +void WCSData::freeWCS() +{ + wcsvfree(&nwcs, &wcs); + nwcs = 0; + wcs = nullptr; +} + +WCSData::WCSData(char *header, int nrec) +{ + int stat[NWCSFIX]; + int nreject = 0; + int status = wcspih(header, nrec, 1, 0, &nreject, &nwcs, &wcs); + if(status != 0) + { + freeWCS(); + return; + } + status = wcsfix(0, 0, wcs, stat); + if(status != 0 || wcs->crpix[0] == 0) + freeWCS(); +} + +WCSData::~WCSData() +{ + if(wcs) + freeWCS(); +} + +SkyPoint WCSData::pixelToWorld(QPointF pixel) const +{ + if(wcs == nullptr)return SkyPoint(); + double pixcrd[2] = {pixel.x(), pixel.y()}; + double imgcrd[8] = {0}; + double phi = 0; + double theta = 0; + double world[8] = {0}; + int stat[NWCSFIX] = {0}; + int status = wcsp2s(wcs, 1, 2, pixcrd, imgcrd, &phi, &theta, world, stat); + if(status == 0) + { + return SkyPoint(world[0], world[1]); + } + return SkyPoint(); +} + +QPointF WCSData::worldToPixel(SkyPoint point) const +{ + return QPointF(); +} + +void WCSData::calculateBounds(double &minRa, double &maxRa, double &minDec, double &maxDec) +{ + minRa = -1000; + maxRa = 1000; + minDec = -1000; + maxDec = 1000; +} + +SkyPoint::SkyPoint() : ra(NAN), dec(NAN) +{ + +} + +SkyPoint::SkyPoint(double ra, double dec) : ra(ra), dec(dec) +{ +} + +void SkyPoint::set(double ra, double dec) +{ + this->ra = ra; + this->dec = dec; +} + +QString SkyPoint::toString() const +{ + if(std::isnan(ra) || std::isnan(dec)) + return QString(); + + QTime t(0, 0); + t = t.addSecs(ra * 240); + + double deg, min, sec; + min = std::modf(dec, °) * 60; + sec = std::modf(min, &min) * 60; + return QString("RA: %1 DEC: %2° %3' %4\"").arg(t.toString("HH'h' mm'm' ss's'")).arg(deg, 2, 'f', 0, '0').arg(min, 2, 'f', 0, '0').arg(sec, 2, 'f', 0, '0'); +} diff --git a/imageinfo.h b/imageinfo.h index 2f9a6fe..841b04a 100644 --- a/imageinfo.h +++ b/imageinfo.h @@ -2,6 +2,8 @@ #define IMAGEINFO_H #include +#include +#include struct FITSRecord { @@ -11,10 +13,38 @@ struct FITSRecord bool editable() const; }; +class SkyPoint +{ + double ra = NAN; + double dec = NAN; +public: + SkyPoint(); + SkyPoint(double ra, double dec); + void set(double ra, double dec); + double RA() const { return ra; } + double DEC() const { return dec; } + QString toString() const; +}; + +class WCSData +{ + int nwcs = 0; + struct wcsprm *wcs = nullptr; + void freeWCS(); +public: + WCSData(); + WCSData(char *header, int nrec); + ~WCSData(); + SkyPoint pixelToWorld(QPointF pixel) const; + QPointF worldToPixel(SkyPoint point) const; + void calculateBounds(double &minRa, double &maxRa, double &minDec, double &maxDec); +}; + struct ImageInfoData { QVector fitsHeader; QVector> info; + std::shared_ptr wcs; }; Q_DECLARE_METATYPE(ImageInfoData); diff --git a/imagescrollareagl.cpp b/imagescrollareagl.cpp index 59b2d8f..ee2284d 100644 --- a/imagescrollareagl.cpp +++ b/imagescrollareagl.cpp @@ -85,7 +85,7 @@ ImageWidget::~ImageWidget() makeCurrent(); } -void ImageWidget::setImage(std::shared_ptr &image, int index) +void ImageWidget::setImage(std::shared_ptr image, int index) { if(image == nullptr)return; @@ -112,6 +112,11 @@ void ImageWidget::setImage(std::shared_ptr &image, int index) update(); } +void ImageWidget::setWCS(std::shared_ptr wcs) +{ + m_wcs = wcs; +} + void ImageWidget::setScale(float scale) { m_scale = scale; @@ -456,12 +461,19 @@ void ImageWidget::mouseMoveEvent(QMouseEvent *event) QVector2D pos = QVector2D(event->pos()); QVector2D pix = (pos + offset) / m_scale; QVector3D rgb; + + SkyPoint sky; + if(m_wcs) + { + sky = m_wcs->pixelToWorld(QPointF(pix.x(), pix.y())); + } + if(m_rawImage->pixel(pix.x(), pix.y(), rgb)) { if(m_bwImg) - emit status(tr("L: %1").arg(rgb.x())); + emit status(tr("L:%1 %2 X:%3 Y:%4").arg(rgb.x()).arg(sky.toString()).arg((int)pix.x()).arg((int)pix.y())); else - emit status(tr("R: %1 G: %2 B: %3").arg(rgb.x()).arg(rgb.y()).arg(rgb.z())); + emit status(tr("R:%1 G:%2 B:%3 %4 X:%5 Y:%6").arg(rgb.x()).arg(rgb.y()).arg(rgb.z()).arg(sky.toString()).arg((int)pix.x()).arg((int)pix.y())); } } } @@ -551,13 +563,17 @@ ImageScrollAreaGL::~ImageScrollAreaGL() } -void ImageScrollAreaGL::setImage(std::shared_ptr image, int index) +void ImageScrollAreaGL::setImage(Image *image) { - m_imageWidget->setImage(image, index); - m_imgWidth = image->width(); - m_imgHeight = image->height(); - if(m_bestFit)bestFit(); - updateScrollbars(); + if(image && image->rawImage()) + { + m_imageWidget->setImage(image->rawImage(), image->number()); + m_imageWidget->setWCS(image->info().wcs); + m_imgWidth = image->rawImage()->width(); + m_imgHeight = image->rawImage()->height(); + if(m_bestFit)bestFit(); + updateScrollbars(); + } } ImageWidget *ImageScrollAreaGL::imageWidget() diff --git a/imagescrollareagl.h b/imagescrollareagl.h index 121c08e..a42f6f9 100644 --- a/imagescrollareagl.h +++ b/imagescrollareagl.h @@ -40,6 +40,7 @@ class ImageWidget : public QOpenGLWidget std::unique_ptr m_transferOptions; std::unique_ptr m_thumbnailTexture; std::shared_ptr m_rawImage; + std::shared_ptr m_wcs; int m_width, m_height; int m_imgWidth, m_imgHeight; int m_currentImg; @@ -61,8 +62,9 @@ class ImageWidget : public QOpenGLWidget public: explicit ImageWidget(Database *database, QWidget *parent = nullptr); ~ImageWidget() override; - void setImage(std::shared_ptr &image, int index); + void setImage(std::shared_ptr image, int index); void setImage(const QPixmap &pixmap); + void setWCS(std::shared_ptr wcs); void setScale(float scale); void blockRepaint(bool block); void allocateThumbnails(const QStringList &paths); @@ -103,7 +105,7 @@ class ImageScrollAreaGL : public QWidget public: explicit ImageScrollAreaGL(Database *database, QWidget *parent = nullptr); ~ImageScrollAreaGL() override; - void setImage(std::shared_ptr image, int index); + void setImage(Image *image); ImageWidget* imageWidget(); void setThumbnails(int count); protected: diff --git a/loadrunable.cpp b/loadrunable.cpp index 057402b..5c2d415 100644 --- a/loadrunable.cpp +++ b/loadrunable.cpp @@ -12,6 +12,7 @@ #include #include "rawimage.h" #include "starfit.h" +#include "wcslib/wcshdr.h" LoadRunable::LoadRunable(const QString &file, Image *receiver, AnalyzeLevel level, bool thumbnail) : m_file(file), @@ -166,6 +167,15 @@ int loadFITSHeader(fitsfile *file, ImageInfoData &info) return status; } } + + char *header = nullptr; + int nrec = 0; + fits_hdr2str(file, TRUE, nullptr, 0, &header, &nrec, &status); + if(status == 0) + { + info.wcs = std::make_shared(header, nrec); + } + fits_free_memory(header, &status); return status; } diff --git a/mainwindow.cpp b/mainwindow.cpp index 55d82a9..2b5d0c8 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -341,7 +341,7 @@ void MainWindow::pixmapLoaded(Image *image) { if(image->rawImage()) { - m_imageGL->setImage(image->rawImage(), image->number()); + m_imageGL->setImage(image); } }