Question

I would like to know what is the fastest way to modify a portion of a QImage.

I have this piece of code that has to be executed with a frequency of 30Hz. It displays an image through a sort of keyhole. It is not possible to see the entire image but only a portion inside a circle. The first for-loop erases the previous "keyhole portion displayed" and the second updates the position of the "displayed keyhole".

for (int i = (prev_y - r_y); i < (prev_y + r_y); i++){
        QRgb *line = (QRgb *)backgrd->scanLine(i);
        for(int j = (prev_x - r_x); j < (prev_x + r_x) ; j++){
            if((i >= 0 && i < this->backgrd->height()) && (j >= 0 && j < this->backgrd->width()))
                line[j] = qRgb(0,0,0);
        }
    }
    prev_x = new_x; prev_y = new_y;

    for (int i = (new_y - r_y); i < (new_y + r_y); i++){
        QRgb *line = (QRgb *)backgrd->scanLine(i);
        QRgb *line2 = (QRgb *)this->picture->scanLine(i);
        for(int j = (new_x - r_x); j < (new_x + r_x) ; j++){
            if ((((new_x - j)*(new_x - j)/(r_x*r_x) + (new_y - i)*(new_y - i)/(r_y*r_y)) <= 1) && (i >= 0) && (i < this->picture->height())&& (j >= 0) && (j < this->picture->width()))
                line[j] = line2[j];
        }
    }
    this->current_img = this->backgrd;
}
this->update(); //Display QImage* this->current_img

If I analyse the timestamps of the program I find a delay in the flow of execution every time it is executed... Is it so high consuming to access a pixel in a QImage? Am I doing something wrong? Is there a better alternative to QImage for a Qt program?

Was it helpful?

Solution 3

Actually I understood it wasn't pixel acces that was slow, but the rendering. During the tests I did I used plain color images, but these kind of images are much faster to render than complex images loaded from file. With other tests I realized was the rendering that was slow.

The fastest way to render an QImage is first of all to transform it using

public: static QImage QGLWidget::convertToGLFormat(const QImage &img)

then the image can be fastly manipulated (it preserves bits() scanline() width() and height() functions) and can be displayed very fast by openGL (no further conversions are necessary)

QPainter painter(this);
glDrawPixels(img.width(), img.height(), GL_RGBA, GL_UNSIGNED_BYTE, img.bits());
painter.end();

OTHER TIPS

How about prerendering your 'keyhole' in an array/qimage and doing a bitwise AND with the source?

  • Original pixel && black => black
  • Original pixel && white => original pixel

You have a lot of conditions in the innermost loop (some can be moved out though), but the circle radius calculation with the multiplies and divides looks costly. You can reuse the keyhole mask for every frame, so no calculations need be performed.

  • You could move some of the conditions at least to the outer loop, and maybe pre-compute some of the terms inside the conditions, though this may be optimized anyway.
  • Call update only for the rectangle(s) you modified
  • Where do you get the time stamp? Maybe you lose time somewhere else?

As far as I know the fastest way to access the data of a QImage is to use QImage::bits() which give you direct access to the data of QImage.

For your problem, A better approch will be to do as Bgie suggested : using a array representing the keyhole and doing only a bitwise AND operation.

it will help to choose the correct format for your Image, the format RGB32 and ARG32_Premultiplied_ARGB32 are the fastest. Don't use ARGB32 if you don't need it.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top