Made unlinked stretch white balancing
This commit is contained in:
+1
-1
@@ -125,7 +125,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
|
||||
QDockWidget *histogramDock = new QDockWidget(tr("Histogram"), this);
|
||||
histogramDock->setWidget(histogram);
|
||||
histogramDock->setObjectName("histogramDock");
|
||||
histogramDock->show();
|
||||
histogramDock->hide();
|
||||
addDockWidget(Qt::LeftDockWidgetArea, histogramDock);
|
||||
|
||||
setWindowTitle(tr("Tenmon"));
|
||||
|
||||
+29
-17
@@ -123,7 +123,7 @@ const RawImage::Stats& RawImage::imageStats()
|
||||
}
|
||||
|
||||
template<typename T, typename U, int ch>
|
||||
void calcStats(const T *data, size_t n, RawImage::Stats &stats)
|
||||
void calcStats(const T *data, size_t n, size_t w, RawImage::Stats &stats)
|
||||
{
|
||||
U sum[4] = {0};
|
||||
U sumSq[4] = {0};
|
||||
@@ -150,7 +150,7 @@ void calcStats(const T *data, size_t n, RawImage::Stats &stats)
|
||||
if(d > sat)saturated[x]++;
|
||||
};
|
||||
|
||||
auto findMedian = [n, histSize](uint32_t histogram[]) -> size_t
|
||||
auto findMedian = [histSize](uint32_t histogram[], size_t n) -> size_t
|
||||
{
|
||||
size_t histSum = 0;
|
||||
for(size_t o=0; o < histSize; o++)
|
||||
@@ -162,6 +162,13 @@ void calcStats(const T *data, size_t n, RawImage::Stats &stats)
|
||||
return 0;
|
||||
};
|
||||
|
||||
size_t na[4] = {n, n, n, n};
|
||||
if constexpr(ch == 1)
|
||||
{
|
||||
na[1] /= 4;
|
||||
na[2] /= 2;
|
||||
na[3] /= 4;
|
||||
}
|
||||
for(size_t i = 0; i < n; i++)
|
||||
{
|
||||
statsFunc(data[i*ch], 0);
|
||||
@@ -170,18 +177,23 @@ void calcStats(const T *data, size_t n, RawImage::Stats &stats)
|
||||
statsFunc(data[i*ch + 1], 1);
|
||||
statsFunc(data[i*ch + 2], 2);
|
||||
}
|
||||
if constexpr(ch == 1)
|
||||
{
|
||||
int bayer = (i % w & 1) + (i / w & 1) + 1;
|
||||
statsFunc(data[i], bayer);
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < 3; i++)
|
||||
for(int i = 0; i < 4; i++)
|
||||
{
|
||||
stats.m_min[i] = min[i];
|
||||
stats.m_max[i] = max[i];
|
||||
stats.m_mean[i] = (double)sum[i] / n;
|
||||
stats.m_mean[i] = (double)sum[i] / na[i];
|
||||
stats.m_saturated[i] = saturated[i];
|
||||
double sum2 = (double)sum[i] * sum[i];
|
||||
stats.m_stdDev[i] = std::sqrt((sumSq[i] - sum2 / n) / (n - 1));
|
||||
stats.m_stdDev[i] = std::sqrt((sumSq[i] - sum2 / na[i]) / (na[i] - 1));
|
||||
|
||||
uint32_t median = findMedian(histogram[i]);
|
||||
uint32_t median = findMedian(histogram[i], na[i]);
|
||||
stats.m_median[i] = median;
|
||||
uint32_t madHist[65536] = {0};
|
||||
madHist[0] = histogram[i][median];
|
||||
@@ -190,7 +202,7 @@ void calcStats(const T *data, size_t n, RawImage::Stats &stats)
|
||||
if(median + o < histSize)madHist[o] += histogram[i][median + o];
|
||||
if(o <= median)madHist[o] += histogram[i][median - o];
|
||||
}
|
||||
stats.m_mad[i] = findMedian(madHist);
|
||||
stats.m_mad[i] = findMedian(madHist, na[i]);
|
||||
if constexpr(!std::numeric_limits<T>::is_integer)
|
||||
{
|
||||
stats.m_median[i] /= 65535.0;
|
||||
@@ -213,33 +225,33 @@ void RawImage::calcStats()
|
||||
{
|
||||
case UINT8:
|
||||
if(channels()==1)
|
||||
::calcStats<uint8_t, uint64_t, 1>(static_cast<const uint8_t*>(origData()), size(), m_stats);
|
||||
::calcStats<uint8_t, uint64_t, 1>(static_cast<const uint8_t*>(origData()), size(), width(), m_stats);
|
||||
else
|
||||
::calcStats<uint8_t, uint64_t, 4>(static_cast<const uint8_t*>(origData()), size(), m_stats);
|
||||
::calcStats<uint8_t, uint64_t, 4>(static_cast<const uint8_t*>(origData()), size(), width(), m_stats);
|
||||
break;
|
||||
case UINT16:
|
||||
if(channels()==1)
|
||||
::calcStats<uint16_t, uint64_t, 1>(static_cast<const uint16_t*>(origData()), size(), m_stats);
|
||||
::calcStats<uint16_t, uint64_t, 1>(static_cast<const uint16_t*>(origData()), size(), width(), m_stats);
|
||||
else
|
||||
::calcStats<uint16_t, uint64_t, 4>(static_cast<const uint16_t*>(origData()), size(), m_stats);
|
||||
::calcStats<uint16_t, uint64_t, 4>(static_cast<const uint16_t*>(origData()), size(), width(), m_stats);
|
||||
break;
|
||||
case UINT32:
|
||||
if(channels()==1)
|
||||
::calcStats<uint32_t, double, 1>(static_cast<const uint32_t*>(origData()), size(), m_stats);
|
||||
::calcStats<uint32_t, double, 1>(static_cast<const uint32_t*>(origData()), size(), width(), m_stats);
|
||||
else
|
||||
::calcStats<uint32_t, double, 4>(static_cast<const uint32_t*>(origData()), size(), m_stats);
|
||||
::calcStats<uint32_t, double, 4>(static_cast<const uint32_t*>(origData()), size(), width(), m_stats);
|
||||
break;
|
||||
case FLOAT32:
|
||||
if(channels()==1)
|
||||
::calcStats<float, double, 1>(static_cast<const float*>(origData()), size(), m_stats);
|
||||
::calcStats<float, double, 1>(static_cast<const float*>(origData()), size(), width(), m_stats);
|
||||
else
|
||||
::calcStats<float, double, 4>(static_cast<const float*>(origData()), size(), m_stats);
|
||||
::calcStats<float, double, 4>(static_cast<const float*>(origData()), size(), width(), m_stats);
|
||||
break;
|
||||
case FLOAT64:
|
||||
if(channels()==1)
|
||||
::calcStats<double, double, 1>(static_cast<const double*>(origData()), size(), m_stats);
|
||||
::calcStats<double, double, 1>(static_cast<const double*>(origData()), size(), width(), m_stats);
|
||||
else
|
||||
::calcStats<double, double, 4>(static_cast<const double*>(origData()), size(), m_stats);
|
||||
::calcStats<double, double, 4>(static_cast<const double*>(origData()), size(), width(), m_stats);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+21
-14
@@ -84,9 +84,9 @@ StretchToolbar::StretchToolbar(QWidget *parent) : QToolBar(tr("Stretch toolbar")
|
||||
falseColorButton->setCheckable(true);
|
||||
connect(falseColorButton, &QAction::toggled, this, &StretchToolbar::falseColor);
|
||||
|
||||
QAction *superPixelButton = addAction(QIcon(":/bayer.png"), tr("Debayer CFA"));
|
||||
superPixelButton->setCheckable(true);
|
||||
connect(superPixelButton, &QAction::toggled, this, &StretchToolbar::superPixel);
|
||||
m_debayer = addAction(QIcon(":/bayer.png"), tr("Debayer CFA"));
|
||||
m_debayer->setCheckable(true);
|
||||
connect(m_debayer, &QAction::toggled, this, &StretchToolbar::superPixel);
|
||||
|
||||
m_autoStretchOnLoad = addAction(QIcon(":/nuke_a.png"), tr("Apply auto stretch on load"));
|
||||
m_autoStretchOnLoad->setCheckable(true);
|
||||
@@ -97,28 +97,35 @@ void StretchToolbar::stretchImage(Image *img)
|
||||
if(img && img->rawImage())
|
||||
{
|
||||
const RawImage::Stats &stats = img->rawImage()->imageStats();
|
||||
int ch = img->rawImage()->channels() == 1 ? 1 : 3;
|
||||
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;
|
||||
|
||||
float bp2 = 0;
|
||||
float mid2 = 0;
|
||||
float max2 = 0;
|
||||
for(int i=0; i < ch; i++)
|
||||
for(; i < ch; i++)
|
||||
{
|
||||
double median, mad, max;
|
||||
double median, mad;
|
||||
median = stats.m_median[i];
|
||||
mad = stats.m_mad[i];
|
||||
max = stats.m_max[i];
|
||||
median /= img->rawImage()->norm();
|
||||
mad /= img->rawImage()->norm();
|
||||
max /= img->rawImage()->norm();
|
||||
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;
|
||||
m_mtfParam.blackPoint[i-o] = bp;
|
||||
m_mtfParam.midPoint[i-o] = mid;
|
||||
m_mtfParam.whitePoint[i-o] = 1.0f;
|
||||
bp2 += bp;
|
||||
mid2 += mid;
|
||||
max2 += max;
|
||||
}
|
||||
if(ch == 1)
|
||||
{
|
||||
@@ -130,7 +137,7 @@ void StretchToolbar::stretchImage(Image *img)
|
||||
{
|
||||
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_mtfParam.whitePoint[0] = m_mtfParam.whitePoint[1] = m_mtfParam.whitePoint[2] = 1.0f;
|
||||
m_stfSlider->setMTFParams(m_mtfParam.blackPoint[0], m_mtfParam.midPoint[0], m_mtfParam.whitePoint[0]);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -22,6 +22,7 @@ class StretchToolbar : public QToolBar
|
||||
STFSlider *m_stfSliderG;
|
||||
STFSlider *m_stfSliderB;
|
||||
QAction *m_autoStretchOnLoad;
|
||||
QAction *m_debayer;
|
||||
QStackedWidget *m_stack;
|
||||
MTFParam m_mtfParam;
|
||||
public:
|
||||
|
||||
Reference in New Issue
Block a user