diff --git a/mainwindow.cpp b/mainwindow.cpp index 9edbf63..0ac8e57 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -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")); diff --git a/rawimage.cpp b/rawimage.cpp index 499af7b..b03eb41 100644 --- a/rawimage.cpp +++ b/rawimage.cpp @@ -123,7 +123,7 @@ const RawImage::Stats& RawImage::imageStats() } template -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::is_integer) { stats.m_median[i] /= 65535.0; @@ -213,33 +225,33 @@ void RawImage::calcStats() { case UINT8: if(channels()==1) - ::calcStats(static_cast(origData()), size(), m_stats); + ::calcStats(static_cast(origData()), size(), width(), m_stats); else - ::calcStats(static_cast(origData()), size(), m_stats); + ::calcStats(static_cast(origData()), size(), width(), m_stats); break; case UINT16: if(channels()==1) - ::calcStats(static_cast(origData()), size(), m_stats); + ::calcStats(static_cast(origData()), size(), width(), m_stats); else - ::calcStats(static_cast(origData()), size(), m_stats); + ::calcStats(static_cast(origData()), size(), width(), m_stats); break; case UINT32: if(channels()==1) - ::calcStats(static_cast(origData()), size(), m_stats); + ::calcStats(static_cast(origData()), size(), width(), m_stats); else - ::calcStats(static_cast(origData()), size(), m_stats); + ::calcStats(static_cast(origData()), size(), width(), m_stats); break; case FLOAT32: if(channels()==1) - ::calcStats(static_cast(origData()), size(), m_stats); + ::calcStats(static_cast(origData()), size(), width(), m_stats); else - ::calcStats(static_cast(origData()), size(), m_stats); + ::calcStats(static_cast(origData()), size(), width(), m_stats); break; case FLOAT64: if(channels()==1) - ::calcStats(static_cast(origData()), size(), m_stats); + ::calcStats(static_cast(origData()), size(), width(), m_stats); else - ::calcStats(static_cast(origData()), size(), m_stats); + ::calcStats(static_cast(origData()), size(), width(), m_stats); break; } } diff --git a/stretchtoolbar.cpp b/stretchtoolbar.cpp index ade2411..1a52804 100644 --- a/stretchtoolbar.cpp +++ b/stretchtoolbar.cpp @@ -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 diff --git a/stretchtoolbar.h b/stretchtoolbar.h index 8b35b9d..d4f941c 100644 --- a/stretchtoolbar.h +++ b/stretchtoolbar.h @@ -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: