Rework stretch to use just MTF
This commit is contained in:
+9
-30
@@ -2,43 +2,22 @@
|
||||
|
||||
uniform sampler2D qt_Texture0;
|
||||
varying vec2 qt_TexCoord0;
|
||||
uniform vec2 scale;
|
||||
uniform float a;
|
||||
uniform int stretch;
|
||||
uniform vec3 mtf_param;
|
||||
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)
|
||||
{
|
||||
vec4 color = texture2D(qt_Texture0, qt_TexCoord0);
|
||||
if(bw)color = color.rrra;
|
||||
color = color*scale.x + scale.y;
|
||||
color = max(color, vec4(0.0f));
|
||||
color = MTF(color, mtf_param);
|
||||
|
||||
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))))
|
||||
color = vec4(0.0);
|
||||
gl_FragColor = color;
|
||||
|
||||
+7
-26
@@ -41,13 +41,13 @@ ImageWidget::ImageWidget(QWidget *parent) : QOpenGLWidget(parent)
|
||||
setFocusPolicy(Qt::ClickFocus);
|
||||
m_range = UINT16_MAX;
|
||||
m_low = 0;
|
||||
m_mid = 0.5;
|
||||
m_high = 1;
|
||||
m_dx = m_dy = 0;
|
||||
m_scale = 1.0f;
|
||||
m_blockRepaint = false;
|
||||
m_range = UINT16_MAX;
|
||||
m_imgWidth = m_imgHeight = -1;
|
||||
m_stretch = 0;
|
||||
}
|
||||
|
||||
ImageWidget::~ImageWidget()
|
||||
@@ -67,6 +67,7 @@ void ImageWidget::setImage(RawImage *image)
|
||||
m_image->destroy();
|
||||
m_image->setFormat(rawImageType.textureFormat);
|
||||
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->setMinMagFilters(QOpenGLTexture::LinearMipMapLinear, QOpenGLTexture::Linear);
|
||||
m_image->setWrapMode(QOpenGLTexture::ClampToEdge);
|
||||
@@ -105,28 +106,11 @@ void ImageWidget::blockRepaint(bool block)
|
||||
if(!block)update();
|
||||
}
|
||||
|
||||
void ImageWidget::setLow(int low)
|
||||
void ImageWidget::setMTFParams(float low, float mid, float high)
|
||||
{
|
||||
m_low = low/m_range;
|
||||
update();
|
||||
}
|
||||
|
||||
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;
|
||||
m_low = low;
|
||||
m_mid = mid;
|
||||
m_high = high;
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -169,13 +153,10 @@ void ImageWidget::paintGL()
|
||||
if(height() > m_image->height()*m_scale)
|
||||
dy = -height()*0.5f + m_image->height()*m_scale*0.5f;
|
||||
|
||||
float s = 1.0f/(m_high-m_low);
|
||||
m_program->bind();
|
||||
m_program->setUniformValue("scale", s, -m_low*s);
|
||||
m_program->setUniformValue("viewport", (float)width(), (float)height());
|
||||
m_program->setUniformValue("offset", dx, dy);
|
||||
m_program->setUniformValue("stretch", m_stretch);
|
||||
m_program->setUniformValue("a", m_param);
|
||||
m_program->setUniformValue("mtf_param", m_low, m_mid, m_high);
|
||||
m_program->setUniformValue("zoom", 1.0f/m_scale);
|
||||
m_program->setUniformValue("bw", m_bwImg);
|
||||
|
||||
|
||||
+2
-6
@@ -33,12 +33,11 @@ class ImageWidget : public QOpenGLWidget
|
||||
int m_width, m_height;
|
||||
int m_imgWidth, m_imgHeight;
|
||||
float m_low;
|
||||
float m_mid;
|
||||
float m_high;
|
||||
int m_stretch;
|
||||
float m_range;
|
||||
float m_dx, m_dy;
|
||||
float m_scale;
|
||||
float m_param;
|
||||
bool m_blockRepaint;
|
||||
bool m_bwImg;
|
||||
public:
|
||||
@@ -49,10 +48,7 @@ public:
|
||||
void setScale(float scale);
|
||||
void blockRepaint(bool block);
|
||||
public slots:
|
||||
void setLow(int low);
|
||||
void setHigh(int high);
|
||||
void setStrech(int stretch);
|
||||
void setStretchParam(float param);
|
||||
void setMTFParams(float low, float mid, float high);
|
||||
void setOffset(int dx, int dy);
|
||||
QImage renderToImage();
|
||||
protected:
|
||||
|
||||
+1
-4
@@ -43,10 +43,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
|
||||
setCentralWidget(m_imageGL);
|
||||
|
||||
StretchPanel *stretchPanel = new StretchPanel(this);
|
||||
connect(stretchPanel, SIGNAL(lowChanged(int)), m_imageGL->imageWidget(), SLOT(setLow(int)));
|
||||
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)));
|
||||
connect(stretchPanel, SIGNAL(paramChanged(float,float,float)), m_imageGL->imageWidget(), SLOT(setMTFParams(float,float,float)));
|
||||
|
||||
m_ringList = new ImageRingList(this);
|
||||
m_filesystem = new FilesystemWidget(m_ringList, this);
|
||||
|
||||
+34
-1
@@ -3,9 +3,15 @@
|
||||
#include <QPainter>
|
||||
#include <QPaintEvent>
|
||||
|
||||
static float clamp(float x)
|
||||
{
|
||||
return std::min(std::max(x, 0.0f), 1.0f);
|
||||
}
|
||||
|
||||
STFSlider::STFSlider(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
setMinimumHeight(15);
|
||||
setMaximumHeight(15);
|
||||
setMouseTracking(true);
|
||||
m_blackPoint = 0;
|
||||
m_midPoint = 0.5;
|
||||
@@ -13,6 +19,29 @@ STFSlider::STFSlider(QWidget *parent) : QWidget(parent)
|
||||
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)
|
||||
{
|
||||
QPainter painter(this);
|
||||
@@ -77,7 +106,10 @@ void STFSlider::mouseMoveEvent(QMouseEvent *event)
|
||||
break;
|
||||
}
|
||||
if(m_grabbed >= 0)
|
||||
repaint();
|
||||
{
|
||||
emit paramChanged(m_blackPoint, midPoint(), m_whitePoint);
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void STFSlider::mousePressEvent(QMouseEvent *event)
|
||||
@@ -95,4 +127,5 @@ void STFSlider::mousePressEvent(QMouseEvent *event)
|
||||
void STFSlider::mouseReleaseEvent(QMouseEvent *)
|
||||
{
|
||||
m_grabbed = -1;
|
||||
emit paramChanged(m_blackPoint, midPoint(), m_whitePoint);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,12 @@ class STFSlider : public QWidget
|
||||
int m_grabbed;
|
||||
public:
|
||||
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:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void mouseMoveEvent(QMouseEvent *event) override;
|
||||
|
||||
+30
-56
@@ -1,42 +1,33 @@
|
||||
#include "stretchpanel.h"
|
||||
#include <QVBoxLayout>
|
||||
#include <QDebug>
|
||||
#include <QPushButton>
|
||||
#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)
|
||||
{
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
QHBoxLayout *layout = new QHBoxLayout(this);
|
||||
setLayout(layout);
|
||||
|
||||
m_lowSlider = new QSlider(Qt::Horizontal, this);
|
||||
m_highSlider = new QSlider(Qt::Horizontal, this);
|
||||
m_paramSlider = new QSlider(Qt::Horizontal, this);
|
||||
m_stfSlider = new STFSlider(this);
|
||||
layout->addWidget(m_stfSlider);
|
||||
connect(m_stfSlider, SIGNAL(paramChanged(float, float, float)), this, SIGNAL(paramChanged(float,float,float)));
|
||||
|
||||
STFSlider *stfslider = new STFSlider(this);
|
||||
|
||||
m_lowSlider->setRange(0, UINT16_MAX);
|
||||
m_lowSlider->setPageStep(512);
|
||||
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()));
|
||||
QPushButton *resetButton = new QPushButton(tr("Reset STF"), this);
|
||||
resetButton->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
|
||||
layout->addWidget(resetButton);
|
||||
connect(resetButton, SIGNAL(pressed()), this, SLOT(resetMTF()));
|
||||
}
|
||||
|
||||
void StretchPanel::imageLoaded(Image *img)
|
||||
@@ -47,36 +38,19 @@ void StretchPanel::imageLoaded(Image *img)
|
||||
{
|
||||
double mean, stdDev, median;
|
||||
img->rawImage()->imageStats(&mean, &stdDev, &median, nullptr, nullptr);
|
||||
double mad = img->rawImage()->MAD();
|
||||
float l = median - mad;
|
||||
m_lowSlider->setValue(l);
|
||||
float p = std::log(0.25)/std::log(mean/UINT16_MAX);
|
||||
m_paramSlider->setValue(p * UINT16_MAX);
|
||||
qDebug() << "Low" << l << p;
|
||||
median /= 65536;
|
||||
double mad = img->rawImage()->MAD() / 65536;
|
||||
float bp = median + mad * BLACK_POINT_SIGMA * MAD_TO_SIGMA;
|
||||
float mid = MTF(median - bp, TARGET_BACKGROUND);
|
||||
m_stfSlider->setMTFParams(bp, mid, 1.0f);
|
||||
emit paramChanged(m_stfSlider->blackPoint(), m_stfSlider->midPoint(), 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StretchPanel::calculateParam()
|
||||
void StretchPanel::resetMTF()
|
||||
{
|
||||
float val = m_paramSlider->value();
|
||||
float param;
|
||||
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);
|
||||
m_stfSlider->setMTFParams(0, 0.5, 1);
|
||||
emit paramChanged(0, 0.5, 1);
|
||||
}
|
||||
|
||||
|
||||
+4
-12
@@ -2,29 +2,21 @@
|
||||
#define STRETCHPANEL_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QSlider>
|
||||
#include <QComboBox>
|
||||
#include "stfslider.h"
|
||||
|
||||
class Image;
|
||||
|
||||
class StretchPanel : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
QSlider *m_lowSlider;
|
||||
QSlider *m_highSlider;
|
||||
QSlider *m_paramSlider;
|
||||
QComboBox *m_stretchSelect;
|
||||
STFSlider *m_stfSlider;
|
||||
public:
|
||||
explicit StretchPanel(QWidget *parent = nullptr);
|
||||
public slots:
|
||||
void imageLoaded(Image *img);
|
||||
void resetMTF();
|
||||
signals:
|
||||
void lowChanged(int low);
|
||||
void highChanged(int high);
|
||||
void stretchChanged(int stretch);
|
||||
void paramChanged(float param);
|
||||
private slots:
|
||||
void calculateParam();
|
||||
void paramChanged(float low, float mid, float high);
|
||||
};
|
||||
|
||||
#endif // STRETCHPANEL_H
|
||||
|
||||
Reference in New Issue
Block a user