Add autotrech to conversion
This commit is contained in:
+9
-1
@@ -191,11 +191,17 @@ void ConvertRunable::run()
|
||||
QFileInfo info(m_outfile);
|
||||
info.dir().mkpath(".");
|
||||
|
||||
if(m_params.autostretch)
|
||||
{
|
||||
rawimage->calcStats();
|
||||
MTFParam mtfParam = rawimage->calcMTFParams();
|
||||
rawimage->applySTF(mtfParam);
|
||||
}
|
||||
if(m_params.binning > 1)
|
||||
{
|
||||
rawimage->resizeInt(m_params.binning, m_params.average);
|
||||
}
|
||||
else if(m_params.resize.isValid() && !m_params.resize.isEmpty())
|
||||
if(m_params.resize.isValid() && !m_params.resize.isEmpty())
|
||||
{
|
||||
QSize imgSize(rawimage->width(), rawimage->height());
|
||||
imgSize = imgSize.scaled(m_params.resize, m_params.aspect);
|
||||
@@ -363,4 +369,6 @@ ConvertRunable::ConvertParams::ConvertParams(const QVariantMap &map)
|
||||
aspect = Qt::IgnoreAspectRatio;
|
||||
}
|
||||
|
||||
if(map.contains("autostretch"))
|
||||
autostretch = map["autostretch"].toBool();
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ public:
|
||||
bool average = true;
|
||||
QSize resize;
|
||||
Qt::AspectRatioMode aspect = Qt::KeepAspectRatio;
|
||||
bool autostretch = false;
|
||||
ConvertParams(){}
|
||||
ConvertParams(const QVariantMap &map);
|
||||
};
|
||||
|
||||
+107
-1
@@ -759,7 +759,7 @@ void integerResample(uint32_t w, uint32_t h, uint32_t ch, uint32_t oldw, uint32_
|
||||
{
|
||||
const T *in = reinterpret_cast<const T*>(in_);
|
||||
T *out = reinterpret_cast<T*>(out_);
|
||||
uint32_t down2 = down * down;
|
||||
const uint32_t down2 = down * down;
|
||||
|
||||
U m = std::numeric_limits<T>::max();
|
||||
if constexpr(std::is_floating_point_v<T>)m = down2;
|
||||
@@ -1104,6 +1104,112 @@ void RawImage::generateLUT()
|
||||
cmsCloseProfile(outProfile);
|
||||
}
|
||||
|
||||
void RawImage::applySTF(const MTFParam &mtfParams)
|
||||
{
|
||||
auto applyMTF = [&](auto *src) -> void
|
||||
{
|
||||
float s = 1.0f;
|
||||
if constexpr(std::numeric_limits<std::remove_reference_t<decltype(*src)>>::is_integer)
|
||||
s = (float)std::numeric_limits<std::remove_reference_t<decltype(*src)>>::max();
|
||||
|
||||
float iscale = 1.0f / s;
|
||||
size_t len = size() * m_ch;
|
||||
for(size_t i = 0; i < len; i++)
|
||||
{
|
||||
float x = src[i] * iscale;
|
||||
x = (x - mtfParams.blackPoint[0]) / (mtfParams.whitePoint[0] - mtfParams.blackPoint[0]);
|
||||
x = std::clamp(x, 0.0f, 1.0f);
|
||||
x = ((mtfParams.midPoint[0] - 1.0f) * x) / ((2.0f * mtfParams.midPoint[0] - 1.0f) * x - mtfParams.midPoint[0]);
|
||||
src[i] = x * s;
|
||||
}
|
||||
};
|
||||
|
||||
switch(m_type)
|
||||
{
|
||||
case UINT8:
|
||||
applyMTF(reinterpret_cast<uint8_t*>(m_pixels.get()));
|
||||
break;
|
||||
case UINT16:
|
||||
applyMTF(reinterpret_cast<uint16_t*>(m_pixels.get()));
|
||||
break;
|
||||
case UINT32:
|
||||
applyMTF(reinterpret_cast<uint32_t*>(m_pixels.get()));
|
||||
break;
|
||||
case FLOAT32:
|
||||
applyMTF(reinterpret_cast<float*>(m_pixels.get()));
|
||||
break;
|
||||
case FLOAT64:
|
||||
applyMTF(reinterpret_cast<double*>(m_pixels.get()));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
MTFParam RawImage::calcMTFParams(bool linked, bool debayer) const
|
||||
{
|
||||
const float BLACK_POINT_SIGMA = -2.8f;
|
||||
const float MAD_TO_SIGMA = 1.4826f;
|
||||
const float TARGET_BACKGROUND = 0.25f;
|
||||
|
||||
auto MTF = [](float x, float m)
|
||||
{
|
||||
if(x < 0)return 0.0f;
|
||||
if(x > 1)return 1.0f;
|
||||
return ((m - 1) * x) / ((2 * m - 1) * x - m);
|
||||
};
|
||||
|
||||
MTFParam mtfParam;
|
||||
|
||||
int i = 0;
|
||||
int ch = m_channels;
|
||||
int o = 0;
|
||||
if(debayer)
|
||||
{
|
||||
i = 1;
|
||||
ch = 4;
|
||||
o = 1;
|
||||
}
|
||||
|
||||
float bp2 = 0;
|
||||
float mid2 = 0;
|
||||
float max2 = 0;
|
||||
for(; i < ch; i++)
|
||||
{
|
||||
double median, mad, max;
|
||||
median = m_stats.m_median[i];
|
||||
mad = m_stats.m_mad[i];
|
||||
median /= norm();
|
||||
bool a = median > 0.5 ? true : false;
|
||||
mad /= norm();
|
||||
max = 1.0f;
|
||||
float bp = a || mad == 0.0f ? 0.0f : std::clamp(median + mad * BLACK_POINT_SIGMA * MAD_TO_SIGMA, 0.0, 1.0);
|
||||
if(a && mad != 0.0f)
|
||||
max = std::clamp(median - mad * BLACK_POINT_SIGMA * MAD_TO_SIGMA, 0.0, 1.0);
|
||||
|
||||
float mid = !a ? MTF(median - bp, TARGET_BACKGROUND) : MTF(TARGET_BACKGROUND, max - median);
|
||||
mtfParam.blackPoint[i-o] = bp;
|
||||
mtfParam.midPoint[i-o] = mid;
|
||||
mtfParam.whitePoint[i-o] = max;
|
||||
bp2 += bp;
|
||||
mid2 += mid;
|
||||
max2 = max > max2 ? max : max2;
|
||||
}
|
||||
if(ch == 1)
|
||||
{
|
||||
mtfParam.blackPoint[1] = mtfParam.blackPoint[2] = mtfParam.blackPoint[0];
|
||||
mtfParam.midPoint[1] = mtfParam.midPoint[2] = mtfParam.midPoint[0];
|
||||
mtfParam.whitePoint[1] = mtfParam.whitePoint[2] = mtfParam.whitePoint[0];
|
||||
}
|
||||
if(linked)
|
||||
{
|
||||
mtfParam.blackPoint[0] = mtfParam.blackPoint[1] = mtfParam.blackPoint[2] = bp2 / ch;
|
||||
mtfParam.midPoint[0] = mtfParam.midPoint[1] = mtfParam.midPoint[2] = mid2 / ch;
|
||||
mtfParam.whitePoint[0] = mtfParam.whitePoint[1] = mtfParam.whitePoint[2] = max2;
|
||||
}
|
||||
return mtfParam;
|
||||
}
|
||||
|
||||
const std::vector<uint16_t> &RawImage::getLUT() const
|
||||
{
|
||||
return m_lut;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#ifndef NO_QT
|
||||
#include <QImage>
|
||||
#endif
|
||||
#include "mtfparam.h"
|
||||
|
||||
extern int THUMB_SIZE;
|
||||
extern int THUMB_SIZE_BORDER;
|
||||
@@ -127,6 +128,8 @@ public:
|
||||
void setICCProfile(const LibXISF::ByteArray &icc);
|
||||
void convertTosRGB();
|
||||
void generateLUT();
|
||||
void applySTF(const MTFParam &mtfParams);
|
||||
MTFParam calcMTFParams(bool linked = false, bool debayer = false) const;
|
||||
const std::vector<uint16_t>& getLUT() const;
|
||||
|
||||
};
|
||||
|
||||
+2
-45
@@ -107,54 +107,11 @@ void StretchToolbar::stretchImage(Image *img)
|
||||
{
|
||||
if(img && img->rawImage())
|
||||
{
|
||||
const RawImage::Stats &stats = img->rawImage()->imageStats();
|
||||
int i = 0;
|
||||
int ch = 1;
|
||||
int o = 0;
|
||||
if(m_stack->currentIndex() == 1 && img->rawImage()->channels() == 1 && m_debayer->isChecked())
|
||||
{
|
||||
i = 1;
|
||||
ch = 4;
|
||||
o = 1;
|
||||
}
|
||||
if(img->rawImage()->channels() >= 3)
|
||||
ch = 3;
|
||||
m_mtfParam = img->rawImage()->calcMTFParams(m_stack->currentIndex() == 0,
|
||||
m_stack->currentIndex() == 1 && img->rawImage()->channels() == 1 && m_debayer->isChecked());
|
||||
|
||||
float bp2 = 0;
|
||||
float mid2 = 0;
|
||||
float max2 = 0;
|
||||
for(; i < ch; i++)
|
||||
{
|
||||
double median, mad, max;
|
||||
median = stats.m_median[i];
|
||||
mad = stats.m_mad[i];
|
||||
max = stats.m_max[i];
|
||||
median /= img->rawImage()->norm();
|
||||
bool a = median > 0.5 ? true : false;
|
||||
mad /= img->rawImage()->norm();
|
||||
max = 1.0f;// /= img->rawImage()->norm();
|
||||
float bp = a || mad == 0.0f ? 0.0f : std::clamp(median + mad * BLACK_POINT_SIGMA * MAD_TO_SIGMA, 0.0, 1.0);
|
||||
if(a && mad != 0.0f)
|
||||
max = std::clamp(median - mad * BLACK_POINT_SIGMA * MAD_TO_SIGMA, 0.0, 1.0);
|
||||
float mid = !a ? MTF(median - bp, TARGET_BACKGROUND) : MTF(TARGET_BACKGROUND, max - median);
|
||||
m_mtfParam.blackPoint[i-o] = bp;
|
||||
m_mtfParam.midPoint[i-o] = mid;// / max;
|
||||
m_mtfParam.whitePoint[i-o] = max;
|
||||
bp2 += bp;
|
||||
mid2 += mid;
|
||||
max2 = max > max2 ? max : max2;
|
||||
}
|
||||
if(ch == 1)
|
||||
{
|
||||
m_mtfParam.blackPoint[1] = m_mtfParam.blackPoint[2] = m_mtfParam.blackPoint[0];
|
||||
m_mtfParam.midPoint[1] = m_mtfParam.midPoint[2] = m_mtfParam.midPoint[0];
|
||||
m_mtfParam.whitePoint[1] = m_mtfParam.whitePoint[2] = m_mtfParam.whitePoint[0];
|
||||
}
|
||||
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;
|
||||
m_stfSlider->setMTFParams(m_mtfParam.blackPoint[0], m_mtfParam.midPoint[0], m_mtfParam.whitePoint[0]);
|
||||
}
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user