diff --git a/CMakeLists.txt b/CMakeLists.txt index f1efc33..2756ff3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,7 @@ set(TENMON_SRC databaseview.cpp databaseview.h delete.cpp filesystemwidget.cpp filesystemwidget.h + histogram.cpp histogram.h imageinfo.cpp imageinfo.h imageringlist.cpp imageringlist.h imagescrollarea.cpp diff --git a/histogram.cpp b/histogram.cpp new file mode 100644 index 0000000..c3ec0ff --- /dev/null +++ b/histogram.cpp @@ -0,0 +1,84 @@ +#include "histogram.h" +#include +#include +#include +#include + +Histogram::Histogram(QWidget *parent) : QWidget(parent) +{ + setStyleSheet("QWidget { background: white; color: black; } "); +} + +void Histogram::imageLoaded(Image *img) +{ + if(img && img->rawImage()) + { + m_histogram = img->rawImage()->imageStats().m_histogram[0]; + m_points.clear(); + update(); + } +} + +void Histogram::paintEvent(QPaintEvent *) +{ + QPainter painter(this); + painter.fillRect(rect(), Qt::black); + + uint h = height(); + uint w = width(); + + if(m_histogram.size()) + { + + if(m_points.size() != w) + { + m_points.clear(); + for(uint64_t i = 0; i < w; i++) + { + uint32_t sum = 0; + uint64_t start = i * m_histogram.size() / w; + uint64_t end =(i+1) * m_histogram.size() / w; + for(uint64_t o = start; o < end; o++) + sum += m_histogram[o]; + m_points.push_back(sum); + } + float scale = *std::max_element(m_points.begin(), m_points.end()); + if(m_log) + { + scale = std::log(scale); + std::for_each(m_points.begin(), m_points.end(), [scale](float &x){ x = (x > 0 ? std::log(x) : 0.0f) / scale; }); + } + else + { + std::for_each(m_points.begin(), m_points.end(), [scale](float &x){ x /= scale; }); + } + } + std::vector points; + points.push_back(QPointF(0, h)); + for(size_t i = 0; i < m_points.size(); i++) + { + points.push_back(QPointF(i, h - m_points[i] * h)); + } + points.push_back(QPoint(w, h)); + painter.setBrush(Qt::gray); + painter.setPen(Qt::white); + + painter.drawPolygon(&points[0], points.size()); + } + + QStyleOptionButton button; + button.initFrom(this); + button.state = m_log ? QStyle::State_On : QStyle::State_Off; + button.text = tr("Logarithmic scale"); + button.rect = style()->subElementRect(QStyle::SE_CheckBoxClickRect, &button, this); + button.rect.moveTop(0); + button.rect.moveRight(w); + style()->drawControl(QStyle::CE_CheckBox, &button, &painter, this); +} + +void Histogram::mouseReleaseEvent(QMouseEvent *) +{ + m_log = !m_log; + m_points.clear(); + update(); +} diff --git a/histogram.h b/histogram.h new file mode 100644 index 0000000..db3c9e7 --- /dev/null +++ b/histogram.h @@ -0,0 +1,22 @@ +#ifndef HISTOGRAM_H +#define HISTOGRAM_H + +#include +#include "imageringlist.h" + +class Histogram : public QWidget +{ + Q_OBJECT + std::vector m_histogram; + std::vector m_points; + bool m_log = false; +public: + explicit Histogram(QWidget *parent = nullptr); +public slots: + void imageLoaded(Image *img); +protected: + void paintEvent(QPaintEvent *) override; + void mouseReleaseEvent(QMouseEvent *) override; +}; + +#endif // HISTOGRAM_H diff --git a/libXISF b/libXISF index 0b0c865..8a1f305 160000 --- a/libXISF +++ b/libXISF @@ -1 +1 @@ -Subproject commit 0b0c865df02fccf1cb300553c2d1ce4d155fbaf9 +Subproject commit 8a1f305cc71135003ef78c919787bbc2865f77af diff --git a/mainwindow.cpp b/mainwindow.cpp index dcc97b7..9edbf63 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -23,6 +23,7 @@ #include "about.h" #include "statusbar.h" #include "settingsdialog.h" +#include "histogram.h" #ifdef __linux__ #include @@ -120,6 +121,13 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) databaseViewDock->hide(); addDockWidget(Qt::LeftDockWidgetArea, filetreeDock); + Histogram *histogram = new Histogram(this); + QDockWidget *histogramDock = new QDockWidget(tr("Histogram"), this); + histogramDock->setWidget(histogram); + histogramDock->setObjectName("histogramDock"); + histogramDock->show(); + addDockWidget(Qt::LeftDockWidgetArea, histogramDock); + setWindowTitle(tr("Tenmon")); connect(m_ringList, SIGNAL(pixmapLoaded(Image*)), this, SLOT(pixmapLoaded(Image*))); @@ -128,6 +136,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) connect(m_ringList, SIGNAL(currentImageChanged(int)), m_filesystem, SLOT(selectFile(int))); connect(m_ringList, &ImageRingList::thumbnailLoaded, m_imageGL->imageWidget(), &ImageWidget::thumbnailLoaded); connect(m_ringList, &ImageRingList::pixmapLoaded, m_stretchPanel, &StretchToolbar::imageLoaded); + connect(m_ringList, &ImageRingList::pixmapLoaded, histogram, &Histogram::imageLoaded); connect(m_imageGL->imageWidget(), &ImageWidget::fileDropped, this, static_cast(&MainWindow::loadFile)); QMenu *fileMenu = new QMenu(tr("File"), this); @@ -207,6 +216,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) dockMenu->addAction(filesystemDock->toggleViewAction()); dockMenu->addAction(databaseViewDock->toggleViewAction()); dockMenu->addAction(filetreeDock->toggleViewAction()); + dockMenu->addAction(histogramDock->toggleViewAction()); menuBar()->addMenu(dockMenu); QMenu *helpMenu = menuBar()->addMenu(tr("Help")); diff --git a/rawimage.cpp b/rawimage.cpp index 203e530..73ed373 100644 --- a/rawimage.cpp +++ b/rawimage.cpp @@ -197,6 +197,9 @@ void calcStats(const T *data, size_t n, RawImage::Stats &stats) stats.m_mad[i] /= 65535.0; } } + + for(size_t i = 0; i < ch; i++) + stats.m_histogram[i] = std::vector(histogram[i], histogram[i] + histSize); } void RawImage::calcStats() diff --git a/rawimage.h b/rawimage.h index 58a85a5..db0f686 100644 --- a/rawimage.h +++ b/rawimage.h @@ -57,6 +57,7 @@ public: double m_max[4] = {0.0}; double m_mad[4] = {0.0}; uint32_t m_saturated[4] = {0}; + std::vector m_histogram[4]; }; protected: std::unique_ptr m_pixels;