QT4 How to blur QPixmap image?
Asked Answered
Q

6

5

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?

Quack answered 11/10, 2010 at 2:42 Comment(1)
I think liuyanghejerry has waited long enough to get credit for the best answer.Contrived
B
13

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
  }
Brott answered 23/1, 2014 at 7:26 Comment(2)
Sometimes I wonder why lower quality questions are risen instead of the good ones. Yours is so far the best answer to this question. +1Binder
Because it uses Qt private API and some day this symbol may simply vanish. Its not documented. Nobody even knows the algorithm used.Scabble
L
9

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.

Largely answered 19/1, 2015 at 14:19 Comment(0)
I
8

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();
}
Interlocutrix answered 29/10, 2011 at 4:3 Comment(0)
Z
7

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.

Zygoma answered 30/8, 2012 at 19:14 Comment(0)
W
0

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.

Waldenses answered 11/10, 2010 at 11:9 Comment(3)
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.)Hayden
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 arrayQuack
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 furtherSharma
C
0

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")
Cerussite answered 1/6, 2019 at 11:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.