From e0527084806d8e0732ff2a939cce395118e2b491 Mon Sep 17 00:00:00 2001 From: "Simon A. Eugster" Date: Mon, 30 Aug 2010 20:27:08 +0000 Subject: [PATCH] =?utf8?q?Histogram=20changes:=20*=20Support=20for=20Rec.?= =?utf8?q?=20601=20AND=20709.=20Default=20to=20Rec.=20709=20(as=20recommen?= =?utf8?q?dation=20for=20digital=20video).=20*=20Added=20a=20=C2=ABsum?= =?utf8?q?=C2=BB=20display,=20simply=20summing=20up=20R/G/B=20values.?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit svn path=/trunk/kdenlive/; revision=4783 --- src/colorcorrection/histogramgenerator.cpp | 57 +++++++++++++++------- src/colorcorrection/histogramgenerator.h | 14 ++++-- src/histogram.cpp | 38 ++++++++++++--- src/histogram.h | 3 ++ src/widgets/histogram_ui.ui | 25 +++++++--- 5 files changed, 101 insertions(+), 36 deletions(-) diff --git a/src/colorcorrection/histogramgenerator.cpp b/src/colorcorrection/histogramgenerator.cpp index 970fc67b..00563381 100644 --- a/src/colorcorrection/histogramgenerator.cpp +++ b/src/colorcorrection/histogramgenerator.cpp @@ -19,7 +19,7 @@ HistogramGenerator::HistogramGenerator() } QImage HistogramGenerator::calculateHistogram(const QSize ¶deSize, const QImage &image, const int &components, - const bool &unscaled, const uint &accelFactor) const + HistogramGenerator::Rec rec, const bool &unscaled, const uint &accelFactor) const { // qDebug() << "Histogram rect size is: " << paradeSize.width() << "/" << paradeSize.height(); if (paradeSize.height() <= 0 || paradeSize.width() <= 0 || image.width() <= 0 || image.height() <= 0) { @@ -30,13 +30,15 @@ QImage HistogramGenerator::calculateHistogram(const QSize ¶deSize, const QIm bool drawR = (components & HistogramGenerator::ComponentR) != 0; bool drawG = (components & HistogramGenerator::ComponentG) != 0; bool drawB = (components & HistogramGenerator::ComponentB) != 0; + bool drawSum = (components & HistogramGenerator::ComponentSum) != 0; - int r[256], g[256], b[256], y[256]; + int r[256], g[256], b[256], y[256], s[766]; // Initialize the values to zero std::fill(r, r+256, 0); std::fill(g, g+256, 0); std::fill(b, b+256, 0); std::fill(y, y+256, 0); + std::fill(s, s+766, 0); const uint iw = image.bytesPerLine(); const uint ih = image.height(); @@ -56,13 +58,26 @@ QImage HistogramGenerator::calculateHistogram(const QSize ¶deSize, const QIm r[qRed(*col)]++; g[qGreen(*col)]++; b[qBlue(*col)]++; - y[(int)floor(.299*qRed(*col) + .587*qGreen(*col) + .114*qBlue(*col))]++; + if (drawY) { + // Use if branch to avoid expensive multiplication if Y disabled + if (rec == HistogramGenerator::Rec_601) { + y[(int)floor(.299*qRed(*col) + .587*qGreen(*col) + .114*qBlue(*col))]++; + } else { + y[(int)floor(.2125*qRed(*col) + .7154*qGreen(*col) + .0721*qBlue(*col))]++; + } + } + if (drawSum) { + // Use an if branch here because the sum takes more operations than rgb + s[qRed(*col)]++; + s[qGreen(*col)]++; + s[qBlue(*col)]++; + } bits += stepsize; } - const int nParts = (drawY ? 1 : 0) + (drawR ? 1 : 0) + (drawG ? 1 : 0) + (drawB ? 1 : 0); + const int nParts = (drawY ? 1 : 0) + (drawR ? 1 : 0) + (drawG ? 1 : 0) + (drawB ? 1 : 0) + (drawSum ? 1 : 0); if (nParts == 0) { // Nothing to draw return QImage(); @@ -82,27 +97,34 @@ QImage HistogramGenerator::calculateHistogram(const QSize ¶deSize, const QIm if (drawY) { // qDebug() << "Drawing Y at " << wy << " with height " << partH; - drawComponentFull(&davinci, y, scaling, QRect(0, wy, ww, partH + dist), QColor(220, 220, 210, 255), dist, unscaled); + drawComponentFull(&davinci, y, scaling, QRect(0, wy, ww, partH + dist), QColor(220, 220, 210, 255), dist, unscaled, 256); + + wy += partH + d; + } + + if (drawSum) { +// qDebug() << "Drawing S at " << wy << " with height " << partH; + drawComponentFull(&davinci, s, scaling/3, QRect(0, wy, ww, partH + dist), QColor(220, 220, 210, 255), dist, unscaled, 256); wy += partH + d; } if (drawR) { // qDebug() << "Drawing R at " << wy << " with height " << partH; - drawComponentFull(&davinci, r, scaling, QRect(0, wy, ww, partH + dist), QColor(255, 128, 0, 255), dist, unscaled); + drawComponentFull(&davinci, r, scaling, QRect(0, wy, ww, partH + dist), QColor(255, 128, 0, 255), dist, unscaled, 256); wy += partH + d; } if (drawG) { // qDebug() << "Drawing G at " << wy << " with height " << partH; - drawComponentFull(&davinci, g, scaling, QRect(0, wy, ww, partH + dist), QColor(128, 255, 0, 255), dist, unscaled); + drawComponentFull(&davinci, g, scaling, QRect(0, wy, ww, partH + dist), QColor(128, 255, 0, 255), dist, unscaled, 256); wy += partH + d; } if (drawB) { // qDebug() << "Drawing B at " << wy << " with height " << partH; - drawComponentFull(&davinci, b, scaling, QRect(0, wy, ww, partH + dist), QColor(0, 128, 255, 255), dist, unscaled); + drawComponentFull(&davinci, b, scaling, QRect(0, wy, ww, partH + dist), QColor(0, 128, 255, 255), dist, unscaled, 256); wy += partH + d; } @@ -110,16 +132,17 @@ QImage HistogramGenerator::calculateHistogram(const QSize ¶deSize, const QIm return histogram; } -QImage HistogramGenerator::drawComponent(const int *y, const QSize &size, const float &scaling, const QColor &color, const bool &unscaled) const +QImage HistogramGenerator::drawComponent(const int *y, const QSize &size, const float &scaling, const QColor &color, + const bool &unscaled, const uint &max) const { - QImage component(256, size.height(), QImage::Format_ARGB32); + QImage component(max, size.height(), QImage::Format_ARGB32); component.fill(qRgba(0, 0, 0, 0)); Q_ASSERT(scaling != INFINITY); const int partH = size.height(); int partY; - for (int x = 0; x < 256; x++) { + for (uint x = 0; x < max; x++) { // Calculate the height of the curve at position x partY = scaling*y[x]; @@ -139,21 +162,21 @@ QImage HistogramGenerator::drawComponent(const int *y, const QSize &size, const } void HistogramGenerator::drawComponentFull(QPainter *davinci, const int *y, const float &scaling, const QRect &rect, - const QColor &color, const int &textSpace, const bool &unscaled) const + const QColor &color, const int &textSpace, const bool &unscaled, const uint &max) const { - QImage component = drawComponent(y, rect.size() - QSize(0, textSpace), scaling, color, unscaled); + QImage component = drawComponent(y, rect.size() - QSize(0, textSpace), scaling, color, unscaled, max); davinci->drawImage(rect.topLeft(), component); int min = 0; - for (int x = 0; x < 256; x++) { + for (uint x = 0; x < max; x++) { min = x; if (y[x] > 0) { break; } } - int max = 255; - for (int x = 255; x >= 0; x--) { - max = x; + int maxVal = max-1; + for (int x = max-1; x >= 0; x--) { + maxVal = x; if (y[x] > 0) { break; } diff --git a/src/colorcorrection/histogramgenerator.h b/src/colorcorrection/histogramgenerator.h index 39934587..cfce26f4 100644 --- a/src/colorcorrection/histogramgenerator.h +++ b/src/colorcorrection/histogramgenerator.h @@ -24,19 +24,23 @@ class HistogramGenerator : public QObject public: HistogramGenerator(); + /** Recommendation to use. + See http://www.poynton.com/ColorFAQ.html for details. */ + enum Rec { Rec_601, Rec_709 }; + /** Calculates a histogram display from the input image. components are OR-ed HistogramGenerator::Components flags and decide with components (Y, R, G, B) to paint. unscaled = true leaves the width at 256 if the widget is wider (to avoid scaling). */ - QImage calculateHistogram(const QSize ¶deSize, const QImage &image, const int &components, const bool &unscaled, - const uint &accelFactor = 1) const; + QImage calculateHistogram(const QSize ¶deSize, const QImage &image, const int &components, const HistogramGenerator::Rec rec, + const bool &unscaled, const uint &accelFactor = 1) const; - QImage drawComponent(const int *y, const QSize &size, const float &scaling, const QColor &color, const bool &unscaled) const; + QImage drawComponent(const int *y, const QSize &size, const float &scaling, const QColor &color, const bool &unscaled, const uint &max) const; void drawComponentFull(QPainter *davinci, const int *y, const float &scaling, const QRect &rect, - const QColor &color, const int &textSpace, const bool &unscaled) const; + const QColor &color, const int &textSpace, const bool &unscaled, const uint &max) const; - enum Components { ComponentY = 1<<0, ComponentR = 1<<1, ComponentG = 1<<2, ComponentB = 1<<3 }; + enum Components { ComponentY = 1<<0, ComponentR = 1<<1, ComponentG = 1<<2, ComponentB = 1<<3, ComponentSum = 1<<4 }; }; diff --git a/src/histogram.cpp b/src/histogram.cpp index a02cc46d..263793e3 100644 --- a/src/histogram.cpp +++ b/src/histogram.cpp @@ -20,23 +20,34 @@ Histogram::Histogram(Monitor *projMonitor, Monitor *clipMonitor, QWidget *parent ui = new Ui::Histogram_UI(); ui->setupUi(this); - ui->cbY->setChecked(true); - ui->cbR->setChecked(true); - ui->cbG->setChecked(true); - ui->cbB->setChecked(true); - m_aUnscaled = new QAction(i18n("Unscaled"), this); m_aUnscaled->setCheckable(true); + + m_aRec601 = new QAction(i18n("Rec. 601"), this); + m_aRec601->setCheckable(true); + m_aRec709 = new QAction(i18n("Rec. 709"), this); + m_aRec709->setCheckable(true); + + m_agRec = new QActionGroup(this); + m_agRec->addAction(m_aRec601); + m_agRec->addAction(m_aRec709); + m_menu->addSeparator(); m_menu->addAction(m_aUnscaled); + m_menu->addSeparator()->setText(i18n("Luma mode")); + m_menu->addAction(m_aRec601); + m_menu->addAction(m_aRec709); bool b = true; b &= connect(ui->cbY, SIGNAL(toggled(bool)), this, SLOT(forceUpdateScope())); + b &= connect(ui->cbS, SIGNAL(toggled(bool)), this, SLOT(forceUpdateScope())); b &= connect(ui->cbR, SIGNAL(toggled(bool)), this, SLOT(forceUpdateScope())); b &= connect(ui->cbG, SIGNAL(toggled(bool)), this, SLOT(forceUpdateScope())); b &= connect(ui->cbB, SIGNAL(toggled(bool)), this, SLOT(forceUpdateScope())); b &= connect(m_aUnscaled, SIGNAL(toggled(bool)), this, SLOT(forceUpdateScope())); + b &= connect(m_aRec601, SIGNAL(toggled(bool)), this, SLOT(forceUpdateScope())); + b &= connect(m_aRec709, SIGNAL(toggled(bool)), this, SLOT(forceUpdateScope())); Q_ASSERT(b); init(); @@ -48,6 +59,9 @@ Histogram::~Histogram() delete ui; delete m_aUnscaled; + delete m_aRec601; + delete m_aRec709; + delete m_agRec; } void Histogram::readConfig() @@ -57,9 +71,12 @@ void Histogram::readConfig() KSharedConfigPtr config = KGlobal::config(); KConfigGroup scopeConfig(config, configName()); ui->cbY->setChecked(scopeConfig.readEntry("yEnabled", true)); + ui->cbS->setChecked(scopeConfig.readEntry("sEnabled", false)); ui->cbR->setChecked(scopeConfig.readEntry("rEnabled", true)); ui->cbG->setChecked(scopeConfig.readEntry("gEnabled", true)); ui->cbB->setChecked(scopeConfig.readEntry("bEnabled", true)); + m_aRec601->setChecked(scopeConfig.readEntry("rec601", false)); + m_aRec709->setChecked(!m_aRec601->isChecked()); } void Histogram::writeConfig() @@ -67,9 +84,11 @@ void Histogram::writeConfig() KSharedConfigPtr config = KGlobal::config(); KConfigGroup scopeConfig(config, configName()); scopeConfig.writeEntry("yEnabled", ui->cbY->isChecked()); + scopeConfig.writeEntry("sEnabled", ui->cbS->isChecked()); scopeConfig.writeEntry("rEnabled", ui->cbR->isChecked()); scopeConfig.writeEntry("gEnabled", ui->cbG->isChecked()); scopeConfig.writeEntry("bEnabled", ui->cbB->isChecked()); + scopeConfig.writeEntry("rec601", m_aRec601->isChecked()); scopeConfig.sync(); } @@ -81,7 +100,7 @@ bool Histogram::isBackgroundDependingOnInput() const { return false; } QRect Histogram::scopeRect() { - qDebug() << "According to the spacer, the top left point is " << ui->verticalSpacer->geometry().x() << "/" << ui->verticalSpacer->geometry().y(); + //qDebug() << "According to the spacer, the top left point is " << ui->verticalSpacer->geometry().x() << "/" << ui->verticalSpacer->geometry().y(); QPoint topleft(offset, offset+ ui->verticalSpacer->geometry().y()); return QRect(topleft, this->rect().size() - QSize(topleft.x() + offset, topleft.y() + offset)); } @@ -97,12 +116,15 @@ QImage Histogram::renderScope(uint accelFactor, QImage qimage) start.start(); const int componentFlags = (ui->cbY->isChecked() ? 1 : 0) * HistogramGenerator::ComponentY + | (ui->cbS->isChecked() ? 1 : 0) * HistogramGenerator::ComponentSum | (ui->cbR->isChecked() ? 1 : 0) * HistogramGenerator::ComponentR | (ui->cbG->isChecked() ? 1 : 0) * HistogramGenerator::ComponentG | (ui->cbB->isChecked() ? 1 : 0) * HistogramGenerator::ComponentB; - QImage histogram = m_histogramGenerator->calculateHistogram(m_scopeRect.size(), qimage, - componentFlags, m_aUnscaled->isChecked(), accelFactor); + HistogramGenerator::Rec rec = m_aRec601->isChecked() ? HistogramGenerator::Rec_601 : HistogramGenerator::Rec_709; + + QImage histogram = m_histogramGenerator->calculateHistogram(m_scopeRect.size(), qimage, componentFlags, + rec, m_aUnscaled->isChecked(), accelFactor); emit signalScopeRenderingFinished(start.elapsed(), accelFactor); return histogram; diff --git a/src/histogram.h b/src/histogram.h index 554f9401..6272e5b2 100644 --- a/src/histogram.h +++ b/src/histogram.h @@ -31,6 +31,9 @@ protected: private: HistogramGenerator *m_histogramGenerator; QAction *m_aUnscaled; + QAction *m_aRec601; + QAction *m_aRec709; + QActionGroup *m_agRec; QRect scopeRect(); bool isHUDDependingOnInput() const; diff --git a/src/widgets/histogram_ui.ui b/src/widgets/histogram_ui.ui index 5a797706..495a3477 100644 --- a/src/widgets/histogram_ui.ui +++ b/src/widgets/histogram_ui.ui @@ -6,8 +6,8 @@ 0 0 - 400 - 300 + 398 + 298 @@ -16,33 +16,36 @@ + + + Y - + R - + G - + B - + Qt::Vertical @@ -62,6 +65,16 @@ + + + + + + + Sum + + + -- 2.39.2