1 /***************************************************************************
2 * Copyright (C) 2010 by Simon Andreas Eugster (simon.eu@gmail.com) *
3 * This file is part of kdenlive. See www.kdenlive.org. *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 ***************************************************************************/
15 The basis matrix for converting RGB to YUV is:
19 0.29900 0.58700 0.11400 1.00000
20 -0.14741 -0.28939 0.43680 x 0.00000
21 0.61478 -0.51480 -0.09998 0.00000
23 The resulting YUV value is then drawn on the circle
24 using U and V as coordinate values.
26 The maximum length of such an UV vector is reached
27 for the colors Red and Cyan: 0.632.
28 To make optimal use of space in the circle, this value
29 can be used for scaling.
31 As we are dealing with RGB values in a range of {0,...,255}
32 and the conversion values are made for [0,1], we already
33 divide the conversion values by 255 previously, e.g. in
37 http://de.wikipedia.org/wiki/Vektorskop
38 http://www.elektroniktutor.de/techno/vektskop.html
45 #include "vectorscopegenerator.h"
47 // The maximum distance from the center for any RGB color is 0.63, so
48 // no need to make the circle bigger than required.
49 const float SCALING = 1/.7;
51 const float VectorscopeGenerator::scaling = 1/.7;
54 Input point is on [-1,1]², 0 being at the center,
55 and positive directions are →top/→right.
57 Maps to the coordinates used in QImages with the 0 point
58 at the top left corner.
77 1. Scale from [-1,1] to [0,1] with y01 := (y+1)/2
78 2. Invert (Orientation of the y axis changes) with y10 := 1-y01
79 3. Scale from [1,0] to [height-1,0] with yy := (height-1) * y10
80 x does not need to be inverted.
83 QPoint VectorscopeGenerator::mapToCircle(const QSize &targetSize, const QPointF &point) const
85 return QPoint( (targetSize.width() -1) * (point.x()+1)/2,
86 (targetSize.height()-1) * (1 - (point.y()+1)/2) );
89 QImage VectorscopeGenerator::calculateVectorscope(const QSize &vectorscopeSize, const QImage &image, const float &gain,
90 const VectorscopeGenerator::PaintMode &paintMode, const bool&,
91 const uint &accelFactor) const
93 // Prepare the vectorscope data
94 const int cw = (vectorscopeSize.width() < vectorscopeSize.height()) ? vectorscopeSize.width() : vectorscopeSize.height();
95 QImage scope = QImage(cw, cw, QImage::Format_ARGB32);
96 scope.fill(qRgba(0,0,0,0));
98 const uchar *bits = image.bits();
101 double dy, dr, dg, db, dmax;
106 const int stepsize = 4*accelFactor;
108 // Just an average for the number of image pixels per scope pixel.
109 // NOTE: byteCount() has to be replaced by (img.bytesPerLine()*img.height()) for Qt 4.5 to compile, see: http://doc.trolltech.org/4.6/qimage.html#bytesPerLine
110 double avgPxPerPx = (double) 4*(image.bytesPerLine()*image.height())/scope.size().width()/scope.size().height()/accelFactor;
111 qDebug() << "Expecting " << avgPxPerPx << " pixels per pixel.";
113 for (int i = 0; i < (image.bytesPerLine()*image.height()); i+= stepsize) {
114 QRgb *col = (QRgb *) bits;
120 y = (double) 0.001173 * r +0.002302 * g +0.0004471* b;
121 u = (double) -0.0005781* r -0.001135 * g +0.001713 * b;
122 v = (double) 0.002411 * r -0.002019 * g -0.0003921* b;
124 pt = mapToCircle(vectorscopeSize, QPointF(SCALING*gain*u, SCALING*gain*v));
126 if (!(pt.x() <= vectorscopeSize.width() && pt.x() >= 0
127 && pt.y() <= vectorscopeSize.height() && pt.y() >= 0)) {
128 // Point lies outside (because of scaling), don't plot it
132 // Draw the pixel using the chosen draw mode.
136 dy = 128; // Default Y value. Lower = darker.
138 // Calculate the RGB values from YUV
140 dg = dy - 100.6*u - 148*v;
146 if (dr > 255) dr = 255;
147 if (dg > 255) dg = 255;
148 if (db > 255) db = 255;
150 scope.setPixel(pt, qRgba(dr, dg, db, 255));
153 case PaintMode_Chroma:
154 dy = 200; // Default Y value. Lower = darker.
156 // Calculate the RGB values from YUV
158 dg = dy - 100.6*u - 148*v;
161 // Scale the RGB values back to max 255
163 if (dg > dmax) dmax = dg;
164 if (db > dmax) dmax = db;
171 scope.setPixel(pt, qRgba(dr, dg, db, 255));
173 case PaintMode_Original:
174 scope.setPixel(pt, *col);
176 case PaintMode_Green:
177 px = scope.pixel(pt);
178 scope.setPixel(pt, qRgba(qRed(px)+(255-qRed(px))/(3*avgPxPerPx), qGreen(px)+20*(255-qGreen(px))/(avgPxPerPx),
179 qBlue(px)+(255-qBlue(px))/(avgPxPerPx), qAlpha(px)+(255-qAlpha(px))/(avgPxPerPx)));
181 case PaintMode_Green2:
182 px = scope.pixel(pt);
183 scope.setPixel(pt, qRgba(qRed(px)+ceil((255-(float)qRed(px))/(4*avgPxPerPx)), 255,
184 qBlue(px)+ceil((255-(float)qBlue(px))/(avgPxPerPx)), qAlpha(px)+ceil((255-(float)qAlpha(px))/(avgPxPerPx))));
186 case PaintMode_Black:
187 px = scope.pixel(pt);
188 scope.setPixel(pt, qRgba(0,0,0, qAlpha(px)+(255-qAlpha(px))/20));