QT4 How to blur QPixmap image?

14,747

Solution 1

1st) declare external QT routine:

QT_BEGIN_NAMESPACE
  extern Q_WIDGETS_EXPORT void qt_blurImage( QPainter *p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, int transposed = 0 );
QT_END_NAMESPACE

2nd) Use:

  extern QImage srcImg;//source image
  QPixmap pxDst( srcImg.size() );//blurred destination
  pxDst.fill( Qt::transparent );
  {
    QPainter painter( &pxDst );
    qt_blurImage( &painter, srcImg, 2, true, false );//blur radius: 2px
  }

Solution 2

Let's contribute to this topic. As of Qt 5.3, following function will help you a lot with applying QGraphicsEffect to QImage (and not losing the alpha)

QImage applyEffectToImage(QImage src, QGraphicsEffect *effect, int extent = 0)
{
    if(src.isNull()) return QImage();   //No need to do anything else!
    if(!effect) return src;             //No need to do anything else!
    QGraphicsScene scene;
    QGraphicsPixmapItem item;
    item.setPixmap(QPixmap::fromImage(src));
    item.setGraphicsEffect(effect);
    scene.addItem(&item);
    QImage res(src.size()+QSize(extent*2, extent*2), QImage::Format_ARGB32);
    res.fill(Qt::transparent);
    QPainter ptr(&res);
    scene.render(&ptr, QRectF(), QRectF( -extent, -extent, src.width()+extent*2, src.height()+extent*2 ) );
    return res;
}

Them, using this function to blur your image is straightforward:

QGraphicsBlurEffect *blur = new QGraphicsBlurEffect;
blur->setBlurRadius(8);
QImage source("://img1.png");
QImage result = applyEffectToImage(source, blur);
result.save("final.png");

Of course, you don't need to save it, this was just an example of usefulness. You can even drop a shadow:

QGraphicsDropShadowEffect *e = new QGraphicsDropShadowEffect;
e->setColor(QColor(40,40,40,245));
e->setOffset(0,10);
e->setBlurRadius(50);
QImage p("://img3.png");
QImage res = applyEffectToImage(p, e, 40);

And note the extent parameter, it adds extent number of pixels to all sides of the original image, especially useful for shadows and blurs to not be cut-off.

Solution 3

Check out this:

#include <QtGui/QApplication>
#include <QImage>
#include <QPixmap>
#include <QLabel>

QImage blurred(const QImage& image, const QRect& rect, int radius, bool alphaOnly = false)
{
    int tab[] = { 14, 10, 8, 6, 5, 5, 4, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2 };
    int alpha = (radius < 1)  ? 16 : (radius > 17) ? 1 : tab[radius-1];

    QImage result = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
    int r1 = rect.top();
    int r2 = rect.bottom();
    int c1 = rect.left();
    int c2 = rect.right();

    int bpl = result.bytesPerLine();
    int rgba[4];
    unsigned char* p;

    int i1 = 0;
    int i2 = 3;

    if (alphaOnly)
        i1 = i2 = (QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3);

    for (int col = c1; col <= c2; col++) {
        p = result.scanLine(r1) + col * 4;
        for (int i = i1; i <= i2; i++)
            rgba[i] = p[i] << 4;

        p += bpl;
        for (int j = r1; j < r2; j++, p += bpl)
            for (int i = i1; i <= i2; i++)
                p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
    }

    for (int row = r1; row <= r2; row++) {
        p = result.scanLine(row) + c1 * 4;
        for (int i = i1; i <= i2; i++)
            rgba[i] = p[i] << 4;

        p += 4;
        for (int j = c1; j < c2; j++, p += 4)
            for (int i = i1; i <= i2; i++)
                p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
    }

    for (int col = c1; col <= c2; col++) {
        p = result.scanLine(r2) + col * 4;
        for (int i = i1; i <= i2; i++)
            rgba[i] = p[i] << 4;

        p -= bpl;
        for (int j = r1; j < r2; j++, p -= bpl)
            for (int i = i1; i <= i2; i++)
                p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
    }

    for (int row = r1; row <= r2; row++) {
        p = result.scanLine(row) + c2 * 4;
        for (int i = i1; i <= i2; i++)
            rgba[i] = p[i] << 4;

        p -= 4;
        for (int j = c1; j < c2; j++, p -= 4)
            for (int i = i1; i <= i2; i++)
                p[i] = (rgba[i] += ((p[i] << 4) - rgba[i]) * alpha / 16) >> 4;
    }

    return result;
}

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QLabel label;
    QImage image("image.png");
    image =  blurred(image,image.rect(),10,false);
    label.setPixmap(QPixmap::fromImage(image));
    label.show();

    return a.exec();
}

Solution 4

Method 1a: grab the raw bits and do it yourself. You'll need to be sufficiently familiar with bitmaps and blurring algorithms to implement the blur yourself. If you want that sort of precision, this is the way to go.

QImage image = pixmap.toImage();
if (image.format() != QImage::Format_RGB32)
     image = image.convertToFormat(QImage::Format_RGB32);
uchar* bits = image.bits();
int rowBytes = image.bytesPerLine();
DoMyOwnBlurAlgorithm(bits, image.width(), image.height(), rowBytes);
return QPixmap::fromImage(image);

Method 1b: who needs raw bits? You can use image.pixel(x,y) and image.setPixel(x,y,color) instead. This won't be as fast as 1a, but it should be a bit easier to understand and code.

QImage image = pixmap.toImage();
QImage output(image.width(), image.height(), image.format());
for (int y=0; y<image.height(); ++y)
   for (int x=0; x<image.width(); ++x)
      output.setPixel(getBlurredColor(image, x, y));
return output;

Method 2: use a QGraphicsBlurEffect, through a widget or scene. The code here uses a label widget:

QPixmap BlurAPixmap(const QPixmap& inPixmap)
{
    QLabel* label = new QLabel();
    label->setPixmap(inPixmap);
    label->setGraphicsEffect(new QGraphicsBlurEffect());
    QPixmap output(inPixmap.width(), inPixmap.height());
    QPainter painter(&output);
    label->render(&painter);
    return output;
}

Tweak as needed. For example, I'm presuming the default graphics blur effect is acceptable. I'm using Method 2 in my project.

Share:
14,747
Astronavigator
Author by

Astronavigator

Updated on June 08, 2022

Comments

  • Astronavigator
    Astronavigator almost 2 years

    QT4 How to blur QPixmap image?

    I am looking for something like one of the following:

    Blur(pixmap); 
    painter.Blur(); 
    painter.Blur(rect);
    

    What is the best way to do this?

  • Caleb Huitt - cjhuitt
    Caleb Huitt - cjhuitt over 13 years
    The QGraphicsEffects are meant to be applied to graphics views, not pixmaps. However, the general idea of a Guassian blur is the way to go; you'll just have to implement the algorithm yourself on the pixmap. (It might be faster/easier to convert to a QImage, though.)
  • Astronavigator
    Astronavigator over 13 years
    Everybody knows these algorithms. But to implement them myselft i have to have way to : 1. convert QPixmap to 2d array 2. way to convert from 2d array back to pixmap. If your advise is to implement it myself, then tell how to convert between QPixmap and 2d array
  • mhcuervo
    mhcuervo almost 10 years
    Sometimes I wonder why lower quality questions are risen instead of the good ones. Yours is so far the best answer to this question. +1
  • Петър Петров
    Петър Петров over 9 years
    First convert to QImage, so you can access pixels directly, then create another QImage, apply Convolution kernel to it and be happy :) Docs will help you further