Commit 89078cf2 authored by Simon Eugster's avatar Simon Eugster Committed by Jean-Baptiste Mardelle
Browse files

Small refactoring, extract CIE factors

See kde/kdenlive#655
parent 41c82802
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
* Dependencies MLT etc. * Dependencies MLT etc.
* MVC * MVC
* GUI elements and their counterpart * GUI elements and their counterpart
* [kdenlivesettings.kcfg](../src/kdenlivesettings.kcfg)
## Architectural Overview ## Architectural Overview
......
...@@ -42,7 +42,7 @@ sudo apt install libkf5archive-dev libkf5bookmarks-dev libkf5coreaddons-dev \ ...@@ -42,7 +42,7 @@ sudo apt install libkf5archive-dev libkf5bookmarks-dev libkf5coreaddons-dev \
libkf5purpose-dev libkf5iconthemes-dev kdoctools-dev libkf5crash-dev \ libkf5purpose-dev libkf5iconthemes-dev kdoctools-dev libkf5crash-dev \
libkf5filemetadata-dev kio kinit qtdeclarative5-dev libqt5svg5-dev \ libkf5filemetadata-dev kio kinit qtdeclarative5-dev libqt5svg5-dev \
qml-module-qtquick-controls qtmultimedia5-dev qtquickcontrols2-5-dev \ qml-module-qtquick-controls qtmultimedia5-dev qtquickcontrols2-5-dev \
appstream gettext libv4l-dev breeze appstream gettext libv4l-dev libqt5webkit5-dev librttr-dev breeze ffmpeg
``` ```
Most development packages will already be installed with the following command: Most development packages will already be installed with the following command:
......
# Coding and Resources
* [All Qt5 classes][qt5c]
* [MLT introduction][mlt-intro].
## Configuration
Named settings are stored in [`kdenlivesettings.kcfg`][sett]. To add a new
setting with default value, add an entry in the settings file, for example:
```xml
<entry name="logscale" type="Bool">
<label>Use logarithmic scale</label>
<default>true</default>
</entry>
```
The setting can then be read and written as follows:
```cpp
// Read
bool logScale = KdenliveSettings::logscale();
// Write
KdenliveSettings::setLogscale(true);
```
[sett]: ../src/kdenlivesettings.kcfg
[mlt-intro]: https://www.mltframework.org/docs/framework/
[qt5c]: https://doc.qt.io/qt-5/classes.html
set(kdenlive_SRCS set(kdenlive_SRCS
${kdenlive_SRCS} ${kdenlive_SRCS}
scopes/colorscopes/colorconstants.h
scopes/colorscopes/abstractgfxscopewidget.cpp scopes/colorscopes/abstractgfxscopewidget.cpp
scopes/colorscopes/colorplaneexport.cpp scopes/colorscopes/colorplaneexport.cpp
scopes/colorscopes/histogram.cpp scopes/colorscopes/histogram.cpp
......
#ifndef KDENLIVE_COLORCONSTANTS_H
#define KDENLIVE_COLORCONSTANTS_H
/**
* ITU-R Recommendation for luminance calculation.
* See http://www.poynton.com/ColorFAQ.html for details.
*/
enum class ITURec {
Rec_601, Rec_709
};
// CIE 601 luminance factors
constexpr float REC_601_R = .299;
constexpr float REC_601_G = .587;
constexpr float REC_601_B = .114;
// CIE 709 luminance factors
constexpr float REC_709_R = .2125;
constexpr float REC_709_G = .7154;
constexpr float REC_709_B = .0721;
#endif //KDENLIVE_COLORCONSTANTS_H
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "klocalizedstring.h" #include "klocalizedstring.h"
#include <KConfigGroup> #include <KConfigGroup>
#include <KSharedConfig> #include <KSharedConfig>
#include <QtWidgets/QButtonGroup>
Histogram::Histogram(QWidget *parent) Histogram::Histogram(QWidget *parent)
: AbstractGfxScopeWidget(false, parent) : AbstractGfxScopeWidget(false, parent)
...@@ -39,6 +40,10 @@ Histogram::Histogram(QWidget *parent) ...@@ -39,6 +40,10 @@ Histogram::Histogram(QWidget *parent)
m_menu->addAction(m_aRec601); m_menu->addAction(m_aRec601);
m_menu->addAction(m_aRec709); m_menu->addAction(m_aRec709);
QButtonGroup scaleGroup;
scaleGroup.addButton(m_ui->rbLinear);
scaleGroup.addButton(m_ui->rbLogarithmic);
connect(m_ui->cbY, &QAbstractButton::toggled, this, &AbstractScopeWidget::forceUpdateScope); connect(m_ui->cbY, &QAbstractButton::toggled, this, &AbstractScopeWidget::forceUpdateScope);
connect(m_ui->cbS, &QAbstractButton::toggled, this, &AbstractScopeWidget::forceUpdateScope); connect(m_ui->cbS, &QAbstractButton::toggled, this, &AbstractScopeWidget::forceUpdateScope);
connect(m_ui->cbR, &QAbstractButton::toggled, this, &AbstractScopeWidget::forceUpdateScope); connect(m_ui->cbR, &QAbstractButton::toggled, this, &AbstractScopeWidget::forceUpdateScope);
...@@ -47,6 +52,7 @@ Histogram::Histogram(QWidget *parent) ...@@ -47,6 +52,7 @@ Histogram::Histogram(QWidget *parent)
connect(m_aUnscaled, &QAction::toggled, this, &Histogram::forceUpdateScope); connect(m_aUnscaled, &QAction::toggled, this, &Histogram::forceUpdateScope);
connect(m_aRec601, &QAction::toggled, this, &Histogram::forceUpdateScope); connect(m_aRec601, &QAction::toggled, this, &Histogram::forceUpdateScope);
connect(m_aRec709, &QAction::toggled, this, &Histogram::forceUpdateScope); connect(m_aRec709, &QAction::toggled, this, &Histogram::forceUpdateScope);
connect(m_ui->rbLogarithmic, &QAbstractButton::toggled, this, &Histogram::forceUpdateScope);
init(); init();
m_histogramGenerator = new HistogramGenerator(); m_histogramGenerator = new HistogramGenerator();
...@@ -76,6 +82,7 @@ void Histogram::readConfig() ...@@ -76,6 +82,7 @@ void Histogram::readConfig()
m_ui->cbB->setChecked(scopeConfig.readEntry("bEnabled", true)); m_ui->cbB->setChecked(scopeConfig.readEntry("bEnabled", true));
m_aRec601->setChecked(scopeConfig.readEntry("rec601", false)); m_aRec601->setChecked(scopeConfig.readEntry("rec601", false));
m_aRec709->setChecked(!m_aRec601->isChecked()); m_aRec709->setChecked(!m_aRec601->isChecked());
m_ui->rbLogarithmic->setChecked(scopeConfig.readEntry("logScale", false));
} }
void Histogram::writeConfig() void Histogram::writeConfig()
...@@ -88,6 +95,7 @@ void Histogram::writeConfig() ...@@ -88,6 +95,7 @@ void Histogram::writeConfig()
scopeConfig.writeEntry("gEnabled", m_ui->cbG->isChecked()); scopeConfig.writeEntry("gEnabled", m_ui->cbG->isChecked());
scopeConfig.writeEntry("bEnabled", m_ui->cbB->isChecked()); scopeConfig.writeEntry("bEnabled", m_ui->cbB->isChecked());
scopeConfig.writeEntry("rec601", m_aRec601->isChecked()); scopeConfig.writeEntry("rec601", m_aRec601->isChecked());
scopeConfig.writeEntry("logScale", m_ui->rbLogarithmic->isChecked());
scopeConfig.sync(); scopeConfig.sync();
} }
...@@ -131,9 +139,9 @@ QImage Histogram::renderGfxScope(uint accelFactor, const QImage &qimage) ...@@ -131,9 +139,9 @@ QImage Histogram::renderGfxScope(uint accelFactor, const QImage &qimage)
(m_ui->cbR->isChecked() ? 1 : 0) * HistogramGenerator::ComponentR | (m_ui->cbG->isChecked() ? 1 : 0) * HistogramGenerator::ComponentG | (m_ui->cbR->isChecked() ? 1 : 0) * HistogramGenerator::ComponentR | (m_ui->cbG->isChecked() ? 1 : 0) * HistogramGenerator::ComponentG |
(m_ui->cbB->isChecked() ? 1 : 0) * HistogramGenerator::ComponentB; (m_ui->cbB->isChecked() ? 1 : 0) * HistogramGenerator::ComponentB;
HistogramGenerator::Rec rec = m_aRec601->isChecked() ? HistogramGenerator::Rec_601 : HistogramGenerator::Rec_709; ITURec rec = m_aRec601->isChecked() ? ITURec::Rec_601 : ITURec::Rec_709;
QImage histogram = m_histogramGenerator->calculateHistogram(m_scopeRect.size(), qimage, componentFlags, rec, m_aUnscaled->isChecked(), accelFactor); QImage histogram = m_histogramGenerator->calculateHistogram(m_scopeRect.size(), qimage, componentFlags, rec, m_aUnscaled->isChecked(), m_ui->rbLogarithmic->isChecked(), accelFactor);
emit signalScopeRenderingFinished(uint(timer.elapsed()), accelFactor); emit signalScopeRenderingFinished(uint(timer.elapsed()), accelFactor);
return histogram; return histogram;
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
***************************************************************************/ ***************************************************************************/
#include "histogramgenerator.h" #include "histogramgenerator.h"
#include "colorconstants.h"
#include "klocalizedstring.h" #include "klocalizedstring.h"
#include <QImage> #include <QImage>
...@@ -18,7 +19,8 @@ ...@@ -18,7 +19,8 @@
HistogramGenerator::HistogramGenerator() = default; HistogramGenerator::HistogramGenerator() = default;
QImage HistogramGenerator::calculateHistogram(const QSize &paradeSize, const QImage &image, const int &components, HistogramGenerator::Rec rec, bool unscaled, QImage HistogramGenerator::calculateHistogram(const QSize &paradeSize, const QImage &image, const int &components,
ITURec rec, bool unscaled, bool logScale,
uint accelFactor) const uint accelFactor) const
{ {
if (paradeSize.height() <= 0 || paradeSize.width() <= 0 || image.width() <= 0 || image.height() <= 0) { if (paradeSize.height() <= 0 || paradeSize.width() <= 0 || image.width() <= 0 || image.height() <= 0) {
...@@ -39,27 +41,27 @@ QImage HistogramGenerator::calculateHistogram(const QSize &paradeSize, const QIm ...@@ -39,27 +41,27 @@ QImage HistogramGenerator::calculateHistogram(const QSize &paradeSize, const QIm
std::fill(y, y + 256, 0); std::fill(y, y + 256, 0);
std::fill(s, s + 766, 0); std::fill(s, s + 766, 0);
const uint iw = (uint)image.bytesPerLine();
const uint ih = (uint)image.height();
const uint ww = (uint)paradeSize.width(); const uint ww = (uint)paradeSize.width();
const uint wh = (uint)paradeSize.height(); const uint wh = (uint)paradeSize.height();
const uint byteCount = iw * ih;
// Read the stats from the input image // Read the stats from the input image
for (int Y = 0; Y < image.height(); ++Y) { for (int Y = 0; Y < image.height(); ++Y) {
for (int X = 0; X < image.width(); X += (int)accelFactor) { for (int X = 0; X < image.width(); X += (int)accelFactor) {
QRgb col = image.pixel(X, Y); QRgb col = image.pixel(X, Y);
r[qRed(col)]++; r[qRed(col)]++;
g[qGreen(col)]++; g[qGreen(col)]++;
b[qBlue(col)]++; b[qBlue(col)]++;
if (drawY) { if (drawY) {
// Use if branch to avoid expensive multiplication if Y disabled // Use if branch to avoid expensive multiplication if Y disabled
if (rec == HistogramGenerator::Rec_601) { if (rec == ITURec::Rec_601) {
y[(int)floor(.299 * qRed(col) + .587 * qGreen(col) + .114 * qBlue(col))]++; y[(int)floor(REC_601_R * (float) qRed(col) + REC_601_G * (float) qGreen(col) + REC_601_B * (float) qBlue(col))]++;
} else { } else {
y[(int)floor(.2125 * qRed(col) + .7154 * qGreen(col) + .0721 * qBlue(col))]++; y[(int)floor(REC_709_R * (float) qRed(col) + REC_709_G * (float) qGreen(col) + REC_709_B * (float) qBlue(col))]++;
} }
} }
if (drawSum) { if (drawSum) {
// Use an if branch here because the sum takes more operations than rgb // Use an if branch here because the sum takes more operations than rgb
s[qRed(col)]++; s[qRed(col)]++;
...@@ -75,53 +77,68 @@ QImage HistogramGenerator::calculateHistogram(const QSize &paradeSize, const QIm ...@@ -75,53 +77,68 @@ QImage HistogramGenerator::calculateHistogram(const QSize &paradeSize, const QIm
return QImage(); return QImage();
} }
const int d = 20; // Distance for text // Distance for text
const int d = 20;
// Height of a single histogram box without text
const int partH = int((int)wh - nParts * d) / nParts; const int partH = int((int)wh - nParts * d) / nParts;
// Total number of bytes of the image
const uint byteCount = (uint) image.sizeInBytes();
// Factor for scaling the measured value to the histogram.
// This factor is used for linear scaling and does not depend
// on the measured histogram values. Very large values,
// e.g. in an image with a lot of white, are clipped.
// Otherwise, the relatively low height of the histogram
// would show all other values close to 0 when one bin is very high.
float scaling = 0; float scaling = 0;
int div = (int)byteCount >> 7; int div = (int)byteCount >> 7;
if (div > 0) { if (div > 0) {
scaling = (float)partH / float((int)byteCount >> 7); scaling = (float)partH / float(byteCount >> 7);
} }
const int dist = 40; const int dist = 40;
int wy = 0; // Drawing position
QImage histogram(paradeSize, QImage::Format_ARGB32); QImage histogram(paradeSize, QImage::Format_ARGB32);
QPainter davinci(&histogram); QPainter davinci(&histogram);
davinci.setPen(QColor(220, 220, 220, 255)); davinci.setPen(QColor(220, 220, 220, 255));
histogram.fill(qRgba(0, 0, 0, 0)); histogram.fill(qRgba(0, 0, 0, 0));
if (drawY) { QColor neutralColor(220, 220, 210, 255);
drawComponentFull(&davinci, y, scaling, QRect(0, wy, (int)ww, partH + dist), QColor(220, 220, 210, 255), dist, unscaled, 256); QColor redColor(255, 128, 0, 255);
QColor greenColor(128, 255, 0, 255);
QColor blueColor(0, 128, 255, 255);
int wy = 0; // Drawing position
if (drawY) {
drawComponentFull(&davinci, y, scaling, QRect(0, wy, (int)ww, partH + dist), neutralColor, dist, unscaled, logScale, 256);
wy += partH + d; wy += partH + d;
} }
if (drawSum) { if (drawSum) {
drawComponentFull(&davinci, s, scaling / 3, QRect(0, wy, (int)ww, partH + dist), QColor(220, 220, 210, 255), dist, unscaled, 256); drawComponentFull(&davinci, s, scaling / 3, QRect(0, wy, (int)ww, partH + dist), neutralColor, dist, unscaled, logScale, 256);
wy += partH + d; wy += partH + d;
} }
if (drawR) { if (drawR) {
drawComponentFull(&davinci, r, scaling, QRect(0, wy, (int)ww, partH + dist), QColor(255, 128, 0, 255), dist, unscaled, 256); drawComponentFull(&davinci, r, scaling, QRect(0, wy, (int)ww, partH + dist), redColor, dist, unscaled, logScale, 256);
wy += partH + d; wy += partH + d;
} }
if (drawG) { if (drawG) {
drawComponentFull(&davinci, g, scaling, QRect(0, wy, (int)ww, partH + dist), QColor(128, 255, 0, 255), dist, unscaled, 256); drawComponentFull(&davinci, g, scaling, QRect(0, wy, (int)ww, partH + dist), greenColor, dist, unscaled, logScale, 256);
wy += partH + d; wy += partH + d;
} }
if (drawB) { if (drawB) {
drawComponentFull(&davinci, b, scaling, QRect(0, wy, (int)ww, partH + dist), QColor(0, 128, 255, 255), dist, unscaled, 256); drawComponentFull(&davinci, b, scaling, QRect(0, wy, (int)ww, partH + dist), blueColor, dist, unscaled, logScale, 256);
} }
return histogram; return histogram;
} }
QImage HistogramGenerator::drawComponent(const int *y, const QSize &size, const float &scaling, const QColor &color, bool unscaled, uint max) const QImage HistogramGenerator::drawComponent(const int *y, const QSize &size, const float &scaling, const QColor &color, bool unscaled, bool logScale, uint max)
{ {
QImage component((int)max, size.height(), QImage::Format_ARGB32); QImage component((int)max, size.height(), QImage::Format_ARGB32);
component.fill(qRgba(0, 0, 0, 255)); component.fill(qRgba(0, 0, 0, 255));
...@@ -129,9 +146,18 @@ QImage HistogramGenerator::drawComponent(const int *y, const QSize &size, const ...@@ -129,9 +146,18 @@ QImage HistogramGenerator::drawComponent(const int *y, const QSize &size, const
const int partH = size.height(); const int partH = size.height();
const int maxBinSize = *std::max_element(&y[0], &y[max - 1]);
const float logScaling = float(size.height()) / log10f(float(maxBinSize + 1));
for (uint x = 0; x < max; ++x) { for (uint x = 0; x < max; ++x) {
// Calculate the height of the curve at position x // Calculate the height of the curve at position x
int partY = int(scaling * (float)y[x]); int partY;
if (logScale) {
partY = int(logScaling * log10f(float(y[x] + 1)));
} else {
partY = int(scaling * (float)y[x]);
}
// Invert the y axis // Invert the y axis
if (partY > partH - 1) { if (partY > partH - 1) {
...@@ -150,9 +176,9 @@ QImage HistogramGenerator::drawComponent(const int *y, const QSize &size, const ...@@ -150,9 +176,9 @@ 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, int textSpace, void HistogramGenerator::drawComponentFull(QPainter *davinci, const int *y, const float &scaling, const QRect &rect, const QColor &color, int textSpace,
bool unscaled, uint max) const bool unscaled, bool logScale, uint max)
{ {
QImage component = drawComponent(y, rect.size() - QSize(0, textSpace), scaling, color, unscaled, max); QImage component = drawComponent(y, rect.size() - QSize(0, textSpace), scaling, color, unscaled, logScale, max);
davinci->drawImage(rect.topLeft(), component); davinci->drawImage(rect.topLeft(), component);
uint min = 0; uint min = 0;
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#define HISTOGRAMGENERATOR_H #define HISTOGRAMGENERATOR_H
#include <QObject> #include <QObject>
#include "colorconstants.h"
class QColor; class QColor;
class QImage; class QImage;
...@@ -25,21 +26,36 @@ class HistogramGenerator : public QObject ...@@ -25,21 +26,36 @@ class HistogramGenerator : public QObject
public: public:
explicit HistogramGenerator(); explicit 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. * 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. * @param paradeSize
unscaled = true leaves the width at 256 if the widget is wider (to avoid scaling). */ * @param image
QImage calculateHistogram(const QSize &paradeSize, const QImage &image, const int &components, const HistogramGenerator::Rec rec, bool unscaled, * @param components OR-ed HistogramGenerator::Components flags and decide with components (Y, R, G, B) to paint.
* @param rec
* @param unscaled unscaled = true leaves the width at 256 if the widget is wider (to avoid scaling).
* @param logScale Use a logarithmic instead of linear scale.
* @param accelFactor
* @return
*/
QImage calculateHistogram(const QSize &paradeSize, const QImage &image, const int &components, const ITURec rec, bool unscaled,
bool logScale,
uint accelFactor = 1) const; uint accelFactor = 1) const;
QImage drawComponent(const int *y, const QSize &size, const float &scaling, const QColor &color, bool unscaled, uint max) const; /**
* Draws the histogram of a single component.
void drawComponentFull(QPainter *davinci, const int *y, const float &scaling, const QRect &rect, const QColor &color, int textSpace, bool unscaled, *
uint max) const; * @param y Bins containing the number of samples per value
* @param size Desired box size of the histogram
* @param scaling Use this scaling factor to scale the y values to the box height
* @param color Color to use for drawing
* @param unscaled Do not scale the width but take the number of bins instead (usually 256)
* @param logScale Use logarithmic scale instead of linear
* @param max Number of bins, usually 256
*/
static QImage drawComponent(const int *y, const QSize &size, const float &scaling, const QColor &color, bool unscaled, bool logScale, uint max) ;
static void drawComponentFull(QPainter *davinci, const int *y, const float &scaling, const QRect &rect, const QColor &color, int textSpace,
bool unscaled, bool logScale, uint max) ;
enum Components { ComponentY = 1 << 0, ComponentR = 1 << 1, ComponentG = 1 << 2, ComponentB = 1 << 3, ComponentSum = 1 << 4 }; enum Components { ComponentY = 1 << 0, ComponentR = 1 << 1, ComponentG = 1 << 2, ComponentB = 1 << 3, ComponentSum = 1 << 4 };
}; };
......
...@@ -181,7 +181,7 @@ QImage Waveform::renderGfxScope(uint accelFactor, const QImage &qimage) ...@@ -181,7 +181,7 @@ QImage Waveform::renderGfxScope(uint accelFactor, const QImage &qimage)
timer.start(); timer.start();
const int paintmode = m_ui->paintMode->itemData(m_ui->paintMode->currentIndex()).toInt(); const int paintmode = m_ui->paintMode->itemData(m_ui->paintMode->currentIndex()).toInt();
WaveformGenerator::Rec rec = m_aRec601->isChecked() ? WaveformGenerator::Rec_601 : WaveformGenerator::Rec_709; ITURec rec = m_aRec601->isChecked() ? ITURec::Rec_601 : ITURec::Rec_709;
QImage wave = m_waveformGenerator->calculateWaveform(scopeRect().size() - m_textWidth - QSize(0, m_paddingBottom), qimage, QImage wave = m_waveformGenerator->calculateWaveform(scopeRect().size() - m_textWidth - QSize(0, m_paddingBottom), qimage,
(WaveformGenerator::PaintMode)paintmode, true, rec, accelFactor); (WaveformGenerator::PaintMode)paintmode, true, rec, accelFactor);
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
***************************************************************************/ ***************************************************************************/
#include "waveformgenerator.h" #include "waveformgenerator.h"
#include "colorconstants.h"
#include <cmath> #include <cmath>
...@@ -25,7 +26,7 @@ WaveformGenerator::WaveformGenerator() = default; ...@@ -25,7 +26,7 @@ WaveformGenerator::WaveformGenerator() = default;
WaveformGenerator::~WaveformGenerator() = default; WaveformGenerator::~WaveformGenerator() = default;
QImage WaveformGenerator::calculateWaveform(const QSize &waveformSize, const QImage &image, WaveformGenerator::PaintMode paintMode, bool drawAxis, QImage WaveformGenerator::calculateWaveform(const QSize &waveformSize, const QImage &image, WaveformGenerator::PaintMode paintMode, bool drawAxis,
WaveformGenerator::Rec rec, uint accelFactor) ITURec rec, uint accelFactor)
{ {
Q_ASSERT(accelFactor >= 1); Q_ASSERT(accelFactor >= 1);
...@@ -70,12 +71,12 @@ QImage WaveformGenerator::calculateWaveform(const QSize &waveformSize, const QIm ...@@ -70,12 +71,12 @@ QImage WaveformGenerator::calculateWaveform(const QSize &waveformSize, const QIm
double dY, dx, dy; double dY, dx, dy;
auto *col = (const QRgb *)bits; auto *col = (const QRgb *)bits;
if (rec == WaveformGenerator::Rec_601) { if (rec == ITURec::Rec_601) {
// CIE 601 Luminance // CIE 601 Luminance
dY = .299 * qRed(*col) + .587 * qGreen(*col) + .114 * qBlue(*col); dY = REC_601_R * float(qRed(*col)) + REC_601_G * float(qGreen(*col)) + REC_601_B * float(qBlue(*col));
} else { } else {
// CIE 709 Luminance // CIE 709 Luminance
dY = .2125 * qRed(*col) + .7154 * qGreen(*col) + .0721 * qBlue(*col); dY = REC_709_R * float(qRed(*col)) + REC_709_G * float(qGreen(*col)) + REC_709_B * float(qBlue(*col));
} }
// dY is on [0,255] now. // dY is on [0,255] now.
......
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
#define WAVEFORMGENERATOR_H #define WAVEFORMGENERATOR_H
#include <QObject> #include <QObject>
#include "colorconstants.h"
class QImage; class QImage;
class QSize; class QSize;
...@@ -21,13 +23,12 @@ class WaveformGenerator : public QObject ...@@ -21,13 +23,12 @@ class WaveformGenerator : public QObject
public: public:
enum PaintMode { PaintMode_Green, PaintMode_Yellow, PaintMode_White }; enum PaintMode { PaintMode_Green, PaintMode_Yellow, PaintMode_White };
enum Rec { Rec_601, Rec_709 };
WaveformGenerator(); WaveformGenerator();
~WaveformGenerator() override; ~WaveformGenerator() override;
QImage calculateWaveform(const QSize &waveformSize, const QImage &image, WaveformGenerator::PaintMode paintMode, bool drawAxis, QImage calculateWaveform(const QSize &waveformSize, const QImage &image, WaveformGenerator::PaintMode paintMode, bool drawAxis,
const WaveformGenerator::Rec rec, uint accelFactor = 1); const ITURec rec, uint accelFactor = 1);
}; };
#endif // WAVEFORMGENERATOR_H #endif // WAVEFORMGENERATOR_H
...@@ -11,69 +11,143 @@ ...@@ -11,69 +11,143 @@