From: Simon A. Eugster Date: Sun, 5 Sep 2010 11:43:27 +0000 (+0000) Subject: RGB Parade > 10x speedup. X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=29c58ebee21498c1367bbd9c0e6b0a7a934a1fe0;p=kdenlive RGB Parade > 10x speedup. 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 --- diff --git a/src/colorcorrection/rgbparadegenerator.cpp b/src/colorcorrection/rgbparadegenerator.cpp index d356696d..cd2a0048 100644 --- a/src/colorcorrection/rgbparadegenerator.cpp +++ b/src/colorcorrection/rgbparadegenerator.cpp @@ -16,6 +16,7 @@ #include #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 ¶deSize, const QIm parade.fill(qRgba(0,0,0,0)); QRgb *col; - QRgb paradeCol; - QPoint paradePoint; QPainter davinci(¶de); double dx, dy; @@ -53,27 +58,36 @@ QImage RGBParadeGenerator::calculateRGBParade(const QSize ¶deSize, 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 ¶deSize, 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 ¶deSize, 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.