QT4 How to blur QPixmap image?

前端 未结 6 1954
遥遥无期
遥遥无期 2021-01-06 02:21

QT4 How to blur QPixmap image?

I am looking for something like one of the following:

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


        
相关标签:
6条回答
  • 2021-01-06 02:33

    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();
    }
    
    0 讨论(0)
  • 2021-01-06 02:39

    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.

    0 讨论(0)
  • 2021-01-06 02:39

    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")
    
    0 讨论(0)
  • 2021-01-06 02:44

    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.

    0 讨论(0)
  • 2021-01-06 02:49

    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.

    0 讨论(0)
  • 2021-01-06 02:56

    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
      }
    
    0 讨论(0)
提交回复
热议问题