* 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
}
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) {
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();
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();
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;
}
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];
}
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;
}
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 };
};
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();
delete ui;
delete m_aUnscaled;
+ delete m_aRec601;
+ delete m_aRec709;
+ delete m_agRec;
}
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()
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();
}
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));
}
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;
private:
HistogramGenerator *m_histogramGenerator;
QAction *m_aUnscaled;
+ QAction *m_aRec601;
+ QAction *m_aRec709;
+ QActionGroup *m_agRec;
QRect scopeRect();
bool isHUDDependingOnInput() const;
<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/>