Commit c471a29f authored by Simon Eugster's avatar Simon Eugster
Browse files

Colorplane export changes:

* YUV plane with Y varying can be exported (ratio U:V fixed)
* RGB plane with two components on one and one component on other axis can be exported
  Usage: e.g. for Curves widget, to visualize color changes
Vectorscope changes:
* Realtime factor shown
* Pixel brightness relative to image size for Green (still needs to be tweaked)

svn path=/trunk/kdenlive/; revision=4587
parent 2b62e018
......@@ -25,8 +25,10 @@ ColorPlaneExport::ColorPlaneExport(QWidget *parent) :
tResX->setText("800");
tResY->setText("800");
cbColorspace->addItem(i18n("YUV"), QVariant(CPE_YUV));
cbColorspace->addItem(i18n("YUV UV plane"), QVariant(CPE_YUV));
cbColorspace->addItem(i18n("YUV Y plane"), QVariant(CPE_YUV_Y));
cbColorspace->addItem(i18n("Modified YUV (Chroma)"), QVariant(CPE_YUV_MOD));
cbColorspace->addItem(i18n("RGB plane, one component varying"), QVariant(CPE_RGB_CURVE));
sliderColor->setSliderPosition(128);
......@@ -43,6 +45,7 @@ ColorPlaneExport::ColorPlaneExport(QWidget *parent) :
connect(kurlrequester, SIGNAL(textChanged(QString)), this, SLOT(slotValidate()));
connect(sliderColor, SIGNAL(valueChanged(int)), this, SLOT(slotUpdateDisplays()));
connect(sliderScaling, SIGNAL(valueChanged(int)), this, SLOT(slotUpdateDisplays()));
connect(cbColorspace, SIGNAL(currentIndexChanged(int)), this, SLOT(slotColormodeChanged()));
kurlrequester->setText("/tmp/yuv-plane.png");
......@@ -55,12 +58,53 @@ ColorPlaneExport::~ColorPlaneExport()
delete m_colorTools;
}
///// Helper functions /////
void ColorPlaneExport::enableSliderScaling(const bool &enable)
{
sliderScaling->setEnabled(enable);
lblScaling->setEnabled(enable);
lblScaleNr->setEnabled(enable);
}
void ColorPlaneExport::enableSliderColor(const bool &enable)
{
sliderColor->setEnabled(enable);
lblSliderName->setEnabled(enable);
lblColNr->setEnabled(enable);
}
void ColorPlaneExport::enableCbVariant(const bool &enable)
{
cbVariant->setEnabled(enable);
lblVariant->setEnabled(enable);
if (!enable) {
while (cbVariant->count() > 0) {
cbVariant->removeItem(0);
}
}
}
///// Slots /////
void ColorPlaneExport::slotUpdateDisplays()
{
m_scaling = 1 - (float)sliderScaling->value()/100;
lblScaleNr->setText("0..." + QString::number(m_scaling, 'f', 2));
lblColNr->setText(QString::number(sliderColor->value()));
switch (cbColorspace->itemData(cbColorspace->currentIndex()).toInt()) {
case CPE_YUV_Y:
lblColNr->setText(i18n("%1 °", QString::number(sliderColor->value())));
break;
default:
lblColNr->setText(QString::number(sliderColor->value()));
break;
}
lblSize->setText(i18n("%1 px", QVariant(tResX->text()).toInt()*QVariant(tResY->text()).toInt()));
}
......@@ -106,23 +150,55 @@ void ColorPlaneExport::slotExportPlane()
case CPE_YUV:
img = m_colorTools->yuvColorWheel(size, sliderColor->value(), m_scaling, false, false);
break;
case CPE_YUV_Y:
img = m_colorTools->yuvVerticalPlane(size, sliderColor->value(), m_scaling);
break;
case CPE_YUV_MOD:
img = m_colorTools->yuvColorWheel(size, sliderColor->value(), m_scaling, true, false);
break;
case CPE_RGB_CURVE:
img = m_colorTools->rgbCurvePlane(size, (ColorTools::ColorsRGB) (cbVariant->itemData(cbVariant->currentIndex()).toInt()));
break;
}
img.save(kurlrequester->text());
}
void ColorPlaneExport::slotColormodeChanged()
{
qDebug() << "Color mode changed to " << cbColorspace->itemData(cbColorspace->currentIndex()).toInt();
switch (cbColorspace->itemData(cbColorspace->currentIndex()).toInt()) {
case CPE_YUV:
case CPE_YUV_MOD:
sliderColor->setVisible(true);
enableSliderScaling(true);
enableSliderColor(true);
enableCbVariant(false);
sliderColor->setRange(0,255);
sliderColor->setPageStep(128);
lblSliderName->setText(i18n("Y value"));
lblSliderName->setToolTip(i18n("The Y value describes the brightness of the colors."));
break;
case CPE_YUV_Y:
qDebug() << "Changing slider range.";
enableSliderScaling(true);
enableSliderColor(true);
enableCbVariant(false);
sliderColor->setMaximum(321);
sliderColor->setRange(0,179);
sliderColor->setPageStep(90);
lblSliderName->setText(i18n("UV angle"));
lblSliderName->setToolTip(i18n("Angle through the UV plane, with all possible Y values."));
break;
case CPE_RGB_CURVE:
// deliberately fall through
default:
sliderColor->setVisible(false);
enableSliderScaling(false);
enableSliderColor(false);
enableCbVariant(true);
cbVariant->addItem(i18n("Red"), QVariant(ColorTools::COL_R));
cbVariant->addItem(i18n("Green"), QVariant(ColorTools::COL_G));
cbVariant->addItem(i18n("Blue"), QVariant(ColorTools::COL_B));
break;
}
this->update();
slotUpdateDisplays();
}
......@@ -22,7 +22,7 @@
class ColorPlaneExport_UI;
enum COLOR_EXPORT_MODE { CPE_YUV, CPE_YUV_MOD };
enum COLOR_EXPORT_MODE { CPE_YUV, CPE_YUV_Y, CPE_YUV_MOD, CPE_RGB_CURVE };
class ColorPlaneExport : public QDialog, public Ui::ColorPlaneExport_UI {
Q_OBJECT
......@@ -36,6 +36,9 @@ private:
ColorTools *m_colorTools;
float m_scaling;
float m_Y;
void enableSliderScaling(const bool &enable);
void enableSliderColor(const bool &enable);
void enableCbVariant(const bool &enable);
private slots:
......
......@@ -17,7 +17,7 @@ ColorTools::ColorTools()
QImage ColorTools::yuvColorWheel(const QSize &size, unsigned char Y, float scaling, bool modifiedVersion, bool circleOnly)
QImage ColorTools::yuvColorWheel(const QSize &size, const unsigned char &Y, const float &scaling, const bool &modifiedVersion, const bool &circleOnly)
{
QImage wheel(size, QImage::Format_ARGB32);
if (size.width() == 0 || size.height() == 0) {
......@@ -89,3 +89,85 @@ QImage ColorTools::yuvColorWheel(const QSize &size, unsigned char Y, float scali
emit signalWheelCalculationFinished();
return wheel;
}
QImage ColorTools::yuvVerticalPlane(const QSize &size, const float &angle, const float &scaling)
{
QImage plane(size, QImage::Format_ARGB32);
if (size.width() == 0 || size.height() == 0) {
qCritical("ERROR: Size of the color plane must not be 0!");
return plane;
}
double dr, dg, db, du, dv, Y;
const int w = size.width();
const int h = size.height();
const double uscaling = scaling*cos(M_PI*angle/180);
const double vscaling = scaling*sin(M_PI*angle/180);
for (int uv = 0; uv < w; uv++) {
du = uscaling*((double)2*uv/w - 1);//(double)?
dv = vscaling*((double)2*uv/w - 1);
for (int y = 0; y < h; y++) {
Y = (double)255*y/h;
// See yuv2rgb, yuvColorWheel
dr = Y + 290.8*dv;
dg = Y - 100.6*du - 148*dv;
db = Y + 517.2*du;
if (dr < 0) dr = 0;
if (dg < 0) dg = 0;
if (db < 0) db = 0;
if (dr > 255) dr = 255;
if (dg > 255) dg = 255;
if (db > 255) db = 255;
plane.setPixel(uv, (h-y-1), qRgba(dr, dg, db, 255));
}
}
return plane;
}
QImage ColorTools::rgbCurvePlane(const QSize &size, const ColorsRGB &color)
{
QImage plane(size, QImage::Format_ARGB32);
if (size.width() == 0 || size.height() == 0) {
qCritical("ERROR: Size of the color plane must not be 0!");
return plane;
}
const int w = size.width();
const int h = size.height();
double dcol, dval;
for (int x = 0; x < w; x++) {
dval = (double)255*x/w;
for (int y = 0; y < h; y++) {
dcol = (double)255*y/h;
if (color == ColorTools::COL_R) {
plane.setPixel(x, (h-y-1), qRgb(dcol, dval, dval));
} else if (color == ColorTools::COL_G) {
plane.setPixel(x, (h-y-1), qRgb(dval, dcol, dval));
} else {
plane.setPixel(x, (h-y-1), qRgb(dval, dval, dcol));
}
}
}
return plane;
}
......@@ -17,6 +17,8 @@
#include <QImage>
class ColorTools : public QObject
{
Q_OBJECT
......@@ -24,6 +26,8 @@ class ColorTools : public QObject
public:
ColorTools();
enum ColorsRGB { COL_R, COL_G, COL_B };
/**
@brief Draws a UV plane with given Y value.
scaling defines how far to zoom in (or out). Lower value = zoom in.
......@@ -31,7 +35,23 @@ public:
If not the full rect should be filled, set circleOnly to true.
See also: http://en.wikipedia.org/wiki/YUV and http://de.wikipedia.org/wiki/Vektorskop
*/
QImage yuvColorWheel(const QSize& size, const unsigned char Y, const float scaling, const bool modifiedVersion, const bool circleOnly);
QImage yuvColorWheel(const QSize& size, const unsigned char &Y, const float &scaling, const bool &modifiedVersion, const bool &circleOnly);
/**
@brief Draws a UV plane with given UV angle (ratio u:v stays constant)
scaling defines how far to zoom in (or out). Lower value = zoom in.
angle defines the angle in a default U/V plane. A vertical plane, on which Y goes from 0 to 1,
is then laid through the UV plane, with the defined angle.
@see yuvColorWheel()
*/
QImage yuvVerticalPlane(const QSize &size, const float &angle, const float &scaling);
/**
@brief Draws a RGB plane with two values on one axis and one on the other.
This is e.g. useful as background for a curves dialog. On the line from bottom left to top right
are neutral colors. The colors on the y axis show what the neutral color will look like when modifying the curve.
color defines the color to modify on the y axis. The other two components will be increased
in equal terms (linear as well) on the x axis.
*/
QImage rgbCurvePlane(const QSize &size, const ColorTools::ColorsRGB &color);
signals:
void signalWheelCalculationFinished();
......
......@@ -251,6 +251,10 @@ void Vectorscope::calculateScope()
QPoint pt;
QRgb px;
// Just an average for the number of image pixels per scope pixel.
double avgPxPerPx = (double) 4*img.byteCount()/scope.size().width()/scope.size().height()/skipPixels;
qDebug() << "Expecting " << avgPxPerPx << " pixels per pixel.";
const QRect scopeRect(QPoint(0,0), scope.size());
for (int i = 0; i < img.byteCount(); i+= stepsize) {
......@@ -318,12 +322,13 @@ void Vectorscope::calculateScope()
break;
case PAINT_GREEN:
px = scope.pixel(pt);
scope.setPixel(pt, qRgba(qRed(px)+(255-qRed(px))/30, 255, qBlue(px)+(255-qBlue(px))/25, qAlpha(px)+(255-qAlpha(px))/20));
scope.setPixel(pt, qRgba(qRed(px)+(255-qRed(px))/(3*avgPxPerPx), qGreen(px)+20*(255-qGreen(px))/(avgPxPerPx),
qBlue(px)+(255-qBlue(px))/(avgPxPerPx), qAlpha(px)+(255-qAlpha(px))/(avgPxPerPx)));
break;
case PAINT_GREEN2:
px = scope.pixel(pt);
scope.setPixel(pt, qRgba(qRed(px)+ceil((255-(float)qRed(px))/30), 255,
qBlue(px)+ceil((255-(float)qBlue(px))/25), qAlpha(px)+ceil((255-(float)qAlpha(px))/20)));
scope.setPixel(pt, qRgba(qRed(px)+ceil((255-(float)qRed(px))/(4*avgPxPerPx)), 255,
qBlue(px)+ceil((255-(float)qBlue(px))/(avgPxPerPx)), qAlpha(px)+ceil((255-(float)qAlpha(px))/(avgPxPerPx))));
break;
case PAINT_BLACK:
px = scope.pixel(pt);
......@@ -498,6 +503,13 @@ void Vectorscope::paintEvent(QPaintEvent *)
circleEnabled = false;
}
// Draw realtime factor (number of skipped pixels)
if (m_aRealtime->isChecked()) {
davinci.setPen(penThin);
davinci.drawText(m_scopeRect.bottomRight()-QPoint(40,15), QVariant(m_skipPixels).toString().append("x"));
}
}
......
......@@ -6,166 +6,163 @@
<rect>
<x>0</x>
<y>0</y>
<width>488</width>
<height>213</height>
<width>553</width>
<height>241</height>
</rect>
</property>
<property name="windowTitle">
<string>Export color plane to PNG</string>
</property>
<widget class="QWidget" name="gridLayoutWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>471</width>
<height>193</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="horizontalSpacing">
<number>10</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="lblSpace">
<property name="text">
<string>Color space</string>
</property>
</widget>
</item>
<item row="0" column="1" colspan="3">
<widget class="QComboBox" name="cbColorspace">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="lblRes">
<property name="text">
<string>Resolution</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="tResX">
<property name="maxLength">
<number>5</number>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QLineEdit" name="tResY">
<property name="maxLength">
<number>5</number>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QLabel" name="lblTimes">
<property name="text">
<string notr="true">×</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="lblFilename">
<property name="text">
<string>Filename</string>
</property>
</widget>
</item>
<item row="5" column="1" colspan="3">
<widget class="KUrlRequester" name="kurlrequester">
<property name="mode">
<set>KFile::File|KFile::LocalOnly</set>
</property>
</widget>
</item>
<item row="4" column="1" colspan="3">
<widget class="QLabel" name="lblSize">
<property name="font">
<font>
<pointsize>8</pointsize>
</font>
</property>
<property name="text">
<string notr="true">(notranslate) Total pixels go here</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="6" column="1" colspan="3">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QSlider" name="sliderColor">
<property name="toolTip">
<string>The Y value describes the brightness of the colors.</string>
</property>
<property name="whatsThis">
<string/>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lblSliderName">
<property name="text">
<string>Y value</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QLabel" name="lblColNr">
<property name="text">
<string notr="true">(notranslate) Y display</string>
</property>
</widget>
</item>
<item row="2" column="1" colspan="2">
<widget class="QSlider" name="sliderScaling">
<property name="toolTip">
<string>How much to zoom in</string>
</property>
<property name="whatsThis">
<string/>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QLabel" name="lblScaleNr">
<property name="text">
<string>(notranslate) % display</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lblScaling">
<property name="text">
<string>Scaling</string>
</property>
</widget>
</item>
</layout>
</widget>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="lblSpace">
<property name="text">
<string>Color space</string>
</property>
</widget>
</item>
<item row="0" column="1" colspan="3">
<widget class="QComboBox" name="cbColorspace">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QLabel" name="lblVariant">
<property name="text">
<string>Variant</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QComboBox" name="cbVariant"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lblSliderName">
<property name="text">
<string notr="true">(notr.ansl.)</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSlider" name="sliderColor">
<property name="whatsThis">
<string/>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QLabel" name="lblColNr">
<property name="text">
<string notr="true">(notranslate) Y display</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="lblScaling">
<property name="text">
<string>Scaling</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSlider" name="sliderScaling">
<property name="toolTip">
<string>How much to zoom in</string>
</property>
<property name="whatsThis">
<string/>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QLabel" name="lblScaleNr">
<property name="text">
<string>(notranslate) % display</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="lblRes">
<property name="text">
<string>Resolution</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="tResX">
<property name="maxLength">
<number>5</number>
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QLabel" name="lblTimes">
<property name="text">
<string notr="true">×</string>
</property>
</widget>
</item>
<item row="4" column="3">
<widget class="QLineEdit" name="tResY">
<property name="maxLength">
<number>5</number>
</property>
</widget>
</item>
<item row="5" column="1" colspan="3">
<widget class="QLabel" name="lblSize">
<property name="font">
<font>
<pointsize>8</pointsize>