]> git.sesse.net Git - kdenlive/commitdiff
Histogram changes:
authorSimon A. Eugster <simon.eu@gmail.com>
Mon, 30 Aug 2010 20:27:08 +0000 (20:27 +0000)
committerSimon A. Eugster <simon.eu@gmail.com>
Mon, 30 Aug 2010 20:27:08 +0000 (20:27 +0000)
* Support for Rec. 601 AND 709. Default to Rec. 709 (as recommendation for digital video).
* Added a «sum» display, simply summing up R/G/B values.

svn path=/trunk/kdenlive/; revision=4783

src/colorcorrection/histogramgenerator.cpp
src/colorcorrection/histogramgenerator.h
src/histogram.cpp
src/histogram.h
src/widgets/histogram_ui.ui

index 970fc67bd9a9972b7200dc2beae257548ffc3cfe..005633817d1b2c16ed8005a81003339e9b1a64e3 100644 (file)
@@ -19,7 +19,7 @@ HistogramGenerator::HistogramGenerator()
 }
 
 QImage HistogramGenerator::calculateHistogram(const QSize &paradeSize, 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 &paradeSize, 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 &paradeSize, 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 &paradeSize, 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 &paradeSize, 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;
         }
index 399345877ff834563a3bbb63bed0616843dc4532..cfce26f4cf23becd345857a5c1d219af9f6071f8 100644 (file)
@@ -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 &paradeSize, const QImage &image, const int &components, const bool &unscaled,
-                           const uint &accelFactor = 1) const;
+    QImage calculateHistogram(const QSize &paradeSize, 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 };
 
 };
 
index a02cc46de5a9b4d00625b211f3077e6c3979a184..263793e337c1415087d8c5e60fa9370a57d99f61 100644 (file)
@@ -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;
index 554f9401953319b1353d9c5a6f25db916d72c4ea..6272e5b2bf3d728ad01e45df6417fdcf78f079a6 100644 (file)
@@ -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;
index 5a797706ddedb7703dfe25da2b877e1c86bdea72..495a347716cb90832c72cad55627d2f01b59120a 100644 (file)
@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>400</width>
-    <height>300</height>
+    <width>398</width>
+    <height>298</height>
    </rect>
   </property>
   <property name="windowTitle">
   <layout class="QGridLayout" name="gridLayout">
    <item row="0" column="1">
     <widget class="QCheckBox" name="cbY">
+     <property name="toolTip">
+      <string extracomment="Luma value"/>
+     </property>
      <property name="text">
       <string>Y</string>
      </property>
     </widget>
    </item>
-   <item row="0" column="2">
+   <item row="0" column="3">
     <widget class="QCheckBox" name="cbR">
      <property name="text">
       <string>R</string>
      </property>
     </widget>
    </item>
-   <item row="0" column="3">
+   <item row="0" column="4">
     <widget class="QCheckBox" name="cbG">
      <property name="text">
       <string>G</string>
      </property>
     </widget>
    </item>
-   <item row="0" column="4">
+   <item row="0" column="5">
     <widget class="QCheckBox" name="cbB">
      <property name="text">
       <string>B</string>
      </property>
     </widget>
    </item>
-   <item row="1" column="1" colspan="4">
+   <item row="1" column="1" colspan="5">
     <spacer name="verticalSpacer">
      <property name="orientation">
       <enum>Qt::Vertical</enum>
      </property>
     </widget>
    </item>
+   <item row="0" column="2">
+    <widget class="QCheckBox" name="cbS">
+     <property name="toolTip">
+      <string extracomment="RGB summed up"/>
+     </property>
+     <property name="text">
+      <string>Sum</string>
+     </property>
+    </widget>
+   </item>
   </layout>
  </widget>
  <resources/>