From 0a803ace10ad283e21b52f382cfcc75a2d66b601 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Du=C5=A1an=20Poizl?= Date: Tue, 10 Oct 2023 22:48:40 +0200 Subject: [PATCH] Prepare for three channels STF --- imagescrollareagl.cpp | 10 +++--- imagescrollareagl.h | 7 ++-- mainwindow.cpp | 2 +- rawimage.cpp | 1 - shaders/image.frag | 13 +++----- shaders/thumb.frag | 10 +++--- stfslider.cpp | 26 ++++++++++++--- stfslider.h | 4 ++- stretchtoolbar.cpp | 78 ++++++++++++++++++++++++++++++++++++++----- stretchtoolbar.h | 15 ++++++++- 10 files changed, 125 insertions(+), 41 deletions(-) diff --git a/imagescrollareagl.cpp b/imagescrollareagl.cpp index 2f3fefa..3de26d8 100644 --- a/imagescrollareagl.cpp +++ b/imagescrollareagl.cpp @@ -225,11 +225,9 @@ QVector2D ImageWidget::getImagePixelCoord(const QVector2D &pos) return (pos + offset) / m_scale; } -void ImageWidget::setMTFParams(float low, float mid, float high) +void ImageWidget::setMTFParams(const MTFParam ¶ms) { - m_low = low; - m_mid = mid; - m_high = high; + m_mtfParams = params; update(); } @@ -339,7 +337,7 @@ void ImageWidget::paintGL() m_thumbnailProgram->bind(); f->glUniform3i(m_thumbnailProgram->uniformLocation("viewport_row"), width(), height(), width()/THUMB_SIZE_BORDER); f->glUniform3i(m_thumbnailProgram->uniformLocation("thumb_size"), THUMB_SIZE_BORDER/2, THUMB_SIZE_BORDER, THUMB_SIZE_BORDER_Y); - m_thumbnailProgram->setUniformValue("mtf_param", m_low, m_mid, m_high); + m_thumbnailProgram->setUniformValueArray("mtf_param", m_mtfParams.blackPoint, 3, 3); m_thumbnailProgram->setUniformValue("invert", m_invert); m_thumbnailProgram->setUniformValue("offset", 0, m_dy); QMatrix4x4 mvp; @@ -388,7 +386,7 @@ void ImageWidget::paintGL() m_program->bind(); m_program->setUniformValue("viewport", (float)width(), (float)height()); m_program->setUniformValue("offset", std::floor(dx), std::floor(dy)); - m_program->setUniformValue("mtf_param", m_low, m_mid, m_high); + m_program->setUniformValueArray("mtf_param", m_mtfParams.blackPoint, 3, 3); m_program->setUniformValue("zoom", 1.0f/m_scale); m_program->setUniformValue("bw", m_bwImg && !m_superpixel); m_program->setUniformValue("false_color", m_falseColor && m_bwImg); diff --git a/imagescrollareagl.h b/imagescrollareagl.h index 428e4f7..53cb7b1 100644 --- a/imagescrollareagl.h +++ b/imagescrollareagl.h @@ -14,6 +14,7 @@ #include "rawimage.h" #include "imageringlist.h" #include "database.h" +#include "stretchtoolbar.h" struct ImageThumb { @@ -46,9 +47,7 @@ class ImageWidget : public QOpenGLWidget int m_width, m_height; int m_imgWidth = -1, m_imgHeight = -1; int m_currentImg = 0; - float m_low = 0.0f; - float m_mid = 0.5f; - float m_high = 1.0; + MTFParam m_mtfParams; float m_dx = 0, m_dy = 0; float m_scale = 1.0f; int m_scaleStop = 0; @@ -81,7 +80,7 @@ public: void allocateThumbnails(const QStringList &paths); QVector2D getImagePixelCoord(const QVector2D &pos); public slots: - void setMTFParams(float low, float mid, float high); + void setMTFParams(const MTFParam ¶ms); void setOffset(float dx, float dy); void superPixel(bool enable); void invert(bool enable); diff --git a/mainwindow.cpp b/mainwindow.cpp index 1f51c76..dcc97b7 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -80,7 +80,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) connect(m_imageGL->imageWidget(), &ImageWidget::status, statusBar, &StatusBar::newStatus); m_stretchPanel = new StretchToolbar(this); - connect(m_stretchPanel, SIGNAL(paramChanged(float,float,float)), m_imageGL->imageWidget(), SLOT(setMTFParams(float,float,float))); + connect(m_stretchPanel, &StretchToolbar::paramChanged, m_imageGL->imageWidget(), &ImageWidget::setMTFParams); connect(m_stretchPanel, &StretchToolbar::autoStretch, [&](){ m_stretchPanel->stretchImage(m_ringList->currentImage().get()); }); connect(m_stretchPanel, &StretchToolbar::invert, m_imageGL->imageWidget(), &ImageWidget::invert); connect(m_stretchPanel, &StretchToolbar::superPixel, m_imageGL->imageWidget(), &ImageWidget::superPixel); diff --git a/rawimage.cpp b/rawimage.cpp index 7f9f015..203e530 100644 --- a/rawimage.cpp +++ b/rawimage.cpp @@ -183,7 +183,6 @@ void calcStats(const T *data, size_t n, RawImage::Stats &stats) uint32_t median = findMedian(histogram[i]); stats.m_median[i] = median; - qDebug() << i << median << median / 65535; uint32_t madHist[65536] = {0}; madHist[0] = histogram[i][median]; for(size_t o = 1; o < histSize; o++) diff --git a/shaders/image.frag b/shaders/image.frag index a6a86bd..d0410dd 100644 --- a/shaders/image.frag +++ b/shaders/image.frag @@ -1,12 +1,11 @@ #version 330 uniform sampler2D qt_Texture0; -uniform vec3 mtf_param; +uniform vec3 mtf_param[3]; uniform bool bw; uniform bool invert; uniform bool srgb; uniform bool false_color; -uniform vec3 whiteBalance; in vec2 qt_TexCoord0; layout(location = 0) out vec4 color; @@ -17,11 +16,11 @@ vec3 Linear2sRGB(vec3 color) greaterThan(color, vec3(0.0031308))); } -vec4 MTF(vec4 x, vec3 m) +vec4 MTF(vec4 x, vec4 low, vec4 mid, vec4 high) { - x = (x - m.x) / (m.z - m.x); + x = (x - low) / (high - low); x = clamp(x, vec4(0.0), vec4(1.0)); - return ((m.y - 1) * x) / ((2 * m.y - 1) * x - m.y); + return ((mid - 1) * x) / ((2 * mid - 1) * x - mid); } vec3 falsecolor(float color) @@ -48,7 +47,7 @@ void main(void) { color = texture(qt_Texture0, qt_TexCoord0); if(bw)color = color.rrra; - color = MTF(color, mtf_param); + color = MTF(color, vec4(mtf_param[0], 0.0), vec4(mtf_param[1], 0.5), vec4(mtf_param[2], 1.0)); if(false_color)color.rgb = falsecolor(color.r); if(invert)color.rgb = vec3(1.0) - color.rgb; @@ -57,8 +56,6 @@ void main(void) if(srgb)color.rgb = Linear2sRGB(color.rgb); - color.rgb *= whiteBalance; - if(any(lessThan(qt_TexCoord0, vec2(0.0))) || any(greaterThan(qt_TexCoord0, vec2(1.0)))) color = vec4(0.0, 0.0, 0.0, 1.0); diff --git a/shaders/thumb.frag b/shaders/thumb.frag index 6829fbe..8264942 100644 --- a/shaders/thumb.frag +++ b/shaders/thumb.frag @@ -1,22 +1,22 @@ #version 330 uniform sampler2DArray qt_Texture0; -uniform vec3 mtf_param; +uniform vec3 mtf_param[3]; uniform bool invert; in vec3 qt_TexCoord0; layout(location = 0) out vec4 color; -vec4 MTF(vec4 x, vec3 m) +vec4 MTF(vec4 x, vec4 low, vec4 mid, vec4 high) { - x = (x - m.x) / (m.z - m.x); + x = (x - low) / (high - low); x = clamp(x, vec4(0.0), vec4(1.0)); - return ((m.y - 1) * x) / ((2 * m.y - 1) * x - m.y); + return ((mid - 1) * x) / ((2 * mid - 1) * x - mid); } void main(void) { color = texture(qt_Texture0, qt_TexCoord0); - color = MTF(color, mtf_param); + color = MTF(color, vec4(mtf_param[0], 0.0), vec4(mtf_param[1], 0.5), vec4(mtf_param[2], 1.0)); if(invert)color = vec4(1.0) - color; color.a = 1.0; } diff --git a/stfslider.cpp b/stfslider.cpp index af5e5c2..f0fc906 100644 --- a/stfslider.cpp +++ b/stfslider.cpp @@ -10,18 +10,34 @@ static float clamp(float x) return std::min(std::max(x, 0.0f), 1.0f); } -STFSlider::STFSlider(QWidget *parent) : QWidget(parent) +STFSlider::STFSlider(const QColor &color, QWidget *parent) : QWidget(parent) { setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); setMinimumWidth(100); - setMinimumHeight(15); - setMaximumHeight(15); setMouseTracking(true); + + if(color == Qt::white) + { + setMaximumHeight(15); + setMinimumHeight(15); + } + else + { + setMaximumHeight(7); + setMinimumHeight(7); + } m_blackPoint = 0; m_midPoint = 0.5; m_whitePoint = 1; m_grabbed = -1; m_fineTune = false; + m_color = color; + if(color == Qt::blue || color == Qt::red) + m_threshold = 1.1f; + else if(color == Qt::green) + m_threshold = 0.8f; + else + m_threshold = 0.4f; setToolTip(tr("Press Shift for fine tuning")); } @@ -60,7 +76,7 @@ void STFSlider::paintEvent(QPaintEvent *event) { qreal p = i/32.0f; qreal c = std::pow(p, 1.0/2.2)*255; - gradient.setColorAt(p, QColor(c, c, c)); + gradient.setColorAt(p, QColor(m_color.redF()*c, m_color.greenF()*c, m_color.blueF()*c)); } QPainterPath tick(QPointF(0, 0)); @@ -75,7 +91,7 @@ void STFSlider::paintEvent(QPaintEvent *event) auto drawTick = [&](qreal p) { - painter.setPen(p < 0.4 ? Qt::white : Qt::black); + painter.setPen(p < m_threshold ? Qt::white : Qt::black); painter.resetTransform(); painter.translate(w*p, 0); painter.drawPath(tick); diff --git a/stfslider.h b/stfslider.h index f86530a..dd3eee9 100644 --- a/stfslider.h +++ b/stfslider.h @@ -13,8 +13,10 @@ class STFSlider : public QWidget int m_grabbed; bool m_fineTune; float m_fineTuneX; + QColor m_color; + float m_threshold; public: - explicit STFSlider(QWidget *parent = nullptr); + explicit STFSlider(const QColor &color = Qt::white, QWidget *parent = nullptr); float blackPoint() const; float midPoint() const; float whitePoint() const; diff --git a/stretchtoolbar.cpp b/stretchtoolbar.cpp index f438308..b4ee306 100644 --- a/stretchtoolbar.cpp +++ b/stretchtoolbar.cpp @@ -18,13 +18,55 @@ float MTF(float x, float m) StretchToolbar::StretchToolbar(QWidget *parent) : QToolBar(tr("Stretch toolbar"), parent) { setObjectName("stretchtoolbar"); - m_stfSlider = new STFSlider(this); - addWidget(m_stfSlider); - connect(m_stfSlider, SIGNAL(paramChanged(float, float, float)), this, SIGNAL(paramChanged(float,float,float))); + QWidget *lum = new QWidget(this); + QVBoxLayout *vbox1 = new QVBoxLayout(lum); + m_stfSlider = new STFSlider(Qt::white, this); + vbox1->addWidget(m_stfSlider); + + /*m_stfSliderR = new STFSlider(Qt::red, this); + m_stfSliderG = new STFSlider(Qt::green, this); + m_stfSliderB = new STFSlider(Qt::blue, this); + QWidget *rgb = new QWidget(this); + QVBoxLayout *vbox2 = new QVBoxLayout(rgb); + vbox2->setSpacing(0); + vbox2->addWidget(m_stfSliderR); + vbox2->addWidget(m_stfSliderG); + vbox2->addWidget(m_stfSliderB);*/ + + m_stack = new QStackedWidget(this); + m_stack->addWidget(lum); + //m_stack->addWidget(rgb); + //m_stack->setCurrentIndex(0); + addWidget(m_stack); + + connect(m_stfSlider, &STFSlider::paramChanged, [this](float blackPoint, float midPoint, float whitePoint){ + m_mtfParam.blackPoint[0] = m_mtfParam.blackPoint[1] = m_mtfParam.blackPoint[2] = blackPoint; + m_mtfParam.midPoint[0] = m_mtfParam.midPoint[1] = m_mtfParam.midPoint[2] = midPoint; + m_mtfParam.whitePoint[0] = m_mtfParam.whitePoint[1] = m_mtfParam.whitePoint[2] = whitePoint; + emit paramChanged(m_mtfParam); + }); + /*connect(m_stfSliderR, &STFSlider::paramChanged, [this](float blackPoint, float midPoint, float whitePoint){ + m_mtfParam.blackPoint[0] = blackPoint; + m_mtfParam.midPoint[0] = midPoint; + m_mtfParam.whitePoint[0] = whitePoint; + emit paramChanged(m_mtfParam); + }); + connect(m_stfSliderG, &STFSlider::paramChanged, [this](float blackPoint, float midPoint, float whitePoint){ + m_mtfParam.blackPoint[1] = blackPoint; + m_mtfParam.midPoint[1] = midPoint; + m_mtfParam.whitePoint[1] = whitePoint; + emit paramChanged(m_mtfParam); + }); + connect(m_stfSliderB, &STFSlider::paramChanged, [this](float blackPoint, float midPoint, float whitePoint){ + m_mtfParam.blackPoint[2] = blackPoint; + m_mtfParam.midPoint[2] = midPoint; + m_mtfParam.whitePoint[2] = whitePoint; + emit paramChanged(m_mtfParam); + });*/ QAction *autoStretchButton = addAction(QIcon(":/nuke.png"), tr("Auto Stretch F12")); autoStretchButton->setShortcut(Qt::Key_F12); - connect(autoStretchButton, SIGNAL(triggered()), this, SIGNAL(autoStretch())); + connect(autoStretchButton, &QAction::triggered, this, &StretchToolbar::autoStretch); QAction *resetButton = addAction(style()->standardIcon(QStyle::SP_DialogResetButton), tr("Reset Screen Transfer Function F11")); resetButton->setShortcut(Qt::Key_F11); @@ -69,20 +111,40 @@ void StretchToolbar::stretchImage(Image *img) if(max>1.0f)max = 1.0f; float bp = median + mad * BLACK_POINT_SIGMA * MAD_TO_SIGMA; float mid = MTF(median - bp, TARGET_BACKGROUND); + m_mtfParam.blackPoint[i] = bp; + m_mtfParam.midPoint[i] = mid; + m_mtfParam.whitePoint[i] = max; bp2 += bp; mid2 += mid; max2 += max; } - m_stfSlider->setMTFParams(bp2 / ch, mid2 / ch, max2 / ch); - emit paramChanged(m_stfSlider->blackPoint(), m_stfSlider->midPoint(), m_stfSlider->whitePoint()); + if(m_stack->currentIndex() == 0) + { + m_mtfParam.blackPoint[0] = m_mtfParam.blackPoint[1] = m_mtfParam.blackPoint[2] = bp2 / ch; + m_mtfParam.midPoint[0] = m_mtfParam.midPoint[1] = m_mtfParam.midPoint[2] = mid2 / ch; + m_mtfParam.whitePoint[0] = m_mtfParam.whitePoint[1] = m_mtfParam.whitePoint[2] = max2 / ch; + m_stfSlider->setMTFParams(m_mtfParam.blackPoint[0], m_mtfParam.midPoint[0], m_mtfParam.whitePoint[0]); + } + else + { + m_stfSliderR->setMTFParams(m_mtfParam.blackPoint[0], m_mtfParam.midPoint[0], m_mtfParam.whitePoint[0]); + m_stfSliderG->setMTFParams(m_mtfParam.blackPoint[1], m_mtfParam.midPoint[1], m_mtfParam.whitePoint[1]); + m_stfSliderB->setMTFParams(m_mtfParam.blackPoint[2], m_mtfParam.midPoint[2], m_mtfParam.whitePoint[2]); + } + emit paramChanged(m_mtfParam); } } } void StretchToolbar::resetMTF() { + MTFParam params; + m_mtfParam = params; m_stfSlider->setMTFParams(0, 0.5, 1); - emit paramChanged(0, 0.5, 1); + m_stfSliderR->setMTFParams(0, 0.5, 1); + m_stfSliderG->setMTFParams(0, 0.5, 1); + m_stfSliderB->setMTFParams(0, 0.5, 1); + emit paramChanged(params); } void StretchToolbar::imageLoaded(Image *img) @@ -90,5 +152,3 @@ void StretchToolbar::imageLoaded(Image *img) if(m_autoStretchOnLoad->isChecked()) stretchImage(img); } - - diff --git a/stretchtoolbar.h b/stretchtoolbar.h index 95d1152..3ec895d 100644 --- a/stretchtoolbar.h +++ b/stretchtoolbar.h @@ -2,15 +2,28 @@ #define STRETCHTOOLBAR_H #include +#include #include "stfslider.h" class Image; +struct MTFParam +{ + float blackPoint[3] = {0.0f, 0.0f, 0.0f}; + float midPoint[3] = {0.5f, 0.5f, 0.5f}; + float whitePoint[3] = {1.0f, 1.0f, 1.0f}; +}; + class StretchToolbar : public QToolBar { Q_OBJECT STFSlider *m_stfSlider; + STFSlider *m_stfSliderR; + STFSlider *m_stfSliderG; + STFSlider *m_stfSliderB; QAction *m_autoStretchOnLoad; + QStackedWidget *m_stack; + MTFParam m_mtfParam; public: explicit StretchToolbar(QWidget *parent = nullptr); public slots: @@ -18,7 +31,7 @@ public slots: void resetMTF(); void imageLoaded(Image *img); signals: - void paramChanged(float low, float mid, float high); + void paramChanged(const MTFParam ¶ms); void autoStretch(); void invert(bool enable); void superPixel(bool enable);