From d59ee7fddca85c751fd5b774ca7af46b0b49db14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Du=C5=A1an=20Poizl?= Date: Fri, 28 Feb 2025 10:40:14 +0100 Subject: [PATCH] Add additional colormaps --- imagescrollarea.cpp | 5 +++++ imagescrollarea.h | 1 + imagewidget.cpp | 23 +++++++++++++++++++++++ imagewidget.h | 4 ++++ mainwindow.cpp | 29 +++++++++++++++++++++++++++++ resources/colormap.png | Bin 0 -> 5539 bytes resources/resources.qrc | 1 + shaders/image.frag | 16 +++++----------- 8 files changed, 68 insertions(+), 11 deletions(-) create mode 100644 resources/colormap.png diff --git a/imagescrollarea.cpp b/imagescrollarea.cpp index b350db3..260a416 100644 --- a/imagescrollarea.cpp +++ b/imagescrollarea.cpp @@ -58,6 +58,11 @@ void ImageScrollArea::setBayerMask(int mask) m_imageWidget->setBayerMask(mask); } +void ImageScrollArea::setColormap(int colormap) +{ + m_imageWidget->setColormap(colormap); +} + void ImageScrollArea::updateScrollbars(int valueH, int stepH, int maxH, int valueV, int stepV, int maxV) { if(maxH > 0) diff --git a/imagescrollarea.h b/imagescrollarea.h index 6ddb6f2..1ff9a5a 100644 --- a/imagescrollarea.h +++ b/imagescrollarea.h @@ -16,6 +16,7 @@ public: void allocateThumbnails(const QStringList &paths); void showThumbnail(bool enable); void setBayerMask(int mask); + void setColormap(int colormap); protected: void updateScrollbars(int valueH, int stepH, int maxH, int valueV, int stepV, int maxV); public slots: diff --git a/imagewidget.cpp b/imagewidget.cpp index 6f2e6ea..f69d3be 100644 --- a/imagewidget.cpp +++ b/imagewidget.cpp @@ -258,6 +258,12 @@ void ImageWidgetGL::setBayerMask(int mask) update(); } +void ImageWidgetGL::setColormap(int colormap) +{ + m_colormapIdx = colormap; + update(); +} + void ImageWidgetGL::setMTFParams(const MTFParam ¶ms) { m_mtfParams = params; @@ -600,6 +606,7 @@ void ImageWidgetGL::paintGL() m_program->setUniformValue("filtering", m_scale > 1.0f ? FILTERING : 1); m_program->setUniformValue("lut_table", 2); m_program->setUniformValue("srgb", m_srgb); + m_program->setUniformValue("colormapIdx", m_colormapIdx); f->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); m_vao->release(); } @@ -702,6 +709,7 @@ void ImageWidgetGL::initializeGL() m_program->setAttributeBuffer("qt_MultiTexCoord0", GL_FLOAT, sizeof(float)*2, 2, sizeof(float)*4); m_program->setUniformValue("qt_Texture0", (GLuint)0); m_program->setUniformValue("lut_table", (GLuint)2); + m_program->setUniformValue("colormap", (GLuint)3); m_program->setUniformValue("scale", 1.0f, 0.0f); m_debayerProgram = std::unique_ptr(new QOpenGLShaderProgram); @@ -764,6 +772,21 @@ void ImageWidgetGL::initializeGL() m_lut->allocateStorage(); m_lut->bind(2); + QImage colormap(":/colormap.png"); + colormap = colormap.convertToFormat(QImage::Format_RGBA8888); + qDebug() << colormap; + m_colormap = std::make_unique(QOpenGLTexture::Target1DArray); + m_colormap->setSize(colormap.width()); + m_colormap->setLayers(colormap.height()); + m_colormap->setFormat(QOpenGLTexture::RGBA8_UNorm); + m_colormap->setMinMagFilters(QOpenGLTexture::Linear, QOpenGLTexture::Linear); + m_colormap->setWrapMode(QOpenGLTexture::ClampToEdge); + m_colormap->allocateStorage(); + for(int i=0; isetData(0, i, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, colormap.scanLine(i)); + + m_colormap->bind(3); + if(m_rawImage) setImage(m_rawImage, m_currentImg); } diff --git a/imagewidget.h b/imagewidget.h index 648b3a7..946059a 100644 --- a/imagewidget.h +++ b/imagewidget.h @@ -26,6 +26,7 @@ public: virtual void bestFit() = 0; virtual void setBayerMask(int mask) = 0; + virtual void setColormap(int colormap) = 0; virtual void setOffset(float dx, float dy) = 0; virtual void allocateThumbnails(const QStringList &paths) = 0; @@ -63,6 +64,7 @@ class ImageWidgetGL : public QOpenGLWidget, public ImageWidget std::unique_ptr m_vaoThumb; std::unique_ptr m_thumbnailTexture; std::unique_ptr m_lut; + std::unique_ptr m_colormap; GLuint m_debayerTex = 0; std::shared_ptr m_rawImage; std::shared_ptr m_wcs; @@ -87,6 +89,7 @@ class ImageWidgetGL : public QOpenGLWidget, public ImageWidget int m_maxTextureSize = 0; int m_maxArrayLayers = 0; int m_firstRed[2] = {0, 0}; + int m_colormapIdx = 0; QVector m_thumnails; Database *m_database = nullptr; QPointF m_lastPos; @@ -102,6 +105,7 @@ public: void allocateThumbnails(const QStringList &paths) override; QVector2D getImagePixelCoord(const QVector2D &pos); void setBayerMask(int mask) override; + void setColormap(int colormap) override; void setOffset(float dx, float dy) override; void setMTFParams(const MTFParam ¶ms) override; void superPixel(bool enable) override; diff --git a/mainwindow.cpp b/mainwindow.cpp index d6b1fad..73bb658 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -207,6 +207,29 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) settings.setValue("mainwindow/bayermask", data); }); + QStringList colormaps = {"Autumn", "Bone", "Jet", "Winter", "Rainbow", "Ocean", "Summer", "Spring", "Cool", "HSV", "Pink", "Hot", "Parula", "Magma", + "Inferno", "Plasma", "Viridis", "Cividis", "Twilight", "Twilight shifted", "Turbo", "Deepgreen"}; + QMenu *colormapMenu = viewMenu->addMenu(tr("Colormap")); + QActionGroup *colormapActionGroup = new QActionGroup(this); + int idx = 0; + QImage cmImg(":/colormap.png"); + for(QString &colormap : colormaps) + { + QImage icon = cmImg.copy(0, idx, cmImg.width(), 1).scaled(32, 32); + QAction *action = colormapActionGroup->addAction(colormap); + action->setIcon(QPixmap::fromImage(icon)); + action->setCheckable(true); action->setData(idx++); + colormapMenu->addAction(action); + } + viewMenu->addMenu(colormapMenu); + connect(colormapActionGroup, &QActionGroup::triggered, [this](QAction *action){ + int data = action->data().toInt(); + m_image->setColormap(data); + QSettings settings; + settings.setValue("mainwindow/colormap", data); + }); + + QAction *thumbnailsAction = viewMenu->addAction(tr("Thumbnails"), Qt::Key_F2, [this](bool checked){ if(SettingsDialog::loadThumbsizes())m_ringList->clearThumbnails(); m_image->allocateThumbnails(m_ringList->imageNames()); @@ -291,6 +314,12 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) case 3: bggrAction->setChecked(true); break; } + int colormap = settings.value("mainwindow/colormap", 4).toInt(); + if(colormap >= 0 && colormap < colormapActionGroup->actions().size()) + colormapActionGroup->actions().at(colormap)->setChecked(true); + + m_image->setBayerMask(bayermask); + m_image->setColormap(colormap); QStringList standardLocations = QStandardPaths::standardLocations(QStandardPaths::PicturesLocation); if(standardLocations.size()) diff --git a/resources/colormap.png b/resources/colormap.png new file mode 100644 index 0000000000000000000000000000000000000000..1fc330b2706a5d4642c3e55baea85554955a5009 GIT binary patch literal 5539 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.nouspiro.tenmon.png ../translations/tenmon_pt_BR.qm ../about/help_en + colormap.png ../about/help_en diff --git a/shaders/image.frag b/shaders/image.frag index aabf6ba..e311e7e 100644 --- a/shaders/image.frag +++ b/shaders/image.frag @@ -1,5 +1,6 @@ uniform sampler2D qt_Texture0; uniform sampler3D lut_table; +uniform sampler1DArray colormap; uniform vec3 mtf_param[3]; uniform vec2 unit_scale; uniform bool bw; @@ -7,6 +8,7 @@ uniform bool invert; uniform bool srgb; uniform bool false_color; uniform int filtering; +uniform int colormapIdx; in vec2 qt_TexCoord0; layout(location = 0) out vec4 color; @@ -26,17 +28,9 @@ vec4 MTF(vec4 x, vec4 low, vec4 mid, vec4 high) vec3 falsecolor(float color) { - const vec3 pallete[] = vec3[]( - vec3(1.0, 0.0, 1.0), //magneta - vec3(0.0, 0.0, 1.0), //blue - vec3(0.0, 1.0, 1.0), //cyan - vec3(0.0, 1.0, 0.0), //green - vec3(1.0, 1.0, 0.0), //yellow - vec3(1.0, 0.0, 0.0), vec3(1.0, 0.0, 0.0));//red - color *= 5.0; - int i = int(color); - float f = fract(color); - return mix(pallete[i], pallete[i+1], f);// * (f * 0.5 + 0.5); + color *= 255.0 / 256.0; + color += 0.5 / 256.0; + return texture(colormap, vec2(color, colormapIdx)).rgb; } vec3 checker()