]> git.sesse.net Git - kdenlive/commitdiff
RGB Parade > 10x speedup.
authorSimon A. Eugster <simon.eu@gmail.com>
Sun, 5 Sep 2010 11:43:27 +0000 (11:43 +0000)
committerSimon A. Eugster <simon.eu@gmail.com>
Sun, 5 Sep 2010 11:43:27 +0000 (11:43 +0000)
Instead of directly reading and painting on the QImage I'm now storing the data in an uint array and painting afterwards with setPixel. This is ways faster and also more accurate.
Bug that RGB Parade disappeared when it was too small (rounding lead to a color value of 0 always) has been fixed as well.

svn path=/trunk/kdenlive/; revision=4837

src/colorcorrection/rgbparadegenerator.cpp

index d356696d4abc9fbf945237d28b03cf7ba61f0e35..cd2a0048c8cea9a6c3badf9749435a2632f4ebc7 100644 (file)
@@ -16,6 +16,7 @@
 #include <QTime>
 
 #define CHOP255(a) ((255) < (a) ? (255) : (a))
+#define CHOP1255(a) ((a) < (1) ? (1) : ((a) > (255) ? (255) : (a)))
 
 const QColor RGBParadeGenerator::colHighlight(255, 245, 235, 255);
 const QColor RGBParadeGenerator::colLight(200, 200, 200, 255);
@@ -25,6 +26,12 @@ const QColor RGBParadeGenerator::colSoft(150, 150, 150, 255);
 const uchar RGBParadeGenerator::distRight(40);
 const uchar RGBParadeGenerator::distBottom(40);
 
+struct StructRGB {
+    uint r;
+    uint g;
+    uint b;
+};
+
 RGBParadeGenerator::RGBParadeGenerator()
 {
 }
@@ -43,8 +50,6 @@ QImage RGBParadeGenerator::calculateRGBParade(const QSize &paradeSize, const QIm
         parade.fill(qRgba(0,0,0,0));
 
         QRgb *col;
-        QRgb paradeCol;
-        QPoint paradePoint;
         QPainter davinci(&parade);
 
         double dx, dy;
@@ -53,27 +58,36 @@ QImage RGBParadeGenerator::calculateRGBParade(const QSize &paradeSize, const QIm
         const uint wh = paradeSize.height();
         const uint iw = image.bytesPerLine();
         const uint ih = image.height();
-        const uint byteCount = iw*ih;
+        const uint byteCount = iw*ih;   // Note that 1 px = 4 B
 
         const uchar offset = 10;
-        const int partW = (ww - 2*offset - distRight) / 3;
-        const int partH = wh - distBottom;
-
-        // To get constant brightness, independant of acceleration factor and input image size
-        // Must be a float because the acceleration factor can be high, leading to <1 expected px per px.
-        // Divide by 3 because of the 3 components.
-        const float brightnessAdjustment = accelFactor * ((float) ww*wh/(byteCount>>3)) / 3;
+        const uint partW = (ww - 2*offset - distRight) / 3;
+        const uint partH = wh - distBottom;
 
+        // Statistics
         uchar minR = 255, minG = 255, minB = 255, maxR = 0, maxG = 0, maxB = 0, r, g, b;
-//        qDebug() << "Expecting about " << avgPxPerPx << " pixels per pixel in the RGB parade. Weakening by " << weaken
-//                << " with an acceleration factor of " << accelFactor;
 
 
+        // Number of input pixels that will fall on one scope pixel.
+        // Must be a float because the acceleration factor can be high, leading to <1 expected px per px.
+        const float pixelDepth = (float)((byteCount>>2) / accelFactor)/(partW*255);
+        const float gain = 255/(8*pixelDepth);
+//        qDebug() << "Pixel depth: expected " << pixelDepth << "; Gain: using " << gain << " (acceleration: " << accelFactor << "x)";
+
         QImage unscaled(ww-distRight, 256, QImage::Format_ARGB32);
         unscaled.fill(qRgba(0, 0, 0, 0));
 
         const float wPrediv = (float)(partW-1)/(iw-1);
 
+        StructRGB paradeVals[partW][256];
+        for (uint i = 0; i < partW; i++) {
+            for (uint j = 0; j < 256; j++) {
+                paradeVals[i][j].r = 0;
+                paradeVals[i][j].g = 0;
+                paradeVals[i][j].b = 0;
+            }
+        }
+
         const uchar *bits = image.bits();
         const uint stepsize = 4*accelFactor;
 
@@ -86,38 +100,9 @@ QImage RGBParadeGenerator::calculateRGBParade(const QSize &paradeSize, const QIm
 
             dx = x*wPrediv;
 
-            paradePoint = QPoint((int)dx, r);
-            paradeCol = QRgb(unscaled.pixel(paradePoint));
-            switch(paintMode) {
-            case PaintMode_RGB:
-                unscaled.setPixel(paradePoint, qRgba(255,10,10, CHOP255(brightnessAdjustment*16 + qAlpha(paradeCol))));
-                break;
-            default:
-                unscaled.setPixel(paradePoint, qRgba(255,255,255, CHOP255(brightnessAdjustment*16 + qAlpha(paradeCol))));
-                break;
-            }
-
-            paradePoint = QPoint((int) (dx + partW + offset), g);
-            paradeCol = QRgb(unscaled.pixel(paradePoint));
-            switch(paintMode) {
-            case PaintMode_RGB:
-                unscaled.setPixel(paradePoint, qRgba(10,255,10, CHOP255(brightnessAdjustment*16 + qAlpha(paradeCol))));
-                break;
-            default:
-                unscaled.setPixel(paradePoint, qRgba(255,255,255, CHOP255(brightnessAdjustment*16 + qAlpha(paradeCol))));
-                break;
-            }
-
-            paradePoint = QPoint((int) (dx + 2*partW + 2*offset), b);
-            paradeCol = QRgb(unscaled.pixel(paradePoint));
-            switch(paintMode) {
-            case PaintMode_RGB:
-                unscaled.setPixel(paradePoint, qRgba(10,10,255, CHOP255(brightnessAdjustment*16 + qAlpha(paradeCol))));
-                break;
-            default:
-                unscaled.setPixel(paradePoint, qRgba(255,255,255, CHOP255(brightnessAdjustment*16 + qAlpha(paradeCol))));
-                break;
-            }
+            paradeVals[(int)dx][r].r++;
+            paradeVals[(int)dx][g].g++;
+            paradeVals[(int)dx][b].b++;
 
 
             if (r < minR) { minR = r; }
@@ -131,6 +116,31 @@ QImage RGBParadeGenerator::calculateRGBParade(const QSize &paradeSize, const QIm
             x += stepsize;
             x %= iw; // Modulo image width, to represent the current x position in the image
         }
+
+
+        const uint offset1 = partW + offset;
+        const uint offset2 = 2*partW + 2*offset;
+        switch(paintMode) {
+        case PaintMode_RGB:
+            for (uint i = 0; i < partW; i++) {
+                for (uint j = 0; j < 256; j++) {
+                    unscaled.setPixel(i,         j, qRgba(255,10,10, CHOP255(gain*paradeVals[i][j].r)));
+                    unscaled.setPixel(i+offset1, j, qRgba(10,255,10, CHOP255(gain*paradeVals[i][j].g)));
+                    unscaled.setPixel(i+offset2, j, qRgba(10,10,255, CHOP255(gain*paradeVals[i][j].b)));
+                }
+            }
+            break;
+        default:
+            for (uint i = 0; i < partW; i++) {
+                for (uint j = 0; j < 256; j++) {
+                    unscaled.setPixel(i,         j, qRgba(255,255,255, CHOP255(gain*paradeVals[i][j].r)));
+                    unscaled.setPixel(i+offset1, j, qRgba(255,255,255, CHOP255(gain*paradeVals[i][j].g)));
+                    unscaled.setPixel(i+offset2, j, qRgba(255,255,255, CHOP255(gain*paradeVals[i][j].b)));
+                }
+            }
+            break;
+        }
+
         // Scale the image to the target height. Scaling is not accomplished before because
         // there are only 255 different values which would lead to gaps if the height is not exactly 255.
         // Don't use bilinear transformation because the fast transformation meets the goal better.