Rework stretch to use just MTF
This commit is contained in:
+9
-30
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user