Rework stretch to use just MTF

This commit is contained in:
2022-04-06 13:12:47 +02:00
parent 31783dbdeb
commit 2ff1b993a1
8 changed files with 93 additions and 135 deletions
+9 -30
View File
@@ -2,43 +2,22 @@
uniform sampler2D qt_Texture0; uniform sampler2D qt_Texture0;
varying vec2 qt_TexCoord0; varying vec2 qt_TexCoord0;
uniform vec2 scale; uniform vec3 mtf_param;
uniform float a;
uniform int stretch;
uniform bool bw; uniform bool bw;
vec4 MTF(vec4 x, vec3 m)
{
x = (x - m.x) / (m.z - m.x);
x = clamp(x, vec4(0.0), vec4(1.0));
return ((m.y - 1) * x) / ((2 * m.y - 1) * x - m.y);
}
void main(void) void main(void)
{ {
vec4 color = texture2D(qt_Texture0, qt_TexCoord0); vec4 color = texture2D(qt_Texture0, qt_TexCoord0);
if(bw)color = color.rrra; if(bw)color = color.rrra;
color = color*scale.x + scale.y; color = MTF(color, mtf_param);
color = max(color, vec4(0.0f));
switch(stretch)
{
case 0:
break;
case 1:
color = sqrt(color);
break;
case 2:
color = pow(color, vec4(a));
break;
case 3:
color = log(a*color + 1.0) / log(vec4(a+1));
break;
case 4:
{
//float l = color.r*0.2126f + color.g*0.7152f + color.b*0.0722f;
float l = (color.r+color.g+color.b)*0.33333;
float k = asinh(l*a)/(l*asinh(a));
color *= k;
}
break;
}
//color = color*scale.x + scale.y;
//float color = pow(c, 0.4545);
if(any(lessThan(qt_TexCoord0, vec2(0.0))) || any(greaterThan(qt_TexCoord0, vec2(1.0)))) if(any(lessThan(qt_TexCoord0, vec2(0.0))) || any(greaterThan(qt_TexCoord0, vec2(1.0))))
color = vec4(0.0); color = vec4(0.0);
gl_FragColor = color; gl_FragColor = color;
+7 -26
View File
@@ -41,13 +41,13 @@ ImageWidget::ImageWidget(QWidget *parent) : QOpenGLWidget(parent)
setFocusPolicy(Qt::ClickFocus); setFocusPolicy(Qt::ClickFocus);
m_range = UINT16_MAX; m_range = UINT16_MAX;
m_low = 0; m_low = 0;
m_mid = 0.5;
m_high = 1; m_high = 1;
m_dx = m_dy = 0; m_dx = m_dy = 0;
m_scale = 1.0f; m_scale = 1.0f;
m_blockRepaint = false; m_blockRepaint = false;
m_range = UINT16_MAX; m_range = UINT16_MAX;
m_imgWidth = m_imgHeight = -1; m_imgWidth = m_imgHeight = -1;
m_stretch = 0;
} }
ImageWidget::~ImageWidget() ImageWidget::~ImageWidget()
@@ -67,6 +67,7 @@ void ImageWidget::setImage(RawImage *image)
m_image->destroy(); m_image->destroy();
m_image->setFormat(rawImageType.textureFormat); m_image->setFormat(rawImageType.textureFormat);
m_image->setSize(image->width(), image->height()); m_image->setSize(image->width(), image->height());
m_image->setMipLevels([&](){ int c = 0; int s = std::min(m_imgWidth, m_imgHeight); while(s>>=1)c++; return c; }());
m_image->allocateStorage(); m_image->allocateStorage();
m_image->setMinMagFilters(QOpenGLTexture::LinearMipMapLinear, QOpenGLTexture::Linear); m_image->setMinMagFilters(QOpenGLTexture::LinearMipMapLinear, QOpenGLTexture::Linear);
m_image->setWrapMode(QOpenGLTexture::ClampToEdge); m_image->setWrapMode(QOpenGLTexture::ClampToEdge);
@@ -105,28 +106,11 @@ void ImageWidget::blockRepaint(bool block)
if(!block)update(); if(!block)update();
} }
void ImageWidget::setLow(int low) void ImageWidget::setMTFParams(float low, float mid, float high)
{ {
m_low = low/m_range; m_low = low;
update(); m_mid = mid;
} m_high = high;
void ImageWidget::setHigh(int high)
{
m_high = high/m_range;
update();
}
void ImageWidget::setStrech(int stretch)
{
m_stretch = stretch;
update();
}
void ImageWidget::setStretchParam(float param)
{
qDebug() << param;
m_param = param;
update(); update();
} }
@@ -169,13 +153,10 @@ void ImageWidget::paintGL()
if(height() > m_image->height()*m_scale) if(height() > m_image->height()*m_scale)
dy = -height()*0.5f + m_image->height()*m_scale*0.5f; dy = -height()*0.5f + m_image->height()*m_scale*0.5f;
float s = 1.0f/(m_high-m_low);
m_program->bind(); m_program->bind();
m_program->setUniformValue("scale", s, -m_low*s);
m_program->setUniformValue("viewport", (float)width(), (float)height()); m_program->setUniformValue("viewport", (float)width(), (float)height());
m_program->setUniformValue("offset", dx, dy); m_program->setUniformValue("offset", dx, dy);
m_program->setUniformValue("stretch", m_stretch); m_program->setUniformValue("mtf_param", m_low, m_mid, m_high);
m_program->setUniformValue("a", m_param);
m_program->setUniformValue("zoom", 1.0f/m_scale); m_program->setUniformValue("zoom", 1.0f/m_scale);
m_program->setUniformValue("bw", m_bwImg); m_program->setUniformValue("bw", m_bwImg);
+2 -6
View File
@@ -33,12 +33,11 @@ class ImageWidget : public QOpenGLWidget
int m_width, m_height; int m_width, m_height;
int m_imgWidth, m_imgHeight; int m_imgWidth, m_imgHeight;
float m_low; float m_low;
float m_mid;
float m_high; float m_high;
int m_stretch;
float m_range; float m_range;
float m_dx, m_dy; float m_dx, m_dy;
float m_scale; float m_scale;
float m_param;
bool m_blockRepaint; bool m_blockRepaint;
bool m_bwImg; bool m_bwImg;
public: public:
@@ -49,10 +48,7 @@ public:
void setScale(float scale); void setScale(float scale);
void blockRepaint(bool block); void blockRepaint(bool block);
public slots: public slots:
void setLow(int low); void setMTFParams(float low, float mid, float high);
void setHigh(int high);
void setStrech(int stretch);
void setStretchParam(float param);
void setOffset(int dx, int dy); void setOffset(int dx, int dy);
QImage renderToImage(); QImage renderToImage();
protected: protected:
+1 -4
View File
@@ -43,10 +43,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
setCentralWidget(m_imageGL); setCentralWidget(m_imageGL);
StretchPanel *stretchPanel = new StretchPanel(this); StretchPanel *stretchPanel = new StretchPanel(this);
connect(stretchPanel, SIGNAL(lowChanged(int)), m_imageGL->imageWidget(), SLOT(setLow(int))); connect(stretchPanel, SIGNAL(paramChanged(float,float,float)), m_imageGL->imageWidget(), SLOT(setMTFParams(float,float,float)));
connect(stretchPanel, SIGNAL(highChanged(int)), m_imageGL->imageWidget(), SLOT(setHigh(int)));
connect(stretchPanel, SIGNAL(stretchChanged(int)), m_imageGL->imageWidget(), SLOT(setStrech(int)));
connect(stretchPanel, SIGNAL(paramChanged(float)), m_imageGL->imageWidget(), SLOT(setStretchParam(float)));
m_ringList = new ImageRingList(this); m_ringList = new ImageRingList(this);
m_filesystem = new FilesystemWidget(m_ringList, this); m_filesystem = new FilesystemWidget(m_ringList, this);
+34 -1
View File
@@ -3,9 +3,15 @@
#include <QPainter> #include <QPainter>
#include <QPaintEvent> #include <QPaintEvent>
static float clamp(float x)
{
return std::min(std::max(x, 0.0f), 1.0f);
}
STFSlider::STFSlider(QWidget *parent) : QWidget(parent) STFSlider::STFSlider(QWidget *parent) : QWidget(parent)
{ {
setMinimumHeight(15); setMinimumHeight(15);
setMaximumHeight(15);
setMouseTracking(true); setMouseTracking(true);
m_blackPoint = 0; m_blackPoint = 0;
m_midPoint = 0.5; m_midPoint = 0.5;
@@ -13,6 +19,29 @@ STFSlider::STFSlider(QWidget *parent) : QWidget(parent)
m_grabbed = -1; m_grabbed = -1;
} }
float STFSlider::blackPoint() const
{
return m_blackPoint;
}
float STFSlider::midPoint() const
{
return m_midPoint;
}
float STFSlider::whitePoint() const
{
return m_whitePoint;
}
void STFSlider::setMTFParams(float low, float mid, float high)
{
m_blackPoint = clamp(low);
m_midPoint = clamp(mid);
m_whitePoint = clamp(high);
update();
}
void STFSlider::paintEvent(QPaintEvent *event) void STFSlider::paintEvent(QPaintEvent *event)
{ {
QPainter painter(this); QPainter painter(this);
@@ -77,7 +106,10 @@ void STFSlider::mouseMoveEvent(QMouseEvent *event)
break; break;
} }
if(m_grabbed >= 0) if(m_grabbed >= 0)
repaint(); {
emit paramChanged(m_blackPoint, midPoint(), m_whitePoint);
update();
}
} }
void STFSlider::mousePressEvent(QMouseEvent *event) void STFSlider::mousePressEvent(QMouseEvent *event)
@@ -95,4 +127,5 @@ void STFSlider::mousePressEvent(QMouseEvent *event)
void STFSlider::mouseReleaseEvent(QMouseEvent *) void STFSlider::mouseReleaseEvent(QMouseEvent *)
{ {
m_grabbed = -1; m_grabbed = -1;
emit paramChanged(m_blackPoint, midPoint(), m_whitePoint);
} }
+6
View File
@@ -13,6 +13,12 @@ class STFSlider : public QWidget
int m_grabbed; int m_grabbed;
public: public:
explicit STFSlider(QWidget *parent = nullptr); explicit STFSlider(QWidget *parent = nullptr);
float blackPoint() const;
float midPoint() const;
float whitePoint() const;
void setMTFParams(float low, float mid, float high);
signals:
void paramChanged(float blackPoint, float midPoint, float whitePoint);
protected: protected:
void paintEvent(QPaintEvent *event) override; void paintEvent(QPaintEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override;
+30 -56
View File
@@ -1,42 +1,33 @@
#include "stretchpanel.h" #include "stretchpanel.h"
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QDebug> #include <QDebug>
#include <QPushButton>
#include "imageringlist.h" #include "imageringlist.h"
#include "stfslider.h"
const float BLACK_POINT_SIGMA = -2.8f;
const float MAD_TO_SIGMA = 1.4826f;
const float TARGET_BACKGROUND = 0.25f;
float MTF(float x, float m)
{
if(x < 0)return 0;
if(x > 1)return 1;
return ((m - 1) * x) / ((2 * m - 1) * x - m);
}
StretchPanel::StretchPanel(QWidget *parent) : QWidget(parent) StretchPanel::StretchPanel(QWidget *parent) : QWidget(parent)
{ {
QVBoxLayout *layout = new QVBoxLayout(this); QHBoxLayout *layout = new QHBoxLayout(this);
setLayout(layout); setLayout(layout);
m_lowSlider = new QSlider(Qt::Horizontal, this); m_stfSlider = new STFSlider(this);
m_highSlider = new QSlider(Qt::Horizontal, this); layout->addWidget(m_stfSlider);
m_paramSlider = new QSlider(Qt::Horizontal, this); connect(m_stfSlider, SIGNAL(paramChanged(float, float, float)), this, SIGNAL(paramChanged(float,float,float)));
STFSlider *stfslider = new STFSlider(this); QPushButton *resetButton = new QPushButton(tr("Reset STF"), this);
resetButton->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
m_lowSlider->setRange(0, UINT16_MAX); layout->addWidget(resetButton);
m_lowSlider->setPageStep(512); connect(resetButton, SIGNAL(pressed()), this, SLOT(resetMTF()));
m_highSlider->setRange(0, UINT16_MAX);
m_highSlider->setPageStep(512);
m_highSlider->setValue(UINT16_MAX);
m_paramSlider->setRange(0, UINT16_MAX);
m_paramSlider->setPageStep(512);
m_stretchSelect = new QComboBox(this);
m_stretchSelect->addItems({tr("Linear"), tr("Square root"), tr("Power"), tr("Logarithm"), tr("Asinh")});
layout->addWidget(m_lowSlider);
layout->addWidget(m_highSlider);
layout->addWidget(m_paramSlider);
layout->addWidget(m_stretchSelect);
layout->addWidget(stfslider);
connect(m_lowSlider, SIGNAL(valueChanged(int)), this, SIGNAL(lowChanged(int)));
connect(m_highSlider, SIGNAL(valueChanged(int)), this, SIGNAL(highChanged(int)));
connect(m_paramSlider, SIGNAL(valueChanged(int)), this, SLOT(calculateParam()));
connect(m_stretchSelect, SIGNAL(activated(int)), this, SIGNAL(stretchChanged(int)));
connect(m_stretchSelect, SIGNAL(activated(int)), this, SLOT(calculateParam()));
} }
void StretchPanel::imageLoaded(Image *img) void StretchPanel::imageLoaded(Image *img)
@@ -47,36 +38,19 @@ void StretchPanel::imageLoaded(Image *img)
{ {
double mean, stdDev, median; double mean, stdDev, median;
img->rawImage()->imageStats(&mean, &stdDev, &median, nullptr, nullptr); img->rawImage()->imageStats(&mean, &stdDev, &median, nullptr, nullptr);
double mad = img->rawImage()->MAD(); median /= 65536;
float l = median - mad; double mad = img->rawImage()->MAD() / 65536;
m_lowSlider->setValue(l); float bp = median + mad * BLACK_POINT_SIGMA * MAD_TO_SIGMA;
float p = std::log(0.25)/std::log(mean/UINT16_MAX); float mid = MTF(median - bp, TARGET_BACKGROUND);
m_paramSlider->setValue(p * UINT16_MAX); m_stfSlider->setMTFParams(bp, mid, 1.0f);
qDebug() << "Low" << l << p; emit paramChanged(m_stfSlider->blackPoint(), m_stfSlider->midPoint(), 1.0f);
} }
} }
} }
void StretchPanel::calculateParam() void StretchPanel::resetMTF()
{ {
float val = m_paramSlider->value(); m_stfSlider->setMTFParams(0, 0.5, 1);
float param; emit paramChanged(0, 0.5, 1);
switch(m_stretchSelect->currentIndex())
{
case 2:
param = val/UINT16_MAX;
param = 1.0f / (param * 5.0f + 1);
break;
case 3:
param = val;
break;
case 4:
param = 1.0f/std::max(0.00001f, 1.0f-(val/UINT16_MAX));
//val += 100;
//param = val/100.0f;
break;
default:
return;
}
emit paramChanged(param);
} }
+4 -12
View File
@@ -2,29 +2,21 @@
#define STRETCHPANEL_H #define STRETCHPANEL_H
#include <QWidget> #include <QWidget>
#include <QSlider> #include "stfslider.h"
#include <QComboBox>
class Image; class Image;
class StretchPanel : public QWidget class StretchPanel : public QWidget
{ {
Q_OBJECT Q_OBJECT
QSlider *m_lowSlider; STFSlider *m_stfSlider;
QSlider *m_highSlider;
QSlider *m_paramSlider;
QComboBox *m_stretchSelect;
public: public:
explicit StretchPanel(QWidget *parent = nullptr); explicit StretchPanel(QWidget *parent = nullptr);
public slots: public slots:
void imageLoaded(Image *img); void imageLoaded(Image *img);
void resetMTF();
signals: signals:
void lowChanged(int low); void paramChanged(float low, float mid, float high);
void highChanged(int high);
void stretchChanged(int stretch);
void paramChanged(float param);
private slots:
void calculateParam();
}; };
#endif // STRETCHPANEL_H #endif // STRETCHPANEL_H