the_naive
the_naive

Reputation: 3064

Faster image mirroring algorithm

I already know how to flip an image vertically or horizontally. I have the following code that does so horizontally. The image data here is stored in a QImage as I was working with Qt here.

QImage image(imageFileName);
QImage newImage(image);

if(image.depth() > 8)
{
    for (int idx_Y = 0; idx_Y < image.height(); idx_Y++)
    {
        for (int idx_X = 0; idx_X < image.width(); idx_X++)
        {
            QRgb rgb = image.pixel(image.width() - 1 - idx_X, idx_Y);
            newImage.setPixel(idx_X, idx_Y, rgb);
        }
    }
}

I'm sure there are faster methods to get it done. However, I don't want any memory allocation on the heap. Could you please tell me what other much faster algorithms there could be?

Thank you.

Upvotes: 0

Views: 1224

Answers (1)

Scheff&#39;s Cat
Scheff&#39;s Cat

Reputation: 20141

Elaborating on @Spektres hint

2 nested for loops are not the problem... the setPixel and pixel functions are usually crawlingly slooow on most gfx APIs. Using direct pixel access instead usually boost speed ~1000 times or more ...

This could look like:

QImage image(imageFileName);
QImage newImage(image);

if (image.depth() >= 8) {
  const int bytesPerPixel = image.depth() / 8;
  for (int y = 0; y < image.height(); ++y) {
    char *dataSrc = image.bits() + y * image.bytesPerLine();
    char *dataDst = newImage.bits() + y * newImage.bytesPerLine()
      + (newImage.width() - 1) * bytesPerPixel;
    for (int i = image.width(); i--;
      dataSrc += bytesPerPixel, dataDst -= bytesPerPixel) {
      for (int i = 0; i < bytesPerPixel; ++i) dataDst[i] = dataSrc[i];
    }
  }
}

Please, note that I changed image.depth() > 8 into image.depth() >= 8. (I saw no reason to exclude e.g. QImage::Format_Grayscale8.)

A slightly modified version for mirroring the QImage newImage in-place (considering that it is already copied):

QImage image(imageFileName);
QImage newImage(image);

if (newImage.depth() >= 8) {
  const int bytesPerPixel = newImage.depth() / 8;
  for (int y = 0; y < image.height(); ++y) {
    char *dataL = newImage.bits() + y * newImage.bytesPerLine();
    char *dataR = dataL + (newImage.width() - 1) * bytesPerPixel;
    for (; dataL < dataR; dataL += bytesPerPixel, dataR -= bytesPerPixel) {
      for (int i = 0; i < bytesPerPixel; ++i) std::swap(dataL[i], dataR[i]);
    }
  }
}

Concerning QImage and qRgb(), you may also notice that Qt supports QImages with 16 bits per component (since Qt 5.12).

I fiddled a bit with this in
SO: Set pixel value of 16 bit grayscale QImage
which might be interesting as well.

Upvotes: 2

Related Questions