Astronavigator
Astronavigator

Reputation: 2051

QT4 How to blur QPixmap image?

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?

Upvotes: 5

Views: 17235

Answers (6)

Fran Raga
Fran Raga

Reputation: 652

Add python code based on @Петър Петров answer for QT 5.

def applyEffectToImage(src, effect):
    scene = QGraphicsScene()
    item = QGraphicsPixmapItem()
    item.setPixmap(QPixmap.fromImage(src))
    item.setGraphicsEffect(effect)
    scene.addItem(item)
    res = QImage(src.size(), QImage.Format_ARGB32)
    res.fill(Qt.transparent)
    ptr = QPainter(res)
    scene.render(ptr, QRectF(), QRectF(0,0, src.width(), src.height()) )
    return res

blur = QGraphicsBlurEffect()
blur.setBlurRadius(8)
source = QImage(r"C:\Users\fran\Desktop\test.png")
result = applyEffectToImage(source, blur)
result.save(r"C:\Users\fran\Desktop\result.png")

Upvotes: 0

liuyanghejerry
liuyanghejerry

Reputation: 3871

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();
}

Upvotes: 8

PeterSvP
PeterSvP

Reputation: 2046

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.

Upvotes: 9

Artiom Khachaturian
Artiom Khachaturian

Reputation: 253

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
  }

Upvotes: 13

AndrewS
AndrewS

Reputation: 8472

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.

Upvotes: 7

gspr
gspr

Reputation: 11227

A Gaussian blur is a simple way to create a blurring effect.

Edit: And lo, I came across Qt's QGraphicsBlurEffect. Introduced in Qt 4.6, it seems to do exactly what you want.

Upvotes: 0

Related Questions