找回密码
 立即注册
收起左侧

使用画笔对窗口某个区域实现模糊处理效果(毛玻璃效果)

7
回复
9093
查看
[复制链接]

尚未签到

来源: 2018-8-13 11:43:23 显示全部楼层 |阅读模式
1Qter豆
先看一下效果图,这是一个截图工具的效果图,我自己也在做类似的功能:



painter 看样子是一个点或者其他什么画笔。
点击某个位置的时候会形成一个圆形的模糊效果(不是整个圆形完全填充为一个颜色,像是一个渐变,但又是不规则渐变)
鼠标移动的时候对不同的点进行模糊,已经处理过的点不会再次出现模糊效果。

这个功能想了三天了,实在没有太好的思路,请教大家是否有人做过类似的实现,指点一下思路就好了,我慢慢研究。

附件: 您需要 登录 才可以下载或查看,没有帐号?立即注册
回复

使用道具 举报

尚未签到

2018-8-13 14:17:26 显示全部楼层
找到了这个文章,但是是针对整个图片的,不知道如何配合 QPainter 和 QPen 来实现对鼠标路径的模糊效果。

  1. #include "mainwindow.h"
  2. #include <QGraphicsBlurEffect>
  3. #include <QGraphicsPixmapItem>
  4. #include <QGraphicsScene>
  5. #include <QApplication>
  6. #include <QPainter>
  7. #include <QLabel>
  8. #include <QImage>
  9. #include <QPixmap>

  10. QImage applyEffectToImage(QImage src, QGraphicsEffect *effect, int extent = 0)
  11. {
  12.     if (src.isNull()) return QImage();   //No need to do anything else!
  13.     if (!effect) return src;             //No need to do anything else!
  14.     QGraphicsScene scene;
  15.     QGraphicsPixmapItem item;
  16.     item.setPixmap(QPixmap::fromImage(src));
  17.     item.setGraphicsEffect(effect);
  18.     scene.addItem(&item);
  19.     QImage res(src.size() + QSize(extent * 2, extent * 2), QImage::Format_ARGB32);
  20.     res.fill(Qt::transparent);
  21.     QPainter ptr(&res);
  22.     scene.render(&ptr, QRectF(), QRectF(-extent, -extent, src.width() + extent * 2, src.height() + extent*2 ));
  23.     return res;
  24. }

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

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

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

  37.     int i1 = 0;
  38.     int i2 = 3;

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

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

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

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

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

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

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

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

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

  77.     return result;
  78. }

  79. int main(int argc, char *argv[])
  80. {
  81.     QApplication a(argc, argv);
  82. #if 1
  83.     QLabel label;
  84.     QImage image("d:/2018-08-13_13-36-56.png");
  85.     image = blurred(image,image.rect(), 10, false);
  86.     label.setPixmap(QPixmap::fromImage(image));
  87.     label.show();
  88. #endif

  89. #if 0
  90.     QGraphicsBlurEffect *blur = new QGraphicsBlurEffect;
  91.     blur->setBlurRadius(8);
  92.     QImage source("d:/2018-08-13_13-36-56.png");
  93.     QImage result = applyEffectToImage(source, blur);
  94.     result.save("d:/2018-08-13_13-36-56.backup.png");
  95. #endif
  96.     return a.exec();
  97. }
复制代码
回复

使用道具 举报

累计签到:41 天
连续签到:1 天
2018-9-24 19:02:26 显示全部楼层
可以将画笔点击过的坐标形成一个折线图元,然后为折线设置较粗的画笔,最后给图元设置模糊效果。
回复

使用道具 举报

尚未签到

2018-9-30 14:00:55 显示全部楼层
baizy77 发表于 2018-9-24 19:02
可以将画笔点击过的坐标形成一个折线图元,然后为折线设置较粗的画笔,最后给图元设置模糊效果。 ...

感谢回复,难点就是在给图元设置模糊效果。这个一句两句可能描述不清楚吧。
回复

使用道具 举报

累计签到:41 天
连续签到:1 天
2018-9-30 14:13:57 显示全部楼层
jiajia_deng 发表于 2018-9-30 14:00
感谢回复,难点就是在给图元设置模糊效果。这个一句两句可能描述不清楚吧。 ...

您可以利用点坐标生成一个折线图元,并将其设置为不可选中(setFlag(QGraphicsItem::ItemIsSelectable)),
然后为该图元设置模糊效果,
        QGraphicsBlurEffect* blurEffect = new QGraphicsBlurEffect();
        blurEffect->setBlurRadius(10);
        调用QGraphicsItem::setGraphicsEffect(blurEffect);
回复

使用道具 举报

尚未签到

2018-9-30 15:23:11 显示全部楼层
baizy77 发表于 2018-9-30 14:13
您可以利用点坐标生成一个折线图元,并将其设置为不可选中(setFlag(QGraphicsItem::ItemIsSelectable)), ...

非常感谢您的思路。图元中的点是根据自己绘制时拖动的坐标取对应的像素颜色吗?
回复

使用道具 举报

累计签到:41 天
连续签到:1 天
2018-9-30 18:15:37 显示全部楼层
jiajia_deng 发表于 2018-9-30 15:23
非常感谢您的思路。图元中的点是根据自己绘制时拖动的坐标取对应的像素颜色吗? ...

是的,还有一个思路,直接用QPainter的接口绘制折线段,坐标获取方法一样,绘制时用浅一些的灰色,alpha值取0.5或者边调整边实验。线宽设置的粗一些。
参与人数 1人气 +2 收起 理由
jiajia_deng + 2 对我帮助很大!

查看全部评分总评分 : 人气 +2

回复

使用道具 举报

尚未签到

2018-9-30 18:52:30 显示全部楼层
baizy77 发表于 2018-9-30 18:15
是的,还有一个思路,直接用QPainter的接口绘制折线段,坐标获取方法一样,绘制时用浅一些的灰色,alpha ...

好的,我试试你说的方法。
我看过 VC 下的实现,对于模糊效果的处理是非常复杂的,Qt 上的现有功能可能无法做到我录像中的那种效果,但是有折中方案也可以接受的。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

公告
可以关注我们的微信公众号yafeilinux_friends获取最新动态,或者加入QQ会员群进行交流:190741849、186601429(已满) 我知道了