Commit e0527084 authored by Simon Eugster's avatar Simon Eugster

Histogram changes:

* 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
parent 0f3dedfa
......@@ -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;
}
......
......@@ -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 };
};
......
......@@ -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;
......
......@@ -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;
......
......@@ -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">
......@@ -16,33 +16,36 @@
<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>
......@@ -62,6 +65,16 @@
</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/>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment